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

10.3 State Change Animation

Score: 5

  • State Animation:

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

  • Key Points:

  • Implementation of State 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

Often when presenting charts, different graphical elements have their own meanings, and in information display, it is necessary to emphasize or compare certain elements. By switching the state of graphical elements to display data, this process also needs to focus on visual effects, providing a more natural visual experience when the state changes.

Interpretation of State Animation (including

state and normal

State Change Animation, Animation Triggered at Any Time

State animation refers to the animation effects triggered when chart elements change according to their current state. In VChart, the design of state animation allows developers to define specific animation behaviors for different states (such as enter, update, exit, etc.). Specifically, normal state animation refers to those animations that loop or persist, running continuously after the chart is rendered until explicitly stopped.

1. Animation Configuration Structure

IAnimationSpec Interface

The IAnimationSpec interface defines the basic structure of animation configuration, which includes animation settings for different states. For normal animations, it can be specified through the animationNormal property:

interface IAnimationSpec<MarkName extends string, Preset extends string> {
  // ... 其他状态 ...
  animationNormal?: IMarkAnimateSpec<MarkName>;
}    

Here, IMarkAnimateSpec is a generic interface used to describe the animation configuration of specific elements (such as each bar in a bar chart). In this way, developers can define personalized normal animation effects for each element.

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 normal animations, the AnimateManager ensures that these animations automatically start after the chart rendering is complete and can be paused or resumed as needed.

class AnimateManager extends StateManager implements IAnimate {
  updateAnimateState(state: AnimationStateEnum, noRender?: boolean) {
    if (state === AnimationStateEnum.normal) {
      this.updateState(
        {
          animationState: {
            callback: (datum: any, element: IElement) => state
          }
        },
        noRender
      );
    }
  }
}    

When chart elements enter the normal state, the updateAnimateState method is called and the state is passed to the internal state management logic. This allows all eligible elements to perform the corresponding normal animation.

3. Animation Configuration Generation

animationConfig Function

To simplify the merging process between user configuration and default configuration, 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 === 'normal') {
      userStateConfig && (config.normal = userStateConfig as IAnimationTypeConfig);
      continue;
    }

    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 animation configuration merging in the normal state, ensuring that the user-provided configuration can be correctly applied to specific graphic elements. If the user does not provide a custom normal animation configuration, the default configuration is used.

4. Specific Implementation of

Taking a scatter plot as an example, suppose we want to add a slight pulse effect to each data point as a normal animation. Here are the detailed implementation steps:

  • Define Animation Configuration: First, specify the animationNormal configuration for the scatter plot series in the chart configuration. Here we can choose the built-in pulse animation type and adjust its duration and easing function.
const chartSpec = {
  series: [
    {
      type: 'scatter',
      data: [/* 数据数组 */],
      animationNormal: {
        type: 'pulse', // 使用脉冲效果
        duration: 800,
        easing: 'easeInOutQuad'
      }
    }
  ]
};    

  • Register Animation: Next, we need to ensure that the pulse animation has 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 { pulseAnimation } from './series/scatter/animation';

Factory.registerAnimation('pulse', pulseAnimation);    

The pulseAnimation function here defines the specific logic of the pulse animation, 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, all data points will automatically start executing the normal animation. This animation will continuously loop while the chart exists, unless explicitly stopped.
// 如果需要暂停所有正在进行的 normal 动画
chart.pauseAnimation();

// 恢复之前暂停的 normal 动画
chart.resumeAnimation();    

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, achieving more complex and delicate animation effects. For normal animations, it can work as part of an independent task chain, collaborating with other animation tasks.

6. Example: Creating a Scatter Plot with

Below is an example of creating a scatter plot with normal animation, illustrating how to use VChart's state animation system to implement the basic process.

Step 1: Define Animation Configuration

First, we need to define the basic configuration of the scatter plot, including the data source and other visual attributes. At the same time, we will specify the normal animation configuration here to ensure that each data point can perform the pulse effect.

const chartSpec = {
  series: [
    {
      type: 'scatter',
      data: [
        { x: 10, y: 20 },
        { x: 20, y: 30 },
        { x: 30, y: 40 }
      ],
      animationNormal: {
        type: 'pulse',
        duration: 800,
        easing: 'easeInOutQuad'
      }
    }
  ]
};    

Step 2: Register Animation

Ensure that the required pulse animation has 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 { pulseAnimation } from './series/scatter/animation';

Factory.registerAnimation('pulse', pulseAnimation);    

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

Once the chart is rendered, all data points will automatically start executing the normal animation. This animation will continue to loop as long as the chart exists, unless explicitly stopped.

// 如果需要暂停所有正在进行的 normal 动画
chart.pauseAnimation();

// 恢复之前暂停的 normal 动画
chart.resumeAnimation();    

Step 5: Dynamically Control Animation

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

// 更新某个系列的 normal 动画配置
chart.updateSeriesOptions(0, {
  animationNormal: {
    duration: 1200, // 更改持续时间
    easing: 'linear' // 更改缓动函数
  }
});

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

7. 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) {
      // 更新状态下的动画逻辑
    } else if (state === AnimationStateEnum.appear) {
      // 出现状态下的动画逻辑
    } else if (state === AnimationStateEnum.normal) {
      // normal 状态下的动画逻辑
      this.updateState(
        {
          animationState: {
            callback: (datum: any, element: IElement) => state
          }
        },
        noRender
      );
    }
  }
}    

In this example, when the element enters the normal state, the updateAnimateState method will update the element's state and trigger the corresponding animation logic. This means that each data point will execute the animation according to the preset normal animation configuration until the state changes again.

8. Animation Lifecycle Management

Event Listeners and Hooks

To better manage the animation lifecycle, 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 the VGRAMMAR_HOOK_EVENT.ANIMATION_END will be triggered at the end of the animation.

this._event.on(VGRAMMAR_HOOK_EVENT.AFTER_DO_RENDER, () => {
  this.runAnimationByState(AnimationStateEnum.normal);
});

this._event.on(VGRAMMAR_HOOK_EVENT.ANIMATION_END, ({ event }) => {
  if (event.animationState === AnimationStateEnum.appear) {
    this.runAnimationByState(AnimationStateEnum.normal);
  }
});    

This code demonstrates how to start the normal animation immediately after the chart rendering is completed, and how to seamlessly switch to the normal animation after the entrance animation ends. This design ensures a smooth transition between animations, enhancing the user experience.

Summary

Through the above steps, we have detailed the implementation principle of the normal state animation in VChart. The normal animation, as a type of state animation, is mainly used to describe the animation effect of chart elements continuously existing in a stable state. VChart ensures the flexibility and maintainability of the normal animation through modular design, factory pattern, state manager pattern, and event-driven mechanism. Developers can easily customize different types of normal animation effects according to actual needs, thereby enhancing the visual appeal and interactive experience of the chart.

This document was revised and organized by the following personnel

玄魂