Skip to content

Commit 24926f7

Browse files
authored
Merge pull request #482 from ewilligers/simple-iteration-progress-works
Simple iteration progress works
2 parents c25d407 + b85f9a3 commit 24926f7

8 files changed

+81
-176
lines changed

src/effect-callback.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
var callback = function() {
3232
var t = callback._animation ? callback._animation.currentTime : null;
3333
if (t !== null) {
34-
t = shared.calculateTimeFraction(shared.calculateActiveDuration(timing), t, timing);
34+
t = shared.calculateIterationProgress(shared.calculateActiveDuration(timing), t, timing);
3535
if (isNaN(t))
3636
t = null;
3737
}

src/group-constructors.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -168,13 +168,13 @@
168168

169169
// If the group has a negative playback rate and is not fill backwards/both, then it should go
170170
// out of effect when it reaches the start of its active interval (tf == 0). If it is fill
171-
// backwards/both then it should stay in effect. calculateTimeFraction will return 0 in the
171+
// backwards/both then it should stay in effect. calculateIterationProgress will return 0 in the
172172
// backwards-filling case, and null otherwise.
173173
if (tf == 0 && animation.playbackRate < 0) {
174174
if (!timing) {
175175
timing = shared.normalizeTimingInput(animation.effect.timing);
176176
}
177-
tf = shared.calculateTimeFraction(shared.calculateActiveDuration(timing), -1, timing);
177+
tf = shared.calculateIterationProgress(shared.calculateActiveDuration(timing), -1, timing);
178178
if (isNaN(tf) || tf == null) {
179179
animation._forEachChild(function(child) {
180180
child.currentTime = -1;

src/keyframe-effect.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
var timeFraction = 0;
1919
var activeDuration = shared.calculateActiveDuration(timing);
2020
var effectTime = function(localTime) {
21-
return shared.calculateTimeFraction(activeDuration, localTime, timing);
21+
return shared.calculateIterationProgress(activeDuration, localTime, timing);
2222
};
2323
effectTime._totalDuration = timing.delay + activeDuration + timing.endDelay;
2424
return effectTime;

src/timing-utilities.js

+65-35
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,10 @@
264264
}
265265

266266
function repeatedDuration(timing) {
267+
// https://w3c.github.io/web-animations/#calculating-the-active-duration
268+
if (timing.duration === 0 || timing.iterations === 0) {
269+
return 0;
270+
}
267271
return timing.duration * timing.iterations;
268272
}
269273

@@ -273,19 +277,24 @@
273277
var PhaseActive = 3;
274278

275279
function calculatePhase(activeDuration, localTime, timing) {
280+
// https://w3c.github.io/web-animations/#animation-effect-phases-and-states
276281
if (localTime == null) {
277282
return PhaseNone;
278283
}
279-
if (localTime < timing.delay) {
284+
285+
var endTime = timing.delay + activeDuration + timing.endDelay;
286+
if (localTime < Math.min(timing.delay, endTime)) {
280287
return PhaseBefore;
281288
}
282-
if (localTime >= timing.delay + activeDuration) {
289+
if (localTime >= Math.min(timing.delay + activeDuration, endTime)) {
283290
return PhaseAfter;
284291
}
292+
285293
return PhaseActive;
286294
}
287295

288296
function calculateActiveTime(activeDuration, fillMode, localTime, phase, delay) {
297+
// https://w3c.github.io/web-animations/#calculating-the-active-time
289298
switch (phase) {
290299
case PhaseBefore:
291300
if (fillMode == 'backwards' || fillMode == 'both')
@@ -302,56 +311,82 @@
302311
}
303312
}
304313

305-
function calculateScaledActiveTime(activeDuration, activeTime, startOffset, timing) {
306-
return (timing.playbackRate < 0 ? activeTime - activeDuration : activeTime) * timing.playbackRate + startOffset;
314+
function calculateOverallProgress(iterationDuration, phase, iterations, activeTime, iterationStart) {
315+
// https://w3c.github.io/web-animations/#calculating-the-overall-progress
316+
var overallProgress = iterationStart;
317+
if (iterationDuration === 0) {
318+
if (phase !== PhaseBefore) {
319+
overallProgress += iterations;
320+
}
321+
} else {
322+
overallProgress += activeTime / iterationDuration;
323+
}
324+
return overallProgress;
307325
}
308326

309-
function calculateIterationTime(iterationDuration, repeatedDuration, scaledActiveTime, startOffset, timing) {
310-
if (scaledActiveTime === Infinity || scaledActiveTime === -Infinity || (scaledActiveTime - startOffset == repeatedDuration && timing.iterations && ((timing.iterations + timing.iterationStart) % 1 == 0))) {
311-
return iterationDuration;
312-
}
327+
function calculateSimpleIterationProgress(overallProgress, iterationStart, phase, iterations, activeTime, iterationDuration) {
328+
// https://w3c.github.io/web-animations/#calculating-the-simple-iteration-progress
313329

314-
return scaledActiveTime % iterationDuration;
330+
var simpleIterationProgress = (overallProgress === Infinity) ? iterationStart % 1 : overallProgress % 1;
331+
if (simpleIterationProgress === 0 && phase === PhaseAfter && iterations !== 0 &&
332+
(activeTime !== 0 || iterationDuration === 0)) {
333+
simpleIterationProgress = 1;
334+
}
335+
return simpleIterationProgress;
315336
}
316337

317-
function calculateCurrentIteration(iterationDuration, iterationTime, scaledActiveTime, timing) {
318-
if (scaledActiveTime === 0) {
319-
return 0;
338+
function calculateCurrentIteration(phase, iterations, simpleIterationProgress, overallProgress) {
339+
// https://w3c.github.io/web-animations/#calculating-the-current-iteration
340+
if (phase === PhaseAfter && iterations === Infinity) {
341+
return Infinity;
320342
}
321-
if (iterationTime == iterationDuration) {
322-
return timing.iterationStart + timing.iterations - 1;
343+
if (simpleIterationProgress === 1) {
344+
return Math.floor(overallProgress) - 1;
323345
}
324-
return Math.floor(scaledActiveTime / iterationDuration);
346+
return Math.floor(overallProgress);
325347
}
326348

327-
function calculateTransformedTime(currentIteration, iterationDuration, iterationTime, timing) {
328-
var currentIterationIsOdd = currentIteration % 2 >= 1;
329-
var currentDirectionIsForwards = timing.direction == 'normal' || timing.direction == (currentIterationIsOdd ? 'alternate-reverse' : 'alternate');
330-
var directedTime = currentDirectionIsForwards ? iterationTime : iterationDuration - iterationTime;
331-
var timeFraction = directedTime / iterationDuration;
332-
return iterationDuration * timing._easingFunction(timeFraction);
349+
function calculateDirectedProgress(playbackDirection, currentIteration, simpleIterationProgress) {
350+
// https://w3c.github.io/web-animations/#calculating-the-directed-progress
351+
var currentDirection = playbackDirection;
352+
if (playbackDirection !== 'normal' && playbackDirection !== 'reverse') {
353+
var d = currentIteration;
354+
if (playbackDirection === 'alternate-reverse') {
355+
d += 1;
356+
}
357+
currentDirection = 'normal';
358+
if (d !== Infinity && d % 2 !== 0) {
359+
currentDirection = 'reverse';
360+
}
361+
}
362+
if (currentDirection === 'normal') {
363+
return simpleIterationProgress;
364+
}
365+
return 1 - simpleIterationProgress;
333366
}
334367

335-
function calculateTimeFraction(activeDuration, localTime, timing) {
368+
function calculateIterationProgress(activeDuration, localTime, timing) {
336369
var phase = calculatePhase(activeDuration, localTime, timing);
337370
var activeTime = calculateActiveTime(activeDuration, timing.fill, localTime, phase, timing.delay);
338371
if (activeTime === null)
339372
return null;
340-
if (activeDuration === 0)
341-
return phase === PhaseBefore ? 0 : 1;
342-
var startOffset = timing.iterationStart * timing.duration;
343-
var scaledActiveTime = calculateScaledActiveTime(activeDuration, activeTime, startOffset, timing);
344-
var iterationTime = calculateIterationTime(timing.duration, repeatedDuration(timing), scaledActiveTime, startOffset, timing);
345-
var currentIteration = calculateCurrentIteration(timing.duration, iterationTime, scaledActiveTime, timing);
346-
return calculateTransformedTime(currentIteration, timing.duration, iterationTime, timing) / timing.duration;
373+
374+
var overallProgress = calculateOverallProgress(timing.duration, phase, timing.iterations, activeTime, timing.iterationStart);
375+
var simpleIterationProgress = calculateSimpleIterationProgress(overallProgress, timing.iterationStart, phase, timing.iterations, activeTime, timing.duration);
376+
var currentIteration = calculateCurrentIteration(phase, timing.iterations, simpleIterationProgress, overallProgress);
377+
var directedProgress = calculateDirectedProgress(timing.direction, currentIteration, simpleIterationProgress);
378+
379+
// https://w3c.github.io/web-animations/#calculating-the-transformed-progress
380+
// https://w3c.github.io/web-animations/#calculating-the-iteration-progress
381+
return timing._easingFunction(directedProgress);
347382
}
348383

349384
shared.cloneTimingInput = cloneTimingInput;
350385
shared.makeTiming = makeTiming;
351386
shared.numericTimingToObject = numericTimingToObject;
352387
shared.normalizeTimingInput = normalizeTimingInput;
353388
shared.calculateActiveDuration = calculateActiveDuration;
354-
shared.calculateTimeFraction = calculateTimeFraction;
389+
shared.calculateIterationProgress = calculateIterationProgress;
355390
shared.calculatePhase = calculatePhase;
356391
shared.normalizeEasing = normalizeEasing;
357392
shared.parseEasingFunction = parseEasingFunction;
@@ -366,11 +401,6 @@
366401
testing.PhaseBefore = PhaseBefore;
367402
testing.PhaseActive = PhaseActive;
368403
testing.PhaseAfter = PhaseAfter;
369-
testing.calculateActiveTime = calculateActiveTime;
370-
testing.calculateScaledActiveTime = calculateScaledActiveTime;
371-
testing.calculateIterationTime = calculateIterationTime;
372-
testing.calculateCurrentIteration = calculateCurrentIteration;
373-
testing.calculateTransformedTime = calculateTransformedTime;
374404
}
375405

376406
})(webAnimationsShared, webAnimationsTesting);

src/web-animations-next-animation.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,7 @@
368368
var timing = this.effect._timing;
369369
var t = this.currentTime;
370370
if (t !== null)
371-
t = shared.calculateTimeFraction(shared.calculateActiveDuration(timing), t, timing);
371+
t = shared.calculateIterationProgress(shared.calculateActiveDuration(timing), t, timing);
372372
if (t == null || isNaN(t))
373373
this._removeChildAnimations();
374374
},

test/js/group-animation.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1093,7 +1093,7 @@ suite('group-animation', function() {
10931093
tick(102);
10941094
assert.equal(getComputedStyle(this.target).marginLeft, '2px');
10951095
tick(103);
1096-
assert.equal(getComputedStyle(this.target).marginLeft, '3px');
1096+
assert.equal(getComputedStyle(this.target).marginLeft, '0px');
10971097
tick(104);
10981098
});
10991099

test/js/timing-utilities.js

+10-55
Original file line numberDiff line numberDiff line change
@@ -56,72 +56,27 @@ suite('timing-utilities', function() {
5656
assert.equal(f(0.1), 0.1);
5757
assert.equal(f(0.25), 0.2);
5858
});
59-
test('calculating phase', function() {
60-
// calculatePhase(activeDuration, localTime, timing);
61-
assert.equal(calculatePhase(1000, 100, {delay: 0}), PhaseActive);
62-
assert.equal(calculatePhase(1000, 100, {delay: 200}), PhaseBefore);
63-
assert.equal(calculatePhase(1000, 2000, {delay: 200}), PhaseAfter);
64-
assert.equal(calculatePhase(1000, null, {delay: 200}), PhaseNone);
65-
});
66-
test('calculating active time', function() {
67-
// calculateActiveTime(activeDuration, fillMode, localTime, phase, delay);
68-
assert.equal(calculateActiveTime(1000, 'forwards', 100, PhaseActive, 0), 100);
69-
assert.equal(calculateActiveTime(1000, 'forwards', 100, PhaseBefore, 200), null);
70-
assert.equal(calculateActiveTime(1000, 'both', 100, PhaseBefore, 200), 0);
71-
assert.equal(calculateActiveTime(1000, 'forwards', 500, PhaseActive, 200), 300);
72-
assert.equal(calculateActiveTime(1000, 'forwards', 1100, PhaseAfter, 200), 1000);
73-
assert.equal(calculateActiveTime(1000, 'none', 1100, PhaseAfter, 200), null);
74-
assert.equal(calculateActiveTime(Infinity, 'both', 5000000, PhaseActive, 2000000), 3000000);
75-
assert.equal(calculateActiveTime(Infinity, 'both', 50000, PhaseBefore, 2000000), 0);
76-
});
77-
test('calculating scaled active time', function() {
78-
// calculateScaledActiveTime(activeDuration, activeTime, startOffset, timingInput);
79-
assert.equal(calculateScaledActiveTime(1000, 200, 300, {playbackRate: 1.5}), 600);
80-
assert.equal(calculateScaledActiveTime(1000, 200, 300, {playbackRate: -4}), 3500);
81-
assert.equal(calculateScaledActiveTime(Infinity, 400, 200, {playbackRate: 1}), 600);
82-
assert.equal(calculateScaledActiveTime(Infinity, 400, 200, {playbackRate: -4}), Infinity);
83-
});
84-
test('calculating iteration time', function() {
85-
// calculateIterationTime(iterationDuration, repeatedDuration, scaledActiveTime, startOffset, timingInput);
86-
assert.equal(calculateIterationTime(500, 5000, 600, 100, {iterations: 10, iterationStart: 0}), 100);
87-
assert.equal(calculateIterationTime(500, 5000, Infinity, 100, {iterations: 10, iterationStart: 0}), 500);
88-
assert.equal(calculateIterationTime(500, 5000, 5100, 100, {iterations: 3.2, iterationStart: 0.8}), 500);
89-
});
90-
test('calculating current iteration', function() {
91-
// calculateCurrentIteration(iterationDuration, iterationTime, scaledActiveTime, timingInput);
92-
assert.equal(calculateCurrentIteration(1000, 400, 4400, {iterations: 50, iterationStart: 0.8}), 4);
93-
assert.equal(calculateCurrentIteration(1000, 1000, 4400, {iterations: 50.2, iterationStart: 0.8}), 50);
94-
});
95-
test('calculating transformed time', function() {
96-
// calculateTransformedTime(currentIteration, iterationDuration, iterationTime, timingInput);
97-
assert.equal(calculateTransformedTime(4, 1000, 200, {_easingFunction: function(x) { return x; }, direction: 'normal'}), 200);
98-
assert.equal(calculateTransformedTime(4, 1000, 200, {_easingFunction: function(x) { return x; }, direction: 'reverse'}), 800);
99-
assert.closeTo(calculateTransformedTime(4, 1000, 200, {_easingFunction: function(x) { return x * x; }, direction: 'reverse'}), 640, 0.0001);
100-
assert.closeTo(calculateTransformedTime(4, 1000, 600, {_easingFunction: function(x) { return x * x; }, direction: 'alternate'}), 360, 0.0001);
101-
assert.closeTo(calculateTransformedTime(3, 1000, 600, {_easingFunction: function(x) { return x * x; }, direction: 'alternate'}), 160, 0.0001);
102-
assert.closeTo(calculateTransformedTime(4, 1000, 600, {_easingFunction: function(x) { return x * x; }, direction: 'alternate-reverse'}), 160, 0.0001);
103-
assert.closeTo(calculateTransformedTime(3, 1000, 600, {_easingFunction: function(x) { return x * x; }, direction: 'alternate-reverse'}), 360, 0.0001);
104-
});
10559
test('EffectTime', function() {
10660
var timing = normalizeTimingInput({duration: 1000, iterations: 4, iterationStart: 0.5, easing: 'linear', direction: 'alternate', delay: 100, fill: 'forwards'});
10761
var timing2 = normalizeTimingInput({duration: 1000, iterations: 4, iterationStart: 0.5, easing: 'ease', direction: 'alternate', delay: 100, fill: 'forwards'});
10862
var effectTF = effectTime(timing);
10963
var effectTF2 = effectTime(timing2);
64+
var epsilon = 0.005;
11065
assert.equal(effectTF(0), null);
11166
assert.equal(effectTF(100), 0.5);
112-
assert.closeTo(effectTF2(100), 0.8, 0.005);
67+
assert.closeTo(effectTF2(100), 0.8, epsilon);
11368
assert.equal(effectTF(600), 1);
114-
assert.closeTo(effectTF2(600), 1, 0.005);
115-
assert.equal(effectTF(700), 0.9);
116-
assert.closeTo(effectTF2(700), 0.99, 0.005);
69+
assert.closeTo(effectTF2(600), 1, epsilon);
70+
assert.closeTo(effectTF(700), 0.9, epsilon);
71+
assert.closeTo(effectTF2(700), 0.99, epsilon);
11772
assert.equal(effectTF(1600), 0);
118-
assert.closeTo(effectTF2(1600), 0, 0.005);
119-
assert.equal(effectTF(4000), 0.4);
120-
assert.closeTo(effectTF2(4000), 0.68, 0.005);
73+
assert.closeTo(effectTF2(1600), 0, epsilon);
74+
assert.closeTo(effectTF(4000), 0.4, epsilon);
75+
assert.closeTo(effectTF2(4000), 0.68, epsilon);
12176
assert.equal(effectTF(4100), 0.5);
122-
assert.closeTo(effectTF2(4100), 0.8, 0.005);
77+
assert.closeTo(effectTF2(4100), 0.8, epsilon);
12378
assert.equal(effectTF(6000), 0.5);
124-
assert.closeTo(effectTF2(6000), 0.8, 0.005);
79+
assert.closeTo(effectTF2(6000), 0.8, epsilon);
12580
});
12681
test('TypeErrors', function() {
12782
var timing = normalizeTimingInput({

0 commit comments

Comments
 (0)