| <!DOCTYPE html> |
| <script src="../resources/testharness.js"></script> |
| <script src="../resources/testharnessreport.js"></script> |
| <style> |
| #box { |
| position: relative; |
| height: 100px; |
| width: 100px; |
| background-color: blue; |
| transition-delay: 0s; |
| transition-duration: 1s; |
| transition-property: width; |
| transition-timing-function: ease; |
| } |
| |
| #box.target, #box:hover { |
| width: 200px; |
| } |
| </style> |
| <div id="box"></div> |
| <script> |
| function assert_px_approx_equals(actual, expected, epsilon, description) { |
| var match = /^([\d.]+)px$/.exec(actual); |
| assert_not_equals(match, null); |
| assert_approx_equals(Number(match[1]), expected, epsilon, description); |
| } |
| |
| test(function() { |
| var box = document.getElementById('box'); |
| |
| assert_equals(getComputedStyle(box).width, '100px', 'initial width'); |
| |
| // Start the animation. |
| box.className = 'target'; |
| getComputedStyle(box).width; // Force the transition. |
| var animation = box.getAnimations()[0]; |
| animation.pause(); |
| |
| animation.currentTime = 0; |
| assert_equals(getComputedStyle(box).width, '100px', 'width at transition start'); |
| animation.currentTime = 400; |
| // cubicBezier(0.25, 0.1, 0.25, 1)(0.4) = 0.68254 |
| assert_px_approx_equals(getComputedStyle(box).width, 168.254, 0.01, 'width mid-forward'); |
| |
| // Reverse the animation. |
| box.className = ''; |
| getComputedStyle(box).width; // Force the transition. |
| animation = box.getAnimations()[0]; |
| animation.pause(); // The animation is replaced, so pause it again. |
| |
| animation.currentTime = 0; |
| assert_px_approx_equals(getComputedStyle(box).width, 168.254, 0.01, 'width after className'); |
| |
| // https://drafts.csswg.org/css-transitions-1/#reversing |
| // Reversing an animation. |
| // reverse shortening factor = output of timing function = 0.68254 |
| // start time = (now) |
| // end time = (now) + duration * shortening factor = (now) + 682.54ms |
| // start value = 168.254 |
| // end value = 100 |
| // progress = 200 / (end time - start time) = 0.2930 |
| // timing output = cubicBezier(0.25, 0.1, 0.25, 1)(0.2930) = 0.49939 |
| // Expected position = (end value - start value) * timing output + start value = 134.165. |
| animation.currentTime = 200; |
| assert_px_approx_equals(getComputedStyle(box).width, 134.165, 0.01, 'width mid-reverse'); |
| |
| // Go forward again. This tests the reversingAdjustedStartValue is set |
| // properly the first time it's reversed. |
| box.className = 'target'; |
| getComputedStyle(box).width; // Force the transition. |
| animation = box.getAnimations()[0]; |
| animation.pause(); // The animation is replaced, so pause it again. |
| |
| animation.currentTime = 0; |
| assert_px_approx_equals(getComputedStyle(box).width, 134.165, 0.01, 'width after second reverse'); |
| |
| // reverse shortening factor |
| // = (output of timing function) * (old shortening factor) + |
| // (1 - old shortening factor) = 0.65831 |
| // start time = (now) |
| // end time = (now) + duration * shortening factor = (now) + 658.31ms |
| // start value = 134.168 |
| // end value = 200 |
| // progress = 400 / (end time - start time) = 0.60761 |
| // timing output = cubicBezier(0.25, 0.1, 0.25, 1)(0.6076) = 0.89032 |
| // Expected position = (end value - start value) * timing output + start value = 192.779 |
| // Accumulated a bit of round off error at this stage of the calculation. Relaxing the tolerance. |
| animation.currentTime = 400; |
| assert_px_approx_equals(getComputedStyle(box).width, 192.779, 0.02, 'width mid-second-reverse'); |
| |
| animation.currentTime = 800; |
| assert_equals(getComputedStyle(box).width, '200px', 'width at end'); |
| |
| assert_equals(box.getAnimations().length, 0, 'animation ended'); |
| |
| }, "Check that reversing a transition (with ease timing function) mid-way adjusts the duration"); |
| </script> |