From eaec9322ee689d0285b99dd8f0fb716a52820031 Mon Sep 17 00:00:00 2001 From: zhouxinyu Date: Wed, 7 Aug 2024 17:48:47 +0800 Subject: [PATCH] feat: component support visibility --- .../vstory/demo/src/demos/BaseComponent.tsx | 46 +++++------ .../src/player/processor/chart/vchart.ts | 2 +- .../processor/component/common-component.ts | 79 +++++++++++++------ .../processor/component/image/image-appear.ts | 8 -- .../component/image/image-visibility.ts | 8 ++ .../processor/component/line/line-appear.ts | 8 -- .../component/line/line-visibility.ts | 8 ++ .../processor/component/rect/rect-appear.ts | 8 -- .../component/rect/rect-visibility.ts | 8 ++ .../processor/component/shape/shape-appear.ts | 8 -- .../component/shape/shape-visibility.ts | 8 ++ .../processor/component/text/text-appear.ts | 37 --------- .../component/text/text-visibility.ts | 46 +++++++++++ ...eline-appear.ts => timeline-visibility.ts} | 8 +- .../src/player/processor/processorMap.ts | 30 ++++--- 15 files changed, 179 insertions(+), 133 deletions(-) delete mode 100644 packages/vstory/src/player/processor/component/image/image-appear.ts create mode 100644 packages/vstory/src/player/processor/component/image/image-visibility.ts delete mode 100644 packages/vstory/src/player/processor/component/line/line-appear.ts create mode 100644 packages/vstory/src/player/processor/component/line/line-visibility.ts delete mode 100644 packages/vstory/src/player/processor/component/rect/rect-appear.ts create mode 100644 packages/vstory/src/player/processor/component/rect/rect-visibility.ts delete mode 100644 packages/vstory/src/player/processor/component/shape/shape-appear.ts create mode 100644 packages/vstory/src/player/processor/component/shape/shape-visibility.ts delete mode 100644 packages/vstory/src/player/processor/component/text/text-appear.ts create mode 100644 packages/vstory/src/player/processor/component/text/text-visibility.ts rename packages/vstory/src/player/processor/component/timeline/{timeline-appear.ts => timeline-visibility.ts} (83%) diff --git a/packages/vstory/demo/src/demos/BaseComponent.tsx b/packages/vstory/demo/src/demos/BaseComponent.tsx index f7d54b5c..6b8d528f 100644 --- a/packages/vstory/demo/src/demos/BaseComponent.tsx +++ b/packages/vstory/demo/src/demos/BaseComponent.tsx @@ -155,85 +155,85 @@ export const BaseComponent = () => { { id: 'scene0', actions: [ - ...new Array(3).fill(0).map((_, i) => { + ...new Array(6).fill(0).map((_, i) => { return { - characterId: 'rect' + i, + characterId: 'rect' + (i % 3), characterActions: [ { startTime: i * 1700, - action: 'appear', + action: i / 3 >= 1 ? 'disappear' : 'appear', payload: { animation: { duration: 1600, - effect: ['fadeIn', 'scaleIn', 'wipeIn'][i] + effect: ['fade', 'scale', 'wipe'][i % 3] } } } ] }; }), - ...new Array(3).fill(0).map((_, i) => { + ...new Array(6).fill(0).map((_, i) => { return { - characterId: 'line' + i, + characterId: 'line' + (i % 3), characterActions: [ { startTime: i * 1700, - action: 'appear', + action: i / 3 >= 1 ? 'disappear' : 'appear', payload: { animation: { duration: 1600, - effect: ['fadeIn', 'scaleIn', 'wipeIn'][i] + effect: ['fade', 'scale', 'wipe'][i % 3] } } } ] }; }), - ...new Array(3).fill(0).map((_, i) => { + ...new Array(6).fill(0).map((_, i) => { return { - characterId: 'shape' + i, + characterId: 'shape' + (i % 3), characterActions: [ { startTime: i * 1700, - action: 'appear', + action: i / 3 >= 1 ? 'disappear' : 'appear', payload: { animation: { duration: 1600, - effect: ['fadeIn', 'scaleIn', 'wipeIn'][i] + effect: ['fade', 'scale', 'wipe'][i % 3] } } } ] }; }), - ...new Array(3).fill(0).map((_, i) => { + ...new Array(6).fill(0).map((_, i) => { return { - characterId: 'image' + i, + characterId: 'image' + (i % 3), characterActions: [ { startTime: i * 1700, - action: 'appear', + action: i / 3 >= 1 ? 'disappear' : 'appear', payload: { animation: { duration: 1600, - effect: ['fadeIn', 'scaleIn', 'wipeIn'][i] + effect: ['fade', 'scale', 'wipe'][i % 3] } } } ] }; }), - ...new Array(4).fill(0).map((_, i) => { + ...new Array(8).fill(0).map((_, i) => { return { - characterId: 'text' + i, + characterId: 'text' + (i % 4), characterActions: [ { startTime: i * 1700, - action: 'appear', + action: i / 4 >= 1 ? 'disappear' : 'appear', payload: { animation: { duration: 1600, - effect: ['fadeIn', 'scaleIn', 'wipeIn', 'typewriter'][i] + effect: ['fade', 'scale', 'wipe', 'typewriter'][i % 4] } } } @@ -242,15 +242,15 @@ export const BaseComponent = () => { }), ...new Array(4).fill(0).map((_, i) => { return { - characterId: 'timeline' + i, + characterId: 'timeline' + (i % 4), characterActions: [ { startTime: i * 1700, - action: 'appear', + action: i / 4 >= 1 ? 'disappear' : 'appear', payload: { animation: { duration: 1600, - effect: ['fadeIn', 'scaleIn', 'wipeIn', 'default'][i] + effect: ['fade', 'scale', 'wipe', 'default'][i % 4] } } } diff --git a/packages/vstory/src/player/processor/chart/vchart.ts b/packages/vstory/src/player/processor/chart/vchart.ts index ae6c0780..082d3548 100644 --- a/packages/vstory/src/player/processor/chart/vchart.ts +++ b/packages/vstory/src/player/processor/chart/vchart.ts @@ -28,7 +28,7 @@ export class VChartVisibilityActionProcessor extends ActionProcessorItem { } run(character: ICharacter, actionSpec: IAction): void { - const vchart = character.graphic._vchart as IVChart; + const vchart = (character.graphic as any)._vchart as IVChart; // series & mark const seriesList = vchart.getChart().getAllSeries(); seriesList.forEach(series => { diff --git a/packages/vstory/src/player/processor/component/common-component.ts b/packages/vstory/src/player/processor/component/common-component.ts index b2b3499f..64feb8bc 100644 --- a/packages/vstory/src/player/processor/component/common-component.ts +++ b/packages/vstory/src/player/processor/component/common-component.ts @@ -17,10 +17,14 @@ import { canDoGraphicAnimation } from './utils'; function fadeIn(character: ICharacter, animation: IFadeInParams, effect: string) { const graphic = getCharacterParentGraphic(character); - _fadeIn(graphic, animation as any); + _fade(graphic, animation as any, true); +} +function fadeOut(character: ICharacter, animation: IFadeInParams, effect: string) { + const graphic = getCharacterParentGraphic(character); + _fade(graphic, animation as any, false); } -function _fadeIn(graphic: IGraphic, params: IFadeInParams): boolean { +function _fade(graphic: IGraphic, params: IFadeInParams, appear: boolean): boolean { if (!canDoGraphicAnimation(graphic, params)) { return false; } @@ -28,22 +32,33 @@ function _fadeIn(graphic: IGraphic, params: IFadeInParams): boolean { const opacity = fade.opacity ?? params.opacity ?? 1; const duration = fade.duration ?? params.duration; const easing = fade.easing ?? params.easing; + // TODO VRender处理opacity为0 + let from = 0.001; + let to = opacity; + if (!appear) { + [from, to] = [to, from]; + } + graphic.setAttributes({ - baseOpacity: 0.001 + baseOpacity: from } as any); - graphic.animate().to({ baseOpacity: opacity }, duration, easing as EasingType); + graphic.animate().to({ baseOpacity: to }, duration, easing as EasingType); return true; } function scaleIn(character: ICharacter, animation: IFadeInParams, effect: string) { const graphics = getCharacterByEffect(character, effect) as IGraphic[]; - graphics.forEach(graphic => _scaleIn(graphic, animation as any)); + graphics.forEach(graphic => _scale(graphic, animation as any, true)); +} +function scaleOut(character: ICharacter, animation: IFadeInParams, effect: string) { + const graphics = getCharacterByEffect(character, effect) as IGraphic[]; + graphics.forEach(graphic => _scale(graphic, animation as any, false)); } -function _scaleIn(graphic: IGraphic, params: IScaleInParams): boolean { +function _scale(graphic: IGraphic, params: IScaleInParams, appear: boolean): boolean { if (!canDoGraphicAnimation(graphic, params)) { return false; } @@ -52,11 +67,17 @@ function _scaleIn(graphic: IGraphic, params: IScaleInParams): boolean { const duration = scale.duration ?? params.duration; const easing = scale.easing ?? params.easing; + let from = 0; + let to = ratio; + if (!appear) { + [from, to] = [to, from]; + } + graphic.setAttributes({ - scaleX: 0, - scaleY: 0 + scaleX: from, + scaleY: from }); - graphic.animate().to({ scaleX: ratio, scaleY: ratio }, duration, easing as EasingType); + graphic.animate().to({ scaleX: to, scaleY: to }, duration, easing as EasingType); return true; } @@ -70,9 +91,13 @@ const Direction: any = { function wipeIn(character: ICharacter, animation: IFadeInParams, effect: string) { const graphic = getCharacterParentGraphic(character); - _wipeIn(graphic, animation as any); + _wipe(graphic, animation as any, true); +} +function wipeOut(character: ICharacter, animation: IFadeInParams, effect: string) { + const graphic = getCharacterParentGraphic(character); + _wipe(graphic, animation as any, false); } -function _wipeIn(graphic: IGraphic, params: IWipeInParams) { +function _wipe(graphic: IGraphic, params: IWipeInParams, appear: boolean) { if (!canDoGraphicAnimation(graphic, params)) { return false; } @@ -82,21 +107,27 @@ function _wipeIn(graphic: IGraphic, params: IWipeInParams) { const duration = wipe.duration ?? params.duration; const easing = wipe.easing ?? params.easing; + let fromRatio = 0; + let toRatio = 1; + if (!appear) { + [fromRatio, toRatio] = [toRatio, fromRatio]; + } + graphic.setAttributes({ wipeDirection: Direction[from], - wipeRatio: 0 + wipeRatio: fromRatio } as any); graphic .animate() - .to({ wipeRatio: 1 }, duration, easing) + .to({ wipeRatio: toRatio }, duration, easing) .onEnd(() => { - graphic.setAttributes({ wipeRatio: 1 } as any); + graphic.setAttributes({ wipeRatio: toRatio } as any); }); return true; } export class CommonAppearActionProcessor extends ActionProcessorItem { - name: 'appear'; + name: 'appearOrDisAppear'; constructor() { super(); @@ -116,21 +147,21 @@ export class CommonAppearActionProcessor extends ActionProcessorItem { run(character: ICharacter, actionSpec: IAction): void { const { animation } = actionSpec.payload ?? {}; - const { effect = 'fadeIn' } = animation ?? ({} as any); + const { effect = 'fade' } = animation ?? ({} as any); - const effectFunc = this.getEffectFunc(effect); + const effectFunc = this.getEffectFunc(effect, actionSpec.action === 'appear'); effectFunc(character, animation as any, effect); } - getEffectFunc(effect: string) { + getEffectFunc(effect: string, appear: boolean) { switch (effect) { - case 'scaleIn': - return scaleIn; - case 'wipeIn': - return wipeIn; - case 'fadeIn': - return fadeIn; + case 'scale': + return appear ? scaleIn : scaleOut; + case 'wipe': + return appear ? wipeIn : wipeOut; + case 'fade': + return appear ? fadeIn : fadeOut; } return fadeIn; } diff --git a/packages/vstory/src/player/processor/component/image/image-appear.ts b/packages/vstory/src/player/processor/component/image/image-appear.ts deleted file mode 100644 index eadf47bd..00000000 --- a/packages/vstory/src/player/processor/component/image/image-appear.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { CommonAppearActionProcessor } from '../common-component'; - -export class ImageAppearActionProcessor extends CommonAppearActionProcessor { - name: 'appear'; - constructor() { - super(); - } -} diff --git a/packages/vstory/src/player/processor/component/image/image-visibility.ts b/packages/vstory/src/player/processor/component/image/image-visibility.ts new file mode 100644 index 00000000..9900363c --- /dev/null +++ b/packages/vstory/src/player/processor/component/image/image-visibility.ts @@ -0,0 +1,8 @@ +import { CommonAppearActionProcessor } from '../common-component'; + +export class ImageVisibilityActionProcessor extends CommonAppearActionProcessor { + name: 'appearOrDisAppear'; + constructor() { + super(); + } +} diff --git a/packages/vstory/src/player/processor/component/line/line-appear.ts b/packages/vstory/src/player/processor/component/line/line-appear.ts deleted file mode 100644 index 44dc6474..00000000 --- a/packages/vstory/src/player/processor/component/line/line-appear.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { CommonAppearActionProcessor } from '../common-component'; - -export class LineAppearActionProcessor extends CommonAppearActionProcessor { - name: 'appear'; - constructor() { - super(); - } -} diff --git a/packages/vstory/src/player/processor/component/line/line-visibility.ts b/packages/vstory/src/player/processor/component/line/line-visibility.ts new file mode 100644 index 00000000..36931b15 --- /dev/null +++ b/packages/vstory/src/player/processor/component/line/line-visibility.ts @@ -0,0 +1,8 @@ +import { CommonAppearActionProcessor } from '../common-component'; + +export class LineVisibilityActionProcessor extends CommonAppearActionProcessor { + name: 'appearOrDisAppear'; + constructor() { + super(); + } +} diff --git a/packages/vstory/src/player/processor/component/rect/rect-appear.ts b/packages/vstory/src/player/processor/component/rect/rect-appear.ts deleted file mode 100644 index 90041b0d..00000000 --- a/packages/vstory/src/player/processor/component/rect/rect-appear.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { CommonAppearActionProcessor } from '../common-component'; - -export class RectAppearActionProcessor extends CommonAppearActionProcessor { - name: 'appear'; - constructor() { - super(); - } -} diff --git a/packages/vstory/src/player/processor/component/rect/rect-visibility.ts b/packages/vstory/src/player/processor/component/rect/rect-visibility.ts new file mode 100644 index 00000000..19913a63 --- /dev/null +++ b/packages/vstory/src/player/processor/component/rect/rect-visibility.ts @@ -0,0 +1,8 @@ +import { CommonAppearActionProcessor } from '../common-component'; + +export class RectVisibilityActionProcessor extends CommonAppearActionProcessor { + name: 'appearOrDisAppear'; + constructor() { + super(); + } +} diff --git a/packages/vstory/src/player/processor/component/shape/shape-appear.ts b/packages/vstory/src/player/processor/component/shape/shape-appear.ts deleted file mode 100644 index 9e8a4444..00000000 --- a/packages/vstory/src/player/processor/component/shape/shape-appear.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { CommonAppearActionProcessor } from '../common-component'; - -export class ShapeAppearActionProcessor extends CommonAppearActionProcessor { - name: 'appear'; - constructor() { - super(); - } -} diff --git a/packages/vstory/src/player/processor/component/shape/shape-visibility.ts b/packages/vstory/src/player/processor/component/shape/shape-visibility.ts new file mode 100644 index 00000000..3d5da14f --- /dev/null +++ b/packages/vstory/src/player/processor/component/shape/shape-visibility.ts @@ -0,0 +1,8 @@ +import { CommonAppearActionProcessor } from '../common-component'; + +export class ShapeVisibilityActionProcessor extends CommonAppearActionProcessor { + name: 'appearOrDisAppear'; + constructor() { + super(); + } +} diff --git a/packages/vstory/src/player/processor/component/text/text-appear.ts b/packages/vstory/src/player/processor/component/text/text-appear.ts deleted file mode 100644 index b2f0b388..00000000 --- a/packages/vstory/src/player/processor/component/text/text-appear.ts +++ /dev/null @@ -1,37 +0,0 @@ -import type { EasingType, IGraphic, IText } from '@visactor/vrender-core'; -import { CommonAppearActionProcessor } from '../common-component'; -import { isString } from '@visactor/vutils'; -import { TypeWriter } from '../../../../animate/typewirter'; -import type { ICharacter } from '../../../../story/character'; -import type { ITypeWriterParams } from '../../interface/appear-action'; -import { getCharacterByEffect } from '../../../../dsl/story-processor/graphic/util'; - -function typewriter(character: ICharacter, animation: ITypeWriterParams, effect: string) { - const graphics = getCharacterByEffect(character, effect) as IGraphic[]; - graphics.forEach((graphic: any) => _typewriter(graphic, animation as any)); -} - -function _typewriter(graphic: IText, params: any) { - if (graphic && graphic.type === 'text') { - const { duration, easing } = params; - const { text } = graphic.attribute; - if (isString(text)) { - graphic.animate().play(new TypeWriter({ text: '' }, { text }, duration, easing as EasingType)); - } - } -} - -export class TextAppearActionProcessor extends CommonAppearActionProcessor { - name: 'appear'; - constructor() { - super(); - } - - getEffectFunc(effect: string) { - switch (effect) { - case 'typewriter': - return typewriter; - } - return super.getEffectFunc(effect); - } -} diff --git a/packages/vstory/src/player/processor/component/text/text-visibility.ts b/packages/vstory/src/player/processor/component/text/text-visibility.ts new file mode 100644 index 00000000..70d6690f --- /dev/null +++ b/packages/vstory/src/player/processor/component/text/text-visibility.ts @@ -0,0 +1,46 @@ +import type { EasingType, IGraphic, IText } from '@visactor/vrender-core'; +import { CommonAppearActionProcessor } from '../common-component'; +import { isString } from '@visactor/vutils'; +import { TypeWriter } from '../../../../animate/typewirter'; +import type { ICharacter } from '../../../../story/character'; +import type { ITypeWriterParams } from '../../interface/appear-action'; +import { getCharacterByEffect } from '../../../../dsl/story-processor/graphic/util'; + +function typewriterIn(character: ICharacter, animation: ITypeWriterParams, effect: string) { + const graphics = getCharacterByEffect(character, effect) as IGraphic[]; + graphics.forEach((graphic: any) => _typewriter(graphic, animation as any, true)); +} +function typewriterOut(character: ICharacter, animation: ITypeWriterParams, effect: string) { + const graphics = getCharacterByEffect(character, effect) as IGraphic[]; + graphics.forEach((graphic: any) => _typewriter(graphic, animation as any, false)); +} + +function _typewriter(graphic: IText, params: any, appear: boolean) { + if (graphic && graphic.type === 'text') { + const { duration, easing } = params; + const { text } = graphic.attribute; + if (isString(text)) { + let from = ''; + let to = text; + if (!appear) { + [from, to] = [to, from]; + } + graphic.animate().play(new TypeWriter({ text: from }, { text: to }, duration, easing as EasingType)); + } + } +} + +export class TextVisibilityActionProcessor extends CommonAppearActionProcessor { + name: 'appearOrDisAppear'; + constructor() { + super(); + } + + getEffectFunc(effect: string, appear: boolean) { + switch (effect) { + case 'typewriter': + return appear ? typewriterIn : typewriterOut; + } + return super.getEffectFunc(effect, appear); + } +} diff --git a/packages/vstory/src/player/processor/component/timeline/timeline-appear.ts b/packages/vstory/src/player/processor/component/timeline/timeline-visibility.ts similarity index 83% rename from packages/vstory/src/player/processor/component/timeline/timeline-appear.ts rename to packages/vstory/src/player/processor/component/timeline/timeline-visibility.ts index 135fb779..d12b491a 100644 --- a/packages/vstory/src/player/processor/component/timeline/timeline-appear.ts +++ b/packages/vstory/src/player/processor/component/timeline/timeline-visibility.ts @@ -19,17 +19,17 @@ function _defaultAppear(graphic: Timeline, params: any) { } } -export class TimelineAppearActionProcessor extends CommonAppearActionProcessor { - name: 'appear'; +export class TimelineVisibilityActionProcessor extends CommonAppearActionProcessor { + name: 'appearOrDisAppear'; constructor() { super(); } - getEffectFunc(effect: string = 'default') { + getEffectFunc(effect: string = 'default', appear: boolean) { switch (effect) { case 'default': return defaultAppear; } - return super.getEffectFunc(effect); + return super.getEffectFunc(effect, appear); } } diff --git a/packages/vstory/src/player/processor/processorMap.ts b/packages/vstory/src/player/processor/processorMap.ts index b9d4cf49..9a948fcd 100644 --- a/packages/vstory/src/player/processor/processorMap.ts +++ b/packages/vstory/src/player/processor/processorMap.ts @@ -1,12 +1,12 @@ import { ACTION_TYPE } from '../../constants/action'; import { StoryChartType, StoryComponentType } from '../../constants/character'; -import { ImageAppearActionProcessor } from './component/image/image-appear'; +import { ImageVisibilityActionProcessor } from './component/image/image-visibility'; import { VChartVisibilityActionProcessor } from './chart/vchart'; -import { LineAppearActionProcessor } from './component/line/line-appear'; -import { RectAppearActionProcessor } from './component/rect/rect-appear'; -import { ShapeAppearActionProcessor } from './component/shape/shape-appear'; -import { TextAppearActionProcessor } from './component/text/text-appear'; -import { TimelineAppearActionProcessor } from './component/timeline/timeline-appear'; +import { LineVisibilityActionProcessor } from './component/line/line-visibility'; +import { RectVisibilityActionProcessor } from './component/rect/rect-visibility'; +import { ShapeVisibilityActionProcessor } from './component/shape/shape-visibility'; +import { TextVisibilityActionProcessor } from './component/text/text-visibility'; +import { TimelineVisibilityActionProcessor } from './component/timeline/timeline-visibility'; export const processorChartMap = { [StoryChartType.VCHART]: { @@ -17,22 +17,28 @@ export const processorChartMap = { export const processorComponentMap = { [StoryComponentType.RECT]: { - [ACTION_TYPE.APPEAR]: new RectAppearActionProcessor() + [ACTION_TYPE.APPEAR]: new RectVisibilityActionProcessor(), + [ACTION_TYPE.DISAPPEAR]: new RectVisibilityActionProcessor() }, [StoryComponentType.LINE]: { - [ACTION_TYPE.APPEAR]: new LineAppearActionProcessor() + [ACTION_TYPE.APPEAR]: new LineVisibilityActionProcessor(), + [ACTION_TYPE.DISAPPEAR]: new LineVisibilityActionProcessor() }, [StoryComponentType.SHAPE]: { - [ACTION_TYPE.APPEAR]: new ShapeAppearActionProcessor() + [ACTION_TYPE.APPEAR]: new ShapeVisibilityActionProcessor(), + [ACTION_TYPE.DISAPPEAR]: new ShapeVisibilityActionProcessor() }, [StoryComponentType.IMAGE]: { - [ACTION_TYPE.APPEAR]: new ImageAppearActionProcessor() + [ACTION_TYPE.APPEAR]: new ImageVisibilityActionProcessor(), + [ACTION_TYPE.DISAPPEAR]: new ImageVisibilityActionProcessor() }, [StoryComponentType.TEXT]: { - [ACTION_TYPE.APPEAR]: new TextAppearActionProcessor() + [ACTION_TYPE.APPEAR]: new TextVisibilityActionProcessor(), + [ACTION_TYPE.DISAPPEAR]: new TextVisibilityActionProcessor() }, [StoryComponentType.TIMELINE]: { - [ACTION_TYPE.APPEAR]: new TimelineAppearActionProcessor() + [ACTION_TYPE.APPEAR]: new TimelineVisibilityActionProcessor(), + [ACTION_TYPE.DISAPPEAR]: new TimelineVisibilityActionProcessor() } };