Skip to content

Commit 3775e2d

Browse files
committed
change signature of state helpers to allow for multiple inputs and outputs
1 parent 1edcc24 commit 3775e2d

File tree

1 file changed

+57
-19
lines changed

1 file changed

+57
-19
lines changed

internal/animate/state.ts

Lines changed: 57 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,34 @@ export interface InternalKeyframe {
1616
timestamp: number;
1717
timingFunction: TimingFunc;
1818
initialPoints: Point[];
19-
preparedBeforePoints?: Point[];
20-
preparedAfterPoints?: Point[];
19+
}
20+
21+
export interface RenderCache {
22+
[frameId: string]: {
23+
preparedEndPoints?: Point[];
24+
preparedStartPoints?: Point[];
25+
};
26+
}
27+
28+
export interface RenderInput {
29+
keyframes: InternalKeyframe[];
30+
timestamp: number;
31+
cache: RenderCache;
32+
}
33+
34+
export interface RenderOutput {
35+
points: Point[];
36+
lastFrameId: string | null;
37+
cache: RenderCache;
38+
}
39+
40+
export interface TransitionInput extends RenderInput {
41+
newFrames: Keyframe[];
42+
}
43+
44+
export interface TransitionOutput {
45+
frames: InternalKeyframe[];
46+
cache: RenderCache;
2147
}
2248

2349
const genId = (): string => {
@@ -34,68 +60,80 @@ export const removeStaleFrames = (
3460
return keyframes.slice(staleCount - 1);
3561
};
3662

37-
// TODO cache prepared points? Ideally without modifying keyframes argument.
38-
export const renderFramesAt = (keyframes: InternalKeyframe[], timestamp: number): Point[] => {
39-
if (keyframes.length === 0) return [];
63+
export const renderFramesAt = (input: RenderInput): RenderOutput => {
64+
const {cache, keyframes} = input;
65+
66+
if (keyframes.length === 0) {
67+
return {cache, lastFrameId: null, points: []};
68+
}
4069

4170
// Animation freezes at the final shape if there are no more keyframes.
42-
if (keyframes.length === 1) return keyframes[0].initialPoints;
71+
if (keyframes.length === 1) {
72+
const first = keyframes[0];
73+
return {cache, lastFrameId: first.id, points: first.initialPoints};
74+
}
4375

4476
// Find the start/end keyframes according to the timestamp.
4577
let startKeyframe = keyframes[0];
4678
let endKeyframe = keyframes[1];
4779
for (let i = 2; i < keyframes.length; i++) {
48-
if (endKeyframe.timestamp < timestamp) break;
80+
if (endKeyframe.timestamp < input.timestamp) break;
4981
startKeyframe = keyframes[i - 1];
5082
endKeyframe = keyframes[i];
5183
}
5284

5385
// Use and cache prepared points for current interpolation.
54-
let preparedStartPoints: Point[] | undefined = startKeyframe.preparedAfterPoints;
55-
let preparedEndPoints: Point[] | undefined = endKeyframe.preparedBeforePoints;
86+
let preparedStartPoints: Point[] | undefined = cache[startKeyframe.id].preparedStartPoints;
87+
let preparedEndPoints: Point[] | undefined = cache[endKeyframe.id].preparedEndPoints;
5688
if (!preparedStartPoints || !preparedEndPoints) {
5789
[preparedStartPoints, preparedEndPoints] = prepare(
5890
startKeyframe.initialPoints,
5991
endKeyframe.initialPoints,
6092
{rawAngles: false, divideRatio: 1},
6193
);
94+
cache[startKeyframe.id].preparedStartPoints = preparedStartPoints;
95+
cache[endKeyframe.id].preparedEndPoints = preparedEndPoints;
6296
}
6397

6498
// Calculate progress between frames as a fraction.
6599
const progress =
66-
(timestamp - startKeyframe.timestamp) / (endKeyframe.timestamp - startKeyframe.timestamp);
100+
(input.timestamp - startKeyframe.timestamp) /
101+
(endKeyframe.timestamp - startKeyframe.timestamp);
67102

68103
// Apply timing function of end frame.
69104
const adjustedProgress = endKeyframe.timingFunction(progress);
70105

71106
// TODO use timing function.
72-
return interpolateBetween(adjustedProgress, preparedStartPoints, preparedEndPoints);
107+
return {
108+
cache,
109+
lastFrameId: startKeyframe.id,
110+
points: interpolateBetween(adjustedProgress, preparedStartPoints, preparedEndPoints),
111+
}
73112
};
74113

75114
// TODO generate internal frames. Delayed frames can just copy the previous one.
76115
// TODO store current blob when interrupts happen to use as source.
77116
// TODO don't remove any frames.
78-
export const transitionFrames = (
79-
currentFrames: InternalKeyframe[],
80-
newFrames: Keyframe[],
81-
timestamp: number,
82-
): InternalKeyframe[] => {
83-
let totalTime = 0;
117+
export const transitionFrames = (input: TransitionInput): TransitionOutput => {
118+
const {cache, timestamp, newFrames} = input;
84119

85120
// Add current state as initial frame.
121+
const currentState = renderFramesAt(input);
86122
let internalFrames: InternalKeyframe[] = [
87123
{
88124
id: genId(),
89-
initialPoints: renderFramesAt(currentFrames, timestamp),
125+
initialPoints: currentState.points,
90126
timestamp: timestamp,
91127
timingFunction: (p) => p,
92128
},
93129
];
130+
131+
let totalTime = 0;
94132
for (let i = 0; i < newFrames.length; i++) {
95133
const keyframe = newFrames[i];
96134
if (keyframe.delay && i > 0) {
97135
}
98136
}
99137

100-
return [];
138+
return {cache, frames: internalFrames};
101139
};

0 commit comments

Comments
 (0)