Skip to content

Commit a467af6

Browse files
committed
smooth replay logic
1 parent 53846e7 commit a467af6

4 files changed

Lines changed: 128 additions & 100 deletions

File tree

‎.eslintrc‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
"guard-for-in": 0,
1111
"func-names": 0,
1212
"class-methods-use-this": 0,
13-
"no-debugger": 0
13+
"no-debugger": 0,
14+
"no-fallthrough": 0
1415
}
1516
}

‎example/example.js‎

Lines changed: 91 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import Keyframes from '../src/keyframes';
22

33
const ball = new Keyframes(document.getElementById('ball'));
4+
const cbElem = document.getElementById('cb');
45

56
// Adding a new animation sequences (keyframe)
67
Keyframes.define([{
@@ -36,111 +37,117 @@ window.resume = () => {
3637

3738
window.reset = () => {
3839
// reset keyframe animation
40+
cbElem.innerHTML = 0;
3941
ball.reset();
4042
};
4143

4244
// example callback function
43-
const cbElem = document.getElementById('cb');
4445
function increment() {
4546
cbElem.innerHTML = parseInt(cbElem.innerHTML, 10) + 1;
4647
}
4748

4849

4950
window.play = (animation) => {
50-
ball.reset(() => {
51-
switch (animation) {
52-
case 'normal':
51+
switch (animation) {
52+
case 'normal':
5353

5454
// move with easing
55-
ball.play({
56-
name: 'ball-move',
57-
duration: '3s',
58-
timingFunction: 'ease',
59-
iterationCount: 'infinite',
60-
direction: 'normal',
61-
fillMode: 'forwards',
62-
complete: increment,
63-
});
64-
65-
break;
66-
case 'spin':
55+
ball.play({
56+
name: 'ball-move',
57+
duration: '3s',
58+
timingFunction: 'ease',
59+
iterationCount: 'infinite',
60+
direction: 'normal',
61+
fillMode: 'forwards',
62+
}, {
63+
onIteration: increment,
64+
onEnd: increment,
65+
});
66+
67+
break;
68+
case 'spin':
6769

6870
// run spin keyframes using the shorthand method.
69-
ball.play('ball-spin 500ms linear 0s 3 normal forwards', increment);
71+
ball.play('ball-spin 500ms linear 0s 3 normal forwards', {
72+
onIteration: increment,
73+
onEnd: increment,
74+
});
7075

71-
break;
72-
case 'linear':
76+
break;
77+
case 'linear':
7378

7479
// move with linear timing
75-
ball.play({
76-
name: 'ball-move',
77-
duration: '3s',
78-
timingFunction: 'linear',
79-
iterationCount: 'infinite',
80-
complete: increment,
81-
});
82-
83-
break;
84-
case 'delay':
80+
ball.play({
81+
name: 'ball-move',
82+
duration: '3s',
83+
timingFunction: 'linear',
84+
iterationCount: 'infinite',
85+
}, {
86+
onIteration: increment,
87+
onEnd: increment,
88+
});
89+
90+
break;
91+
case 'delay':
8592

8693
// set a 2 second delay before starting
87-
ball.play({
88-
name: 'ball-move',
89-
duration: '3s',
90-
timingFunction: 'linear',
91-
delay: '3s',
92-
iterationCount: 'infinite',
93-
complete: increment,
94-
});
95-
96-
break;
97-
case 'once':
94+
ball.play({
95+
name: 'ball-move',
96+
duration: '3s',
97+
timingFunction: 'linear',
98+
delay: '3s',
99+
iterationCount: 'infinite',
100+
}, {
101+
onIteration: increment,
102+
onEnd: increment,
103+
});
104+
105+
break;
106+
case 'once':
98107

99108
// only play the animation once
100-
ball.play({
101-
name: 'ball-move',
102-
duration: '3s',
103-
timingFunction: 'ease',
104-
complete: increment,
105-
});
106-
107-
break;
108-
case 'multi':
109+
ball.play({
110+
name: 'ball-move',
111+
duration: '3s',
112+
timingFunction: 'ease',
113+
}, {
114+
onIteration: increment,
115+
onEnd: increment,
116+
});
117+
118+
break;
119+
case 'multi':
109120
// play multiple animations
110-
ball.play(
111-
[
112-
'ball-spin 500ms linear 0s 6',
113-
{
114-
name: 'ball-move',
115-
duration: '3s',
116-
timingFunction: 'ease',
117-
iterationCount: 1,
118-
},
119-
],
120-
increment,
121-
);
122-
break;
123-
default:
124-
125-
case 'chained':
126-
// play chained animations using callbacks
127-
ball.play({
128-
name: 'ball-spin',
129-
duration: '1s',
130-
iterationCount: 1,
131-
complete: () => {
132-
increment();
133-
setTimeout(() => ball.play({
134-
name: 'ball-move',
135-
duration: '1s',
136-
iterationCount: 1,
137-
complete: () => {
138-
ball.reset();
139-
increment();
140-
},
141-
}), 1000);
121+
ball.play(
122+
[
123+
'ball-spin 500ms linear 0s 6',
124+
{
125+
name: 'ball-move',
126+
duration: '3s',
127+
timingFunction: 'ease',
128+
iterationCount: 1,
142129
},
143-
});
144-
}
145-
});
130+
],
131+
{
132+
onIteration: increment,
133+
},
134+
);
135+
break;
136+
default:
137+
138+
case 'chained':
139+
// play chained animations using callbacks
140+
ball.chain([{
141+
name: 'ball-spin',
142+
duration: '1s',
143+
iterationCount: 1,
144+
}, {
145+
name: 'ball-move',
146+
duration: '1s',
147+
iterationCount: 1,
148+
}], {
149+
onEnd: increment,
150+
});
151+
break;
152+
}
146153
};

‎src/keyframes.js‎

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,10 @@ class Keyframes {
3131
}
3232

3333
play(animationOptions, callbacks) {
34-
if (this.elem.style.animationName === animationOptions.name) {
35-
this.reset(() => this.play(animationOptions, callbacks));
34+
if (this.elem.style.animationName === this.getAnimationName(animationOptions)) {
35+
requestAnimationFrame(() => {
36+
this.reset().then(() => this.play(animationOptions, callbacks));
37+
});
3638
return this;
3739
}
3840

@@ -116,11 +118,13 @@ class Keyframes {
116118

117119
resetQueue() {
118120
return new Promise((accept, reject) => {
119-
this.removeEvents();
120-
this.queueStore = [];
121-
this.reset().then(() => {
122-
accept();
123-
}).catch(reject);
121+
requestAnimationFrame(() => {
122+
this.removeEvents();
123+
this.queueStore = [];
124+
this.reset().then(() => {
125+
accept();
126+
}).catch(reject);
127+
});
124128
});
125129
}
126130

@@ -131,6 +135,20 @@ class Keyframes {
131135
return this;
132136
}
133137

138+
getAnimationName(frameOptions) {
139+
switch (frameOptions.constructor) {
140+
case Array: {
141+
return frameOptions.map(this.getAnimationName).join(', ');
142+
}
143+
case String: {
144+
return frameOptions.split(' ')[0];
145+
}
146+
default: {
147+
return frameOptions.name;
148+
}
149+
}
150+
}
151+
134152
static playCSS(frameOptions) {
135153
const animObjToStr = function (obj) {
136154
const newObj = Object.assign({}, {
@@ -156,12 +174,12 @@ class Keyframes {
156174
if (frameOptions.constructor === Array) {
157175
const frameOptionsStrings = [];
158176
for (let i = 0; i < frameOptions.length; i += 1) {
159-
frameOptionsStrings.push(typeof frameOptions[i] === 'string' ?
177+
frameOptionsStrings.push(frameOptions[i].constructor === String ?
160178
frameOptions[i] :
161179
animObjToStr(frameOptions[i]));
162180
}
163181
return frameOptionsStrings.join(', ');
164-
} else if (typeof frameOptions === 'string') {
182+
} else if (frameOptions.constructor === String) {
165183
return frameOptions;
166184
}
167185

‎test/play.js‎

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ describe('Play', () => {
5757
});
5858
});
5959
});
60-
assert.equal(count, 5);
60+
assert.equal(count, 6);
6161
});
6262
});
6363

@@ -79,12 +79,14 @@ describe('Play', () => {
7979
it('Should be able to add queue items on the fly', async () => {
8080
const animation = await browser.evaluate(async () => {
8181
return new Promise((resolve, reject) => {
82-
kf.queue(['ball-roll 0.1s'], {
83-
onEnd: () => {
84-
resolve(window.elem.style.animation);
85-
}
82+
kf.resetQueue().then(() => {
83+
kf.queue(['ball-roll 0.1s'], {
84+
onEnd: () => {
85+
resolve(window.elem.style.animation);
86+
}
87+
});
88+
kf.queue('ball-roll2 0.1s');
8689
});
87-
kf.queue('ball-roll2 0.1s');
8890
});
8991
});
9092
assert.equal(animation, 'ball-roll2 0.1s');

0 commit comments

Comments
 (0)