Skip to content

Commit

Permalink
feat:增加跳转&速度控制 (#267)
Browse files Browse the repository at this point in the history
* feat: 增加跳转

* feat: speed

---------

Co-authored-by: xuying.xu <[email protected]>
  • Loading branch information
tangying1027 and xuying.xu authored May 7, 2024
1 parent f194efa commit 99b9eea
Show file tree
Hide file tree
Showing 10 changed files with 229 additions and 57 deletions.
24 changes: 17 additions & 7 deletions packages/f-engine/src/canvas/render/animation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -374,21 +374,31 @@ function calAnimationTime(
keyFrame: Record<string, playerFrame>,
parentEffect?: any,
) {
if (!childrenAnimation) return;
const animations = [];
if (!childrenAnimation) return { animators: null, time: 0 };

const animators = [];
let time = 0;

Children.map(childrenAnimation, (item: Animator) => {
if (!item) return;
const animator = item.clone();
const { vNode, children } = animator;
const { duration, delay } = keyFrame[vNode?.key] || {};

const globalEffect = mix(parentEffect, { duration, delay }) || {};
animator.globalEffect = globalEffect;
animator.children = calAnimationTime(children, keyFrame, globalEffect);
const globalEffect = mix(parentEffect || {}, { duration, delay });
const effect = { ...animator.effect, ...globalEffect };
animator.effect = effect;

animations.push(animator);
// computed time
const { duration: gDuration = 0, delay: gDelay = 0 } = effect;
const animUnits = calAnimationTime(children, keyFrame, globalEffect);
time = Math.max(time, gDuration + gDelay, animUnits.time);

animator.children = animUnits.animators;
animators.push(animator);
});
return animations;

return { animators, time };
}

export { createAnimation, calAnimationTime };
16 changes: 10 additions & 6 deletions packages/f-engine/src/canvas/render/animator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@ class Animator extends EE {
animations: IAnimation[];
// 节点动画树
children: Animator[];
// 组件下的全局effect
globalEffect: any;
time: number;

constructor() {
super();
Expand All @@ -32,11 +29,10 @@ class Animator extends EE {

// 首次播放
run() {
const { vNode, shape, start, end, effect, children, globalEffect } = this;
const { vNode, shape, start, end, effect, children } = this;

const animations: IAnimation[] = [];
if (effect) {
const mergeEffect = { ...effect, ...globalEffect };
const {
property = [],
easing,
Expand All @@ -47,7 +43,7 @@ class Animator extends EE {
direction = 'normal',
onFrame,
onEnd,
} = mergeEffect;
} = effect;
// shape 动画
if ((property.length || onFrame) && duration > 0) {
// 应用样式
Expand Down Expand Up @@ -239,6 +235,14 @@ class Animator extends EE {
});
}

setPlaybackRate(speed) {
const { animations } = this;
if (!animations || !animations.length) return;
animations.forEach((d) => {
d.playbackRate = speed;
});
}

endEmit(animations: IAnimation[]) {
if (!animations.length) {
this.emit('end');
Expand Down
4 changes: 2 additions & 2 deletions packages/f-engine/src/canvas/render/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -433,9 +433,9 @@ function getUpdateAnimation(component, newChildren, keyFrame) {
component.didUpdate();

// 处理 animator
const cloneChildrenAinmation = calAnimationTime(childrenAnimation, keyFrame);
const animUnits = calAnimationTime(childrenAnimation, keyFrame);

return cloneChildrenAinmation;
return animUnits;
}

export {
Expand Down
57 changes: 37 additions & 20 deletions packages/f-engine/src/canvas/timeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,60 +3,69 @@ import { Group } from '@antv/g-lite';
import Animator from './render/animator';
import EE from 'eventemitter3';

type AnimaUnit = {
childrenAnimation: Animator[];
totalTime: number;
type AnimUnit = {
animators: Animator[];
time: number;
};
class Timeline extends EE {
animator: Animator;
animators: AnimaUnit[] = [];
animUnits: AnimUnit[] = [];
frame: number = 0;
playState: string = 'play';
endFrame: number;
speed: number;
time: number;

constructor(props) {
super();
const { animators, playState, root } = props;
const { animUnits, playState, root, speed = 1, goto } = props;
this.animator = new Animator();
const rootShape = new Group();
this.animator.reset(rootShape);
root.appendChild(rootShape);

this.animators = animators;
this.animUnits = animUnits;
this.playState = playState;
this.endFrame = animators.length - 1;
this.endFrame = animUnits.length - 1;
this.speed = speed;
this.time = goto;
}

start() {
const { animator, frame, playState, endFrame } = this;
const { animator, frame, playState, endFrame, time, speed } = this;
if (frame < endFrame && playState === 'finish') {
this.frame = endFrame;
}
this.drawFrame();
animator.on('end', this.next);
this.animator.run();
this.setPlayState(playState);
time && this.goTo(time);
this.setPlaybackRate(speed);
}

next = () => {
const { frame, playState, endFrame } = this;
const { frame, playState, endFrame, speed } = this;
if (playState !== 'play') return;

this.frame = frame + 1;
if (frame < endFrame) {
this.drawFrame();
this.animator.run();
this.setPlaybackRate(speed);
} else {
this.emit('end');
this.playState = 'finish';
}
};

drawFrame() {
const { animator, animators, frame } = this;
const childAnimator = animators[frame].childrenAnimation;
const { animator, animUnits, frame } = this;
const childAnimator = animUnits[frame].animators;
animator.shape.removeChildren();
childAnimator.map((d) => animator.shape.appendChild(d?.shape));
childAnimator.map((d) => {
animator.shape.appendChild(d?.shape);
});
animator.children = childAnimator;
}

Expand All @@ -77,6 +86,12 @@ class Timeline extends EE {
}
}

setPlaybackRate(speed) {
const { animator } = this;
this.speed = speed;
animator.setPlaybackRate(speed);
}

getPlayState() {
return this.playState;
}
Expand All @@ -95,22 +110,24 @@ class Timeline extends EE {

clear() {
this.animator = null;
this.animators = [];
this.animUnits = [];
this.playState = null;
this.endFrame = null;
}

goTo(time) {
const { frame, animators, playState } = this;
const { frame, animUnits, playState } = this;
let target;

const target = animators.findIndex((cur) => {
if (time - cur.totalTime < 0) {
return true;
for (let i = 0; i < animUnits.length; i++) {
const cur = animUnits[i];
target = i;
if (time > cur.time) {
time -= cur.time; // 计算剩余时间
} else {
time = time - cur?.totalTime;
return false;
break;
}
});
}

if (frame !== target) {
this.frame = target;
Expand Down
37 changes: 22 additions & 15 deletions packages/f-engine/src/player.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export interface PlayerProps {
/**
* 播放速率,默认为 1
*/
// speed?: number;
speed?: number;
children?: JSX.Element | null;

keyFrames?: Record<string, playerFrame>[];
Expand Down Expand Up @@ -63,49 +63,51 @@ class Player extends Component<PlayerProps> {
}

didMount(): void {
const { keyFrames, children, state, onend, goTo } = this.props;
const { keyFrames, children, state, onend, goTo, speed } = this.props;

this.playerFrames = keyFrames.reduce((array, cur) => {
const frames = generateFrameElement(cur, array[array.length - 1] || children);
array.push(frames);
return array;
}, []);

this.preNode = cloneNode(this._vNode);
const array = this.playerFrames.map((cur, index) => {
const keyFrame = keyFrames[index];
this.preNode = cloneNode(this.preNode || this._vNode);
const animUnits = getUpdateAnimation(this, cur, keyFrame) || {};

const childrenAnimation = getUpdateAnimation(this, cur, keyFrame);
this.preNode = cloneNode(this.preNode);
return {
childrenAnimation,
totalTime: 0,
};
return animUnits;
});

this.timeline = new Timeline({
animators: array,
animUnits: array,
playState: state,
root: this.context.canvas,
speed: speed,
time: goTo,
});

this.timeline.start();
onend && this.timeline.on('end', onend);
goTo && this.goTo(goTo);
}

willReceiveProps(nextProps: PlayerProps, _context?: IContext) {
const { props: lastProps, timeline } = this;
const { state, goTo: nextTime } = nextProps;
const { goTo } = lastProps;
const { state, goTo: nextTime, speed: newSpeed } = nextProps;
const { goTo: lastTime, speed: lastSpeed } = lastProps;

// state 更新
if (!isEqual(state, timeline.getPlayState())) {
timeline.updateState({ state });
}

if (!isEqual(nextTime, goTo)) {
this.goTo(nextTime);
if (!isEqual(nextTime, lastTime)) {
timeline.goTo(nextTime);
}

// 播放速度
if (!isEqual(newSpeed, lastSpeed)) {
timeline.setPlaybackRate(newSpeed);
}
}

Expand All @@ -114,6 +116,11 @@ class Player extends Component<PlayerProps> {
timeline.goTo(time);
}

setPlaybackRate(speed) {
const { timeline } = this;
timeline.setPlaybackRate(speed);
}

render() {
return null;
}
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 99b9eea

Please sign in to comment.