Skip to content

Commit 36d2cd5

Browse files
committed
implement remainder of transition util
1 parent 08ff8bb commit 36d2cd5

File tree

2 files changed

+50
-28
lines changed

2 files changed

+50
-28
lines changed

internal/animate/state.ts

Lines changed: 47 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export interface RenderOutput {
3939

4040
export interface TransitionInput<T extends Keyframe> extends RenderInput {
4141
newFrames: T[];
42-
shapeGenerator:(keyframe: T) => Point[],
42+
shapeGenerator: (keyframe: T) => Point[];
4343
}
4444

4545
export interface TransitionOutput {
@@ -73,7 +73,8 @@ export const renderFramesAt = (input: RenderInput): RenderOutput => {
7373
}
7474

7575
// Use and cache prepared points for current interpolation.
76-
let preparedStartPoints: Point[] | undefined = renderCache[startKeyframe.id].preparedStartPoints;
76+
let preparedStartPoints: Point[] | undefined =
77+
renderCache[startKeyframe.id].preparedStartPoints;
7778
let preparedEndPoints: Point[] | undefined = renderCache[endKeyframe.id].preparedEndPoints;
7879
if (!preparedStartPoints || !preparedEndPoints) {
7980
[preparedStartPoints, preparedEndPoints] = prepare(
@@ -100,37 +101,58 @@ export const renderFramesAt = (input: RenderInput): RenderOutput => {
100101
};
101102
};
102103

103-
// TODO generate internal frames. Delayed frames can just copy the previous one.
104-
// TODO store current shape when interrupts happen to use as source.
105104
// TODO defend against "bad" keyframes like negative timing.
106-
// TODO copy keyframes as soon as possible to make sure they aren't modified afterwards.
107-
export const transitionFrames = <T extends Keyframe>(input: TransitionInput<T>): TransitionOutput => {
108-
const {timestamp, newFrames} = input;
105+
export const transitionFrames = <T extends Keyframe>(
106+
input: TransitionInput<T>,
107+
): TransitionOutput => {
108+
// Erase all old frames.
109+
const newInternalFrames: InternalKeyframe[] = [];
109110

110-
// Wipe animation when given no keyframes.
111+
// Reset animation when given no keyframes.
111112
if (input.newFrames.length === 0) {
112-
return {newFrames: []};
113+
return {newFrames: newInternalFrames};
113114
}
114115

115116
// Add current state as initial frame.
116117
const currentState = renderFramesAt(input);
117-
let internalFrames: InternalKeyframe[] = [
118-
{
119-
id: genId(),
120-
initialPoints: currentState.points,
121-
timestamp: timestamp,
122-
timingFunction: (p) => p,
123-
transitionSourceFrameIndex: -1,
124-
isSynthetic: true,
125-
},
126-
];
127-
128-
let totalTime = 0;
129-
for (let i = 0; i < newFrames.length; i++) {
130-
const keyframe = newFrames[i];
131-
if (keyframe.delay && i > 0) {
118+
newInternalFrames.push({
119+
id: genId(),
120+
initialPoints: currentState.points,
121+
timestamp: input.timestamp,
122+
timingFunction: timingFunctions.linear,
123+
transitionSourceFrameIndex: -1,
124+
isSynthetic: true,
125+
});
126+
127+
// Generate and add new frames.
128+
let totalOffset = 0;
129+
for (let i = 0; i < input.newFrames.length; i++) {
130+
const keyframe = input.newFrames[i];
131+
132+
// Copy previous frame when current one has a delay.
133+
if (keyframe.delay) {
134+
totalOffset += keyframe.delay;
135+
const prevFrame = newInternalFrames[newInternalFrames.length - 1];
136+
newInternalFrames.push({
137+
id: genId(),
138+
initialPoints: prevFrame.initialPoints,
139+
timestamp: input.timestamp + totalOffset,
140+
timingFunction: timingFunctions.linear,
141+
transitionSourceFrameIndex: i - 1,
142+
isSynthetic: true,
143+
});
132144
}
145+
146+
totalOffset += keyframe.duration;
147+
newInternalFrames.push({
148+
id: genId(),
149+
initialPoints: input.shapeGenerator(keyframe),
150+
timestamp: input.timestamp + totalOffset,
151+
timingFunction: timingFunctions[keyframe.timingFunction || "linear"],
152+
transitionSourceFrameIndex: i,
153+
isSynthetic: false,
154+
});
133155
}
134156

135-
return {newFrames: internalFrames};
157+
return {newFrames: newInternalFrames};
136158
};

public/animate.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ const canvasBlobGenerator = (keyframe: CanvasKeyframe): Point[] => {
3838
curr.y += keyframe?.canvasOptions?.offsetY || 0;
3939
return curr;
4040
});
41-
}
41+
};
4242

4343
export const canvasPath = (): CanvasAnimation => {
4444
let internalFrames: InternalKeyframe[] = [];
@@ -67,7 +67,7 @@ export const canvasPath = (): CanvasAnimation => {
6767
const transition: CanvasAnimation["transition"] = (...keyframes) => {
6868
const transitionOutput = transitionFrames<CanvasKeyframe>({
6969
renderCache: renderCache,
70-
timestamp: Date.now(),
70+
timestamp: Date.now(),
7171
currentFrames: internalFrames,
7272
newFrames: keyframes,
7373
shapeGenerator: canvasBlobGenerator,
@@ -80,7 +80,7 @@ export const canvasPath = (): CanvasAnimation => {
8080

8181
// Populate callback store using returned frame ids.
8282
for (const newFrame of internalFrames) {
83-
if (newFrame.transitionSourceFrameIndex === null) continue;
83+
if (newFrame.isSynthetic) continue;
8484
const {callback} = keyframes[newFrame.transitionSourceFrameIndex];
8585
if (callback) callbackStore[newFrame.id] = callback;
8686
}

0 commit comments

Comments
 (0)