|
1 | 1 | import type { ComponentAnimator } from '../component'; |
2 | | -import type { EasingType, IAnimateStepType, ICustomAnimate } from '@visactor/vrender-core'; |
| 2 | +import type { EasingType, IAnimateStepType, ICustomAnimate, Stage } from '@visactor/vrender-core'; |
3 | 3 | import { Step } from '../step'; |
4 | 4 |
|
5 | 5 | export abstract class ACustomAnimate<T> extends Step implements ICustomAnimate { |
@@ -52,3 +52,78 @@ export abstract class AComponentAnimate<T> extends ACustomAnimate<T> { |
52 | 52 | this._animator && this._animator.stop(); |
53 | 53 | } |
54 | 54 | } |
| 55 | + |
| 56 | +export abstract class AStageAnimate<T> extends ACustomAnimate<T> { |
| 57 | + willCallBeforeStageRender: boolean = true; |
| 58 | + willCallAfterStageRender: boolean = true; |
| 59 | + constructor(customFrom: T, customTo: T, duration: number, easing: EasingType, params?: any) { |
| 60 | + super(customFrom, customTo, duration, easing, params); |
| 61 | + this.props = {} as T; |
| 62 | + } |
| 63 | + |
| 64 | + // 用户重载 |
| 65 | + protected beforeStageRender(stage: Stage, canvas: HTMLCanvasElement): HTMLCanvasElement | void | null | false { |
| 66 | + return false; |
| 67 | + } |
| 68 | + |
| 69 | + // 用户重载 |
| 70 | + protected afterStageRender(stage: Stage, canvas: HTMLCanvasElement): HTMLCanvasElement | void | null | false { |
| 71 | + return false; |
| 72 | + } |
| 73 | + |
| 74 | + onFirstRun(): void { |
| 75 | + super.onFirstRun(); |
| 76 | + this.target.stage.setBeforeRender(this._beforeStageRender); |
| 77 | + this.target.stage.setAfterRender(this._afterStageRender); |
| 78 | + // 禁用脏矩形,因为stage动画可能会批量修改整体画面 |
| 79 | + this.target.stage.disableDirtyBounds(); |
| 80 | + } |
| 81 | + |
| 82 | + stop() { |
| 83 | + super.stop(); |
| 84 | + this.target.stage.removeBeforeRender(this._beforeStageRender); |
| 85 | + this.target.stage.removeAfterRender(this._afterStageRender); |
| 86 | + } |
| 87 | + onUpdate(end: boolean, ratio: number, out: Record<string, any>): void { |
| 88 | + super.onUpdate(end, ratio, out); |
| 89 | + this.willCallBeforeStageRender = true; |
| 90 | + this.willCallAfterStageRender = true; |
| 91 | + } |
| 92 | + |
| 93 | + protected _beforeStageRender = () => { |
| 94 | + if (!this.willCallBeforeStageRender) { |
| 95 | + return; |
| 96 | + } |
| 97 | + this.willCallBeforeStageRender = false; |
| 98 | + const stage = this.target.stage as any; |
| 99 | + const canvas = stage.window.getContext().canvas.nativeCanvas; |
| 100 | + const outputCanvas = this.beforeStageRender(stage, canvas); |
| 101 | + if (outputCanvas) { |
| 102 | + this.renderToStage(stage, outputCanvas); |
| 103 | + } |
| 104 | + }; |
| 105 | + |
| 106 | + protected _afterStageRender = () => { |
| 107 | + if (!this.willCallAfterStageRender) { |
| 108 | + return; |
| 109 | + } |
| 110 | + this.willCallAfterStageRender = false; |
| 111 | + const stage = this.target.stage as any; |
| 112 | + const canvas = stage.window.getContext().canvas.nativeCanvas; |
| 113 | + const outputCanvas = this.afterStageRender(stage, canvas); |
| 114 | + if (outputCanvas) { |
| 115 | + this.renderToStage(stage, outputCanvas); |
| 116 | + } |
| 117 | + }; |
| 118 | + |
| 119 | + protected renderToStage(stage: Stage, canvas: HTMLCanvasElement): HTMLCanvasElement | void | null | false { |
| 120 | + const stageCanvas = stage.window.getContext().canvas.nativeCanvas; |
| 121 | + const ctx = stageCanvas.getContext('2d'); |
| 122 | + if (!ctx) { |
| 123 | + return false; |
| 124 | + } |
| 125 | + ctx.clearRect(0, 0, stageCanvas.width, stageCanvas.height); |
| 126 | + ctx.drawImage(canvas, 0, 0); |
| 127 | + return stageCanvas; |
| 128 | + } |
| 129 | +} |
0 commit comments