@@ -39,7 +39,7 @@ export interface RenderOutput {
3939
4040export interface TransitionInput < T extends Keyframe > extends RenderInput {
4141 newFrames : T [ ] ;
42- shapeGenerator :( keyframe : T ) => Point [ ] ,
42+ shapeGenerator : ( keyframe : T ) => Point [ ] ;
4343}
4444
4545export 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} ;
0 commit comments