Skip to content

Commit

Permalink
Merge pull request #154 from VisActor/feat/character-runtime-optimiza…
Browse files Browse the repository at this point in the history
…tion

Feat/character runtime optimization
  • Loading branch information
neuqzxy authored Dec 17, 2024
2 parents 08eea54 + 3570d2b commit 7d27a14
Show file tree
Hide file tree
Showing 38 changed files with 149 additions and 209 deletions.
16 changes: 8 additions & 8 deletions docs/assets/guide/en/tutorial_docs/extend/Custom_Character.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ If you need to display a Lottie animation in your work, but the main VStory pack

Since VStory is based on VRender, we need to implement the corresponding functionality with VRender first, and then integrate it into VStory as a `Character`. Fortunately, the `@visactor/vrender-kits` package already provides a Lottie element that we can directly use.
We found the `Lottie` element in the `@visactor/vrender-kits` package, and to use it in VStory, we need to encapsulate it. The purpose of encapsulation is twofold:

1. Provide some default attributes
2. Provide parameter conversion, as the parameters in VStory are different from those in the VRender `Lottie` element. For example, layout parameters need to be converted to corresponding x, y, width, height, etc. parameters.
3. Obtain some special abilities of VStory, such as all components in VStory carry a text configuration.
Expand Down Expand Up @@ -81,17 +82,14 @@ export class LottieCharacter extends CharacterComponent<LottieComponent, ILottie

protected _group: IGroup;

static RunTime: IComponentCharacterRuntimeConstructor[] = [LottieRuntime];

protected createAndAddGraphic(attribute: ILottieComponentAttributes): void {
this._graphic = new LottieComponent(attribute);
this.canvas.addGraphic(this._graphic);
}

protected _initRuntime(): void {
LottieCharacter.RunTime.forEach(R => {
this._runtime.push(new R(this));
});
super._initRuntime();
this._runtime.push(LottieRuntimeInstance);
}

protected getDefaultAttribute(): Partial<ILottieComponentAttributes> {
Expand Down Expand Up @@ -120,9 +118,9 @@ After encapsulation, we need to define a `Runtime` for `Lottie`. `Runtime` is th
```ts
export class LottieRuntime extends BaseRuntime implements IComponentCharacterRuntime {
type = 'Lottie';
applyConfigToAttribute(): void {
super.applyConfigToAttribute();
const rawAttribute = this._character.getAttribute();
applyConfigToAttribute(character: ICharacterComponent): void {
super.applyConfigToAttribute(character);
const rawAttribute = character.getAttribute();

const { data } = rawAttribute.graphic;
// Place a default Lottie
Expand All @@ -134,6 +132,8 @@ export class LottieRuntime extends BaseRuntime implements IComponentCharacterRun
rawAttribute.graphic.fill = true;
}
}

export const LottieRuntimeInstance = new LottieRuntime();
```

## Defining Processor
Expand Down
49 changes: 25 additions & 24 deletions docs/assets/guide/zh/tutorial_docs/extend/Custom_Character.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
# 自定义Character
# 自定义 Character

在前面的章节中,我们介绍了DSL的基本概念,然后介绍了如何使用VStory来编排一个故事。但是在实际的开发中,我们可能需要自定义一些Character,比如自定义一个特殊的组件,然后在DSL中使用。这个章节我们以一个真实的例子,介绍如何自定义一个Character
在前面的章节中,我们介绍了 DSL 的基本概念,然后介绍了如何使用 VStory 来编排一个故事。但是在实际的开发中,我们可能需要自定义一些 Character,比如自定义一个特殊的组件,然后在 DSL 中使用。这个章节我们以一个真实的例子,介绍如何自定义一个 Character

## 介绍

我们提供了`@visactor/vstory-external`包,用于方便用户进行自定义Character的开发。一些扩展功能都可以在这个包中实现。下面我们通过一个接入Lottie的例子来介绍如何在这个包中进行扩展
我们提供了`@visactor/vstory-external`包,用于方便用户进行自定义 Character 的开发。一些扩展功能都可以在这个包中实现。下面我们通过一个接入 Lottie 的例子来介绍如何在这个包中进行扩展

![](https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/vstory/vstory-external.png)

## 自定义一个Lottie的Character
## 自定义一个 Lottie 的 Character

如果需要在作品中现在需要展示一个Lottie动画,但是VStory的主包里并没有提供这样的Character。现在我们就需要在`@visactor/vstory-external`包中进行扩展。
如果需要在作品中现在需要展示一个 Lottie 动画,但是 VStory 的主包里并没有提供这样的 Character。现在我们就需要在`@visactor/vstory-external`包中进行扩展。

### 实现一个基于VRender的组件
### 实现一个基于 VRender 的组件

VStory 底层是基于 VRender 的,所以我们需要用 VRender 先实现对应的功能,然后再接入到 VStory 中成为 VStory 的一个`Character`。很好的是`@visactor/vrender-kits`里已经提供了一个 Lottie 图元,我们可以直接使用。
我们找到了`@visactor/vrender-kits`包中的`Lottie`图元,在 VStory 中使用它我们需要将它封装一下,封装的目的有两个:

VStory底层是基于VRender的,所以我们需要用VRender先实现对应的功能,然后再接入到VStory中成为VStory的一个`Character`。很好的是`@visactor/vrender-kits`里已经提供了一个Lottie图元,我们可以直接使用。
我们找到了`@visactor/vrender-kits`包中的`Lottie`图元,在VStory中使用它我们需要将它封装一下,封装的目的有两个:
1. 提供一些默认的属性
2. 提供参数转换,因为VStory中的参数和VRender中`Lottie`图元的参数是不一样的,所以我们需要进行参数转换。比如布局的参数要转成对应的x、y、width、height等参数
3. 得到一些VStory的特殊能力,比如VStory的所有组件都携带一个文字配置
2. 提供参数转换,因为 VStory 中的参数和 VRender 中`Lottie`图元的参数是不一样的,所以我们需要进行参数转换。比如布局的参数要转成对应的 x、y、width、height 等参数
3. 得到一些 VStory 的特殊能力,比如 VStory 的所有组件都携带一个文字配置

```ts
export class LottieComponent extends BaseComponentWithText {
Expand Down Expand Up @@ -71,27 +72,24 @@ export class LottieComponent extends BaseComponentWithText {
}
```

### 封装一个Character
### 封装一个 Character

有了一个`Lottie`组件之后,我们就可以封装一个`Character`了。后续再`DSL`中的`character`配置就会被实例化为我们现在封装的`Character`实例,在Character中,我们将会使用上面的`Lottie`组件。
有了一个`Lottie`组件之后,我们就可以封装一个`Character`了。后续再`DSL`中的`character`配置就会被实例化为我们现在封装的`Character`实例,在 Character 中,我们将会使用上面的`Lottie`组件。

```ts
export class LottieCharacter extends CharacterComponent<LottieComponent, ILottieComponentAttributes> {
static type = LOTTIE;

protected _group: IGroup;

static RunTime: IComponentCharacterRuntimeConstructor[] = [LottieRuntime];

protected createAndAddGraphic(attribute: ILottieComponentAttributes): void {
this._graphic = new LottieComponent(attribute);
this.canvas.addGraphic(this._graphic);
}

protected _initRuntime(): void {
LottieCharacter.RunTime.forEach(R => {
this._runtime.push(new R(this));
});
super._initRuntime();
this._runtime.push(LottieRuntimeInstance);
}

protected getDefaultAttribute(): Partial<ILottieComponentAttributes> {
Expand All @@ -115,14 +113,14 @@ export class LottieCharacter extends CharacterComponent<LottieComponent, ILottie
}
```

实例封装好了之后,我们需要定义一下`Lottie``Runtime``Runtime`是一个`Character`的运行时执行的内容,其有一些生命周期,比如当主动更新Character的options时,runtime就会执行
实例封装好了之后,我们需要定义一下`Lottie``Runtime``Runtime`是一个`Character`的运行时执行的内容,其有一些生命周期,比如当主动更新 Character 的 options 时,runtime 就会执行

```ts
export class LottieRuntime extends BaseRuntime implements IComponentCharacterRuntime {
type = 'Lottie';
applyConfigToAttribute(): void {
super.applyConfigToAttribute();
const rawAttribute = this._character.getAttribute();
applyConfigToAttribute(character: ICharacterComponent): void {
super.applyConfigToAttribute(character);
const rawAttribute = character.getAttribute();

const { data } = rawAttribute.graphic;
// 放一个默认的lottie
Expand All @@ -134,13 +132,16 @@ export class LottieRuntime extends BaseRuntime implements IComponentCharacterRun
rawAttribute.graphic.fill = true;
}
}

export const LottieRuntimeInstance = new LottieRuntime();
```

## 定义processor
## 定义 processor

上面我们定义好了一个 Lottie 的 Character,现在我们需要定义具体的行为了,比如 appear、disappear、style 等用来执行入场、出场、样式变化的行为。代码中行为的定义在`processor`中。processor 负责处理 DSL 中定义的对应行为。我们只需要给`Lottie`定义一个 appear 和 disappear 的 processor 即可。其他的就复用通用组件的行为

上面我们定义好了一个Lottie的Character,现在我们需要定义具体的行为了,比如appear、disappear、style等用来执行入场、出场、样式变化的行为。代码中行为的定义在`processor`中。processor负责处理DSL中定义的对应行为。我们只需要给`Lottie`定义一个appear和disappear的processor即可。其他的就复用通用组件的行为
我们要做的很简单,只需要在 appear 的时候,调用图元播放 Lottie 动画就行。其他的就复用通用组件的行为

我们要做的很简单,只需要在appear的时候,调用图元播放Lottie动画就行。其他的就复用通用组件的行为
```ts
function runLottieAnimate(character: ICharacter, effect: string) {
const graphics = getCharacterByEffect(character, effect) as IGraphic[];
Expand Down
24 changes: 8 additions & 16 deletions packages/vstory-core/src/character/chart/character-chart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,9 @@ import { getChartModelWithEvent } from './utils/vchart-pick';
import type { ICharacterConfig, ICharacterInitOption } from '../../interface/dsl/dsl';
import type { IChartCharacterConfig } from '../../interface/dsl/chart';
import { getLayoutFromWidget } from '../../utils/layout';
import type {
IChartCharacterRuntime,
IChartCharacterRuntimeConstructor,
IUpdateConfigParams
} from './interface/runtime';
import { CommonSpecRuntime } from './runtime/common-spec';
import { CommonLayoutRuntime } from './runtime/common-layout';
import type { IChartCharacterRuntime, IUpdateConfigParams } from './interface/runtime';
import { CommonSpecRuntimeInstance } from './runtime/common-spec';
import { CommonLayoutRuntimeInstance } from './runtime/common-layout';
import { ChartConfigProcess } from './chart-config-process';
import type { ICharacterChart } from './interface/character-chart';
import { mergeChartOption } from '../../utils/chart';
Expand All @@ -32,8 +28,6 @@ export class CharacterChart<T extends IChartGraphicAttribute>
protected _timeline: ITimeline;
protected _runtime: IChartCharacterRuntime[] = [];

static RunTime: IChartCharacterRuntimeConstructor[] = [CommonSpecRuntime, CommonLayoutRuntime];

constructor(config: ICharacterConfig, option: ICharacterInitOption) {
super(config, option);
this._timeline = new DefaultTimeline();
Expand Down Expand Up @@ -152,9 +146,7 @@ export class CharacterChart<T extends IChartGraphicAttribute>
}

protected _initRuntime(): void {
CharacterChart.RunTime.forEach(R => {
this._runtime.push(new R(this));
});
this._runtime.push(CommonSpecRuntimeInstance, CommonLayoutRuntimeInstance);
}
protected _clearRuntime(): void {
this._runtime.length = 0;
Expand All @@ -173,7 +165,7 @@ export class CharacterChart<T extends IChartGraphicAttribute>

protected applyConfigToAttribute(diffConfig: IUpdateConfigParams, config: IUpdateConfigParams): void {
this._attribute = this.getDefaultAttribute() as any;
this._runtime.forEach(r => r.applyConfigToAttribute?.());
this._runtime.forEach(r => r.applyConfigToAttribute?.(this));
}

getDefaultAttribute(): Partial<IChartGraphicAttribute> {
Expand All @@ -191,17 +183,17 @@ export class CharacterChart<T extends IChartGraphicAttribute>
panel: {},
ticker: this._ticker,
zIndex: this._config.zIndex ?? 0,
vchartBoundsMode: this._config.options.initOption?.vchartBoundsMode ?? 'auto',
vchartBoundsMode: this._config.options.initOption?.vchartBoundsMode ?? 'clip',
chartInitOptions: mergeChartOption(
{
performanceHook: {
afterInitializeChart: (vchart: IVChart) => {
// (<IChartTemp>this.configProcess.dataTempTransform?.specTemp)?.afterInitialize({ character: this });
this._runtime.forEach(r => r.afterInitialize?.(vchart));
this._runtime.forEach(r => r.afterInitialize?.(this, vchart));
},

afterVRenderDraw: () => {
this._runtime.forEach(r => r.afterVRenderDraw?.());
this._runtime.forEach(r => r.afterVRenderDraw?.(this));
}
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { registerRankingBarChart } from '@visactor/vchart-extension';
import VChart from '@visactor/vchart';
import { CharacterChart } from '../character-chart';
import type { IChartGraphicAttribute } from '../graphic/vchart-graphic';
import { RankingBarRuntime } from '../runtime/ranking-bar';
import { RankingBarRuntimeInstance } from '../runtime/ranking-bar';

export function registerRankingBarTemp() {
registerRankingBarChart({ VChart });
Expand All @@ -13,7 +13,7 @@ export class RankingBarCharacter extends CharacterChart<IChartGraphicAttribute>

protected _initRuntime(): void {
super._initRuntime();
this._runtime.push(new RankingBarRuntime(this));
this._runtime.push(RankingBarRuntimeInstance);
}

tickTo(t: number): void {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { CharacterType } from '../../../constants/character';
import { CharacterChart } from '../character-chart';
import type { IChartGraphicAttribute } from '../graphic/vchart-graphic';
import { WaveScatterRuntime } from '../runtime/wave-scatter';
import { WaveScatterRuntimeInstance } from '../runtime/wave-scatter';

function waterDrop(ctx: any, size: number, topX: number, topY: number) {
ctx.beginPath();
Expand All @@ -28,7 +28,7 @@ export class WaveScatterCharacter extends CharacterChart<IWaveScatterChartGraphi

protected _initRuntime(): void {
super._initRuntime();
this._runtime.push(new WaveScatterRuntime(this));
this._runtime.push(WaveScatterRuntimeInstance);
}

getDefaultAttribute(): Partial<IWaveScatterChartGraphicAttribute> {
Expand Down
8 changes: 4 additions & 4 deletions packages/vstory-core/src/character/chart/interface/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@ import type { ICharacterConfig } from '../../../interface/dsl/dsl';
export interface IChartCharacterRuntime {
readonly type: string;
// 应用config到attribute
applyConfigToAttribute?: () => void;
applyConfigToAttribute?: (character: ICharacter) => void;

// 图表初始化完成
afterInitialize?: (vchart: IVChart) => void;
afterInitialize?: (character: ICharacter, vchart: IVChart) => void;

// 图表绘制完成
afterVRenderDraw?: () => void;
afterVRenderDraw?: (character: ICharacter) => void;
}

export interface IChartCharacterRuntimeConstructor {
new (character: ICharacter): IChartCharacterRuntime;
new (): IChartCharacterRuntime;
}

export type IUpdateConfigParams = Omit<Partial<ICharacterConfig>, 'id' | 'type'>;
20 changes: 7 additions & 13 deletions packages/vstory-core/src/character/chart/runtime/common-layout.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,13 @@
import { merge, normalizePadding } from '@visactor/vutils';
import { merge } from '@visactor/vutils';
import type { IChartCharacterRuntime } from '../interface/runtime';
import { getLayoutFromWidget } from '../../../utils/layout';
import { parsePadding } from '@visactor/vrender-core';
import type { ICharacterChart } from '../interface/character-chart';

export class CommonLayoutRuntime implements IChartCharacterRuntime {
type = 'CommonLayout';

protected declare _character: ICharacterChart;

constructor(character: ICharacterChart) {
this._character = character;
}

applyConfigToAttribute(): void {
const rawAttribute = this._character.getAttribute();
const config = this._character.config;
applyConfigToAttribute(character: ICharacterChart): void {
const rawAttribute = character.getAttribute();
const config = character.config;
const layoutData = getLayoutFromWidget(config.position);
const layout = getLayoutFromWidget(config.position);
const viewBox = {
Expand All @@ -25,7 +17,7 @@ export class CommonLayoutRuntime implements IChartCharacterRuntime {
y2: layout.height
};
rawAttribute.viewBox = viewBox;
rawAttribute.renderCanvas = this._character.canvas.getNativeCanvas();
rawAttribute.renderCanvas = character.canvas.getNativeCanvas();

merge(rawAttribute, layoutData);

Expand All @@ -34,3 +26,5 @@ export class CommonLayoutRuntime implements IChartCharacterRuntime {
merge(rawAttribute.panel, panel, layoutData);
}
}

export const CommonLayoutRuntimeInstance = new CommonLayoutRuntime();
14 changes: 5 additions & 9 deletions packages/vstory-core/src/character/chart/runtime/common-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,10 @@ import type { ICharacterChart } from '../interface/character-chart';
export class CommonSpecRuntime implements IChartCharacterRuntime {
type = 'CommonSpec';

protected declare _character: ICharacterChart;

constructor(character: ICharacterChart) {
this._character = character;
}

applyConfigToAttribute(): void {
const rawAttribute = this._character.getAttribute();
applyConfigToAttribute(character: ICharacterChart): void {
const rawAttribute = character.getAttribute();
const { spec } = rawAttribute;
const options = this._character.config.options;
const options = character.config.options;
const { title, legends, data, color, axes, rootConfig = {}, padding } = options;

if (title) {
Expand Down Expand Up @@ -45,3 +39,5 @@ export class CommonSpecRuntime implements IChartCharacterRuntime {
merge(spec, { ...rootConfig });
}
}

export const CommonSpecRuntimeInstance = new CommonSpecRuntime();
12 changes: 4 additions & 8 deletions packages/vstory-core/src/character/chart/runtime/ranking-bar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,8 @@ import type { ICharacterChart } from '../interface/character-chart';
export class RankingBarRuntime implements IChartCharacterRuntime {
type = 'RankingBar';

protected declare _character: ICharacterChart;

constructor(character: ICharacterChart) {
this._character = character;
}

applyConfigToAttribute(): void {
const rawAttribute = this._character.getAttribute();
applyConfigToAttribute(character: ICharacterChart): void {
const rawAttribute = character.getAttribute();
const { spec } = rawAttribute;
// 关掉player显示
spec.player = {
Expand All @@ -22,3 +16,5 @@ export class RankingBarRuntime implements IChartCharacterRuntime {
spec.animationEnter = false;
}
}

export const RankingBarRuntimeInstance = new RankingBarRuntime();
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,5 @@
// return;
// }
// }

// export const ScatterBarRuntimeInstance = new ScatterBarRuntime();
Loading

0 comments on commit 7d27a14

Please sign in to comment.