!!!###!!!title=Data Update Animation——VisActor/VChart Contributing Documents!!!###!!!!!!###!!!description=---title: 10.4 Data Update Animation key words: VisActor,VChart,VTable,VStrory,VMind,VGrammar,VRender,Visualization,Chart,Data,Table,Graph,Gis,LLM---!!!###!!!

10.4 Data Update Animation

Score: 8

  • Update Animation:

  • Code Entry: packages/vchart/src/animation/

  • Key Points:

  • Implementation of Update Animation

  • Other Reference Documents:

https://www.visactor.io/vchart/guide/tutorial_docs/Animation/Animation_Types

https://www.visactor.io/vrender/guide/asd/Basic_Tutorial/Animate

https://visactor.io/vgrammar/guide/guides/animation

Magic Frame (Part 1): The Principle of Animation Implementation in Front-end Chart Libraries - A vivid visualization work often involves animation. Whether it's various charts or narrative works, organizing the week - Juejin

After understanding how to add change animation effects when specific chart element data changes, we can configure data update animations for series elements in a specific type of chart to meet animation effects in specific scenarios.

Interpretation of Data Update Animation Implementation

Data update animation refers to the animation effect executed by chart elements based on the new data state when the chart data changes. In VChart, this animation is designed to be very flexible and can be applied to three scenarios: new data entry (enter), existing data update (update), and old data removal (exit). Below is a detailed interpretation of the implementation.

1. Animation Configuration Structure

IAnimationSpec Interface

The IAnimationSpec interface defines the basic structure of animation configuration, which includes animation settings for different states. For data update animations, it mainly involves the following three properties:

  • animationEnter: Describes the animation effect when new data is added.

  • animationUpdate: Describes the animation effect when existing data is updated.

  • animationExit: Describes the animation effect when old data is removed.

interface IAnimationSpec<MarkName extends string, Preset extends string> {
  animationEnter?: boolean | ICommonStateAnimateSpec | IMarkAnimateSpec<MarkName>;
  animationUpdate?: boolean | ICommonStateAnimateSpec | IMarkAnimateSpec<MarkName>;
  animationExit?: boolean | ICommonStateAnimateSpec | IMarkAnimateSpec<MarkName>;
}    

Each attribute can accept a boolean value (enable/disable), a preset configuration object, or a custom configuration object as a parameter, providing developers with a high degree of customization possibilities.

2. Animation Manager

AnimateManager Class

The AnimateManager class is responsible for managing and coordinating the state of all animations. It implements the IAnimate interface and provides methods to update and retrieve animation states. For data update animations, the AnimateManager ensures that these animations are automatically triggered when data changes and can be paused or resumed as needed.

class AnimateManager extends StateManager implements IAnimate {
  updateAnimateState(state: AnimationStateEnum, noRender?: boolean) {
    if (state === AnimationStateEnum.update) {
      this.updateState(
        {
          animationState: {
            callback: (datum: any, element: IElement) => element.diffState
          }
        },
        noRender
      );
    } else if (state === AnimationStateEnum.appear) {
      // 出现状态下的动画逻辑
    } else if (state === AnimationStateEnum.exit) {
      // 退出状态下的动画逻辑
    }
  }
}    

When chart elements enter the update, appear, or exit states, the updateAnimateState method is called and passes the state to the internal state management logic. This allows all eligible elements to perform the corresponding animations.

3. Animation Configuration Generation

animationConfig Function

To simplify the merging process between user configurations and default configurations, VChart provides a helper function called animationConfig. This function iterates over all possible animation states and constructs the final animation configuration object based on the user-provided configuration or the default configuration.

function animationConfig<Preset extends string>(
  defaultConfig: MarkAnimationSpec = {},
  userConfig?: Partial<Record<IAnimationState, boolean | IStateAnimateSpec<Preset> | IAnimationConfig | IAnimationConfig[]>>,
  params?: { dataIndex: (datum: any, params: any) => number; dataCount: () => number; }
): MarkAnimationSpec {
  const config = {} as MarkAnimationSpec;

  for (let i = 0; i < AnimationStates.length; i++) {
    const state = AnimationStates[i];
    const userStateConfig = userConfig ? userConfig[state] : undefined;

    if (userStateConfig === false) continue;

    if (state === 'enter' || state === 'update' || state === 'exit') {
      let defaultStateConfig: IAnimationConfig[];
      if (isArray(defaultConfig[state])) {
        defaultStateConfig = defaultConfig[state] as IAnimationConfig[];
      } else {
        defaultStateConfig = [{ ...DEFAULT_ANIMATION_CONFIG[state], ...defaultConfig[state] } as any];
      }

      config[state] = defaultStateConfig;
    }
  }

  return config;
}    

This function handles the merging of animation configurations in enter, update, and exit states, ensuring that the configurations provided by the user are correctly applied to specific graphical elements. If the user does not provide custom animation configurations, the default configurations are used.

4. Specific Implementation of Data Update Animation

Taking a bar chart as an example, suppose we want to add a fade-in effect for newly added data points, a scaling effect for updated data points, and a fade-out effect for removed data points. Here are the detailed implementation steps:

  • Define Animation Configuration: First, specify the animationEnter, animationUpdate, and animationExit configurations for the bar chart series in the chart configuration. Here, we can choose built-in animation types and adjust their duration and easing functions.
const chartSpec = {
  series: [
    {
      type: 'bar',
      data: [/* 初始数据数组 */],
      animationEnter: {
        type: 'fadeIn', // 新数据点淡入
        duration: 800,
        easing: 'easeInOutQuad'
      },
      animationUpdate: {
        type: 'scaleIn', // 更新数据点缩放
        duration: 500,
        easing: 'easeInOutQuad'
      },
      animationExit: {
        type: 'fadeOut', // 移除数据点淡出
        duration: 600,
        easing: 'easeInOutQuad'
      }
    }
  ]
};    

  • Register Animation: Next, we need to ensure that the required animations have been correctly registered in the system. This step is usually completed at project startup or explicitly called where needed.
import { Factory } from '@visactor/vchart';
import { Appear_FadeIn, ScaleInOutAnimation, Appear_FadeOut } from './series/bar/animation';

// 注册淡入动画
Factory.registerAnimation('fadeIn', Appear_FadeIn);

// 注册缩放动画
Factory.registerAnimation('scaleIn', ScaleInOutAnimation);

// 注册淡出动画
Factory.registerAnimation('fadeOut', Appear_FadeOut);    

The Appear_FadeIn, ScaleInOutAnimation, and Appear_FadeOut functions here define the specific logic for fade-in, scale, and fade-out animations, such as how to change the transparency or size of graphic elements.

  • Initialize the chart instance: With the above configuration, we can initialize a VChart instance and pass the configuration to it. This will trigger the rendering process of the chart and apply the corresponding animation effects.
import { VChart } from '@visactor/vchart';

const container = document.getElementById('chart-container');
const chart = new VChart({
  el: container,
  spec: chartSpec,
  options: {
    animation: true, // 开启动画
    theme: 'light'   // 使用浅色主题
  }
});    

  • Trigger Animation: Once the chart is rendered, any change in data will automatically trigger animation. For example, when new data is added, the animationEnter configuration takes effect; when data is updated, the animationUpdate configuration is effective; and when data is removed, the animationExit configuration is applied.
// 假设一段时间后需要更新数据
setTimeout(() => {
  const newData = [/* 新的数据数组 */];
  chart.updateSeriesData(newData);
}, 5000);    

5. Execution of Animation Tasks

IAnimationTask Interface

For complex animation sequences, VChart introduces the IAnimationTask interface to describe the data structure of animation tasks. Each task includes a time offset, an action queue, and a list of successor tasks, forming a chain-like animation execution mechanism.

interface IAnimationTask {
  timeOffset: number;
  actionList: Action[];
  nextTaskList: IAnimationTask[];
}    

This design allows multiple animation tasks to be executed sequentially or concurrently, enabling more complex and delicate animation effects. For data update animations, it can be part of an independent task chain, working in conjunction with other animation tasks.

6. Example: Creating a Bar Chart with Data Update Animation

Below is an example of creating a bar chart with data update animation, illustrating how to use VChart's data update animation system to implement the basic process.

Step 1: Define Animation Configuration

First, we need to define the basic configuration of the bar chart, including the data source and other visual attributes. At the same time, we will also specify the animationEnter, animationUpdate, and animationExit configurations here to ensure that the corresponding animation effects can be triggered when the data changes.

const chartSpec = {
  series: [
    {
      type: 'bar',
      data: [
        { value: 10 },
        { value: 20 },
        { value: 30 }
      ],
      animationEnter: {
        type: 'fadeIn',
        duration: 800,
        easing: 'easeInOutQuad'
      },
      animationUpdate: {
        type: 'scaleIn',
        duration: 500,
        easing: 'easeInOutQuad'
      },
      animationExit: {
        type: 'fadeOut',
        duration: 600,
        easing: 'easeInOutQuad'
      }
    }
  ]
};    

Step 2: Register Animation

Ensure that the required animations have been correctly registered in the system. This step is usually completed at project startup or explicitly called where needed.

import { Factory } from '@visactor/vchart';
import { Appear_FadeIn, ScaleInOutAnimation, Appear_FadeOut } from './series/bar/animation';

Factory.registerAnimation('fadeIn', Appear_FadeIn);
Factory.registerAnimation('scaleIn', ScaleInOutAnimation);
Factory.registerAnimation('fadeOut', Appear_FadeOut);    

Step 3: Initialize the Chart Instance

With the above configuration, we can initialize a VChart instance and pass the configuration to it. This step will trigger the chart rendering process and apply the corresponding animation effects.

import { VChart } from '@visactor/vchart';

const container = document.getElementById('chart-container');
const chart = new VChart({
  el: container,
  spec: chartSpec,
  options: {
    animation: true, // 开启动画
    theme: 'light'   // 使用浅色主题
  }
});    

Step 4: Trigger Data Update Animation

Once the chart is rendered, any changes in the data will automatically trigger animations. For example, when new data is added, the animationEnter configuration will take effect; when data is updated, the animationUpdate configuration is effective; and when data is removed, the animationExit configuration is applied.

// 模拟数据更新
setTimeout(() => {
  const updatedData = [
    { value: 15 }, // 更新第一个数据点
    { value: 25 }, // 更新第二个数据点
    { value: 35 }, // 更新第三个数据点
    { value: 45 }  // 添加一个新的数据点
  ];

  // 更新图表数据并触发动画
  chart.updateSeriesData(updatedData);
}, 5000);    

In this example, the updateSeriesData method triggers a series of animations:

  • For newly added data points (the fourth data point), the animationEnter configuration makes it gradually appear with a fade-in effect.

  • For existing data points (the first three data points), the animationUpdate configuration adjusts their size based on the new data values and transitions them with a scaling effect.

  • If any data points are removed, the animationExit configuration makes them disappear with a fade-out effect.

Step 5: Dynamically Control Animations

In some cases, you may want to dynamically control the behavior of data update animations, such as changing the speed or style of the animation. VChart provides flexible methods to achieve this.

// 更新某个系列的数据更新动画配置
chart.updateSeriesOptions(0, {
  animationEnter: {
    duration: 1000, // 更改淡入动画的持续时间
    easing: 'linear' // 更改缓动函数
  },
  animationUpdate: {
    duration: 700, // 更改缩放动画的持续时间
    easing: 'easeInOutCubic' // 更改缓动函数
  },
  animationExit: {
    duration: 900, // 更改淡出动画的持续时间
    easing: 'easeInOutCubic' // 更改缓动函数
  }
});

// 重新应用新的动画配置
chart.render();    

7. Animation Lifecycle Management

Event Listeners and Hooks

To better manage the lifecycle of animations, VChart provides a series of event listeners and hook functions. For example, the VGRAMMAR_HOOK_EVENT.AFTER_DO_RENDER event can be triggered after the chart is initially rendered, while VGRAMMAR_HOOK_EVENT.ANIMATION_END will be triggered at the end of the animation.

this._event.on(VGRAMMAR_HOOK_EVENT.AFTER_DO_RENDER, () => {
  // 图表首次渲染完成后的逻辑
});

this._event.on(VGRAMMAR_HOOK_EVENT.ANIMATION_END, ({ event }) => {
  if (event.animationState === AnimationStateEnum.enter) {
    // enter 动画结束后的逻辑
  } else if (event.animationState === AnimationStateEnum.update) {
    // update 动画结束后的逻辑
  } else if (event.animationState === AnimationStateEnum.exit) {
    // exit 动画结束后的逻辑
  }
});    

This code demonstrates how to execute specific logic at different animation stages to ensure smooth transitions between animations and enhance user experience.

8. Difference Detection and Animation Trigger

Difference Detection

During the data update process, VChart automatically performs difference detection to identify which data points are new, updated, or removed. Based on this information, AnimateManager triggers the corresponding animations.

if (state === AnimationStateEnum.update) {
  this.updateState(
    {
      animationState: {
        callback: (datum: any, element: IElement) => element.diffState
      }
    },
    noRender
  );
}    

The diffState attribute here indicates the type of state change for the element, such as enter, update, or exit. The AnimateManager will decide which type of animation to apply based on this attribute.

9. Specific Implementation of Animation

Specific Animation Functions

Each specific animation function (such as Appear_FadeIn, ScaleInOutAnimation, and Appear_FadeOut) defines the specific behavior of the animation. For example, the Appear_FadeIn function might look like this:

export const Appear_FadeIn: IAnimationTypeConfig = {
  type: 'fadeIn',
  duration: 800,
  easing: 'easeInOutQuad',
  channel: {
    opacity: { from: 0, to: 1 }
  }
};    

This code defines a fade-in animation by adjusting the opacity attribute of a graphic element from 0 to 1 to achieve a visual fade-in effect.

10. Animation State Management

State Transition and Update

AnimateManager not only manages normal animations but also handles animation transitions in other states. For example, when new data is added, the animation in the enter state is triggered; when data is updated, the animation in the update state takes effect; and when data is removed, the animation in the exit state comes into play.

class AnimateManager extends StateManager implements IAnimate {
  updateAnimateState(state: AnimationStateEnum, noRender?: boolean) {
    if (state === AnimationStateEnum.update) {
      this.updateState(
        {
          animationState: {
            callback: (datum: any, element: IElement) => element.diffState
          }
        },
        noRender
      );
    } else if (state === AnimationStateEnum.appear) {
      // appear 状态下的动画逻辑
    } else if (state === AnimationStateEnum.exit) {
      // exit 状态下的动画逻辑
    }
  }
}    

When chart elements enter the update, appear, or exit states, the updateAnimateState method is called and passes the state to the internal state management logic. This allows all eligible elements to perform the corresponding animations.

Summary

Through the above steps, we have detailed the implementation principles of data update animations in VChart. The data update animation system of VChart cleverly combines the factory pattern, state manager pattern, and modular animation configuration, providing not only a rich set of built-in animation effects but also supporting highly customizable needs. Developers can flexibly configure and combine different animations according to actual application scenarios to create visual effects that are both beautiful and practical. Specifically:

  • **animationEnter**: Suitable for entry animations of new data points, such as fade-in, growth, etc.

  • **animationUpdate**: Suitable for update animations of existing data points, such as scaling, color gradient, etc.

  • **animationExit**: Suitable for exit animations of old data points, such as fade-out, shrink, etc.

This design ensures that when data changes, the chart can be presented to users in a smooth and intuitive manner, enhancing the interactive experience and visual appeal.

This document was revised and organized by the following personnel

Xuanhun