| <!DOCTYPE html> |
| <meta charset=utf-8> |
| <title>Test element-based scroll offset for scroll timeline.</title> |
| <script src="/resources/testharness.js"></script> |
| <script src="/resources/testharnessreport.js"></script> |
| <script src="/web-animations/testcommon.js"></script> |
| <script src="testcommon.js"></script> |
| |
| <style> |
| .scroller { |
| overflow: auto; |
| height: 500px; |
| width: 500px; |
| will-change: transform; |
| } |
| |
| .contents { |
| height: 2000px; |
| width: 2000px; |
| position: relative; |
| } |
| |
| .vertical #start, .vertical #end { |
| background: blue; |
| border-top: 5px solid pink; |
| box-sizing: border-box; |
| width: 100%; |
| height: 50px; |
| } |
| |
| .vertical #start { |
| position: absolute; |
| top: 50px; |
| } |
| |
| .vertical #end { |
| position: absolute; |
| top: 1050px; |
| } |
| |
| .horizontal #start, .horizontal #end { |
| background: blue; |
| border-left:5px solid pink; |
| box-sizing: border-box; |
| height: 100%; |
| width: 50px; |
| } |
| |
| .horizontal #start { |
| position: absolute; |
| left: 50px; |
| } |
| |
| .horizontal #end { |
| position: absolute; |
| left: 1050px; |
| } |
| </style> |
| <div id="log"></div> |
| <script> |
| 'use strict'; |
| |
| async function createScrollAnimationTest(description, config) { |
| promise_test(async t => { |
| const scroller = createScrollerWithStartAndEnd(t, config.orientation); |
| t.add_cleanup(() => scroller.remove()); |
| |
| const start = scroller.querySelector("#start"); |
| const end = scroller.querySelector("#end"); |
| |
| // Force layout to ensure the scroll timeline gets the correct scroll |
| // range. |
| start.offsetHeight; |
| |
| const timeline = createScrollTimeline(t, { |
| source: scroller, |
| orientation: config.orientation, |
| fill: 'both', |
| scrollOffsets: |
| [{target: start, ...config.start}, {target: end, ...config.end }] |
| }); |
| |
| // Wait for new animation frame which allows the timeline to compute new |
| // current time. |
| await waitForNextFrame(); |
| |
| const animation = createScrollLinkedAnimation(t, timeline); |
| const scrollRange = (config.orientation == 'vertical') |
| ? end.offsetTop - start.offsetTop |
| : end.offsetLeft - start.offsetLeft; |
| |
| // Verify initial start and current times in Idle state. |
| assert_equals(animation.currentTime, null, |
| "The current time is null in Idle state."); |
| assert_equals(animation.startTime, null, |
| "The start time is null in Idle state."); |
| |
| animation.play(); |
| assert_true(animation.pending, "Animation is in pending state."); |
| // Verify initial start and current times in Pending state. |
| assert_percents_equal(animation.currentTime, 0, |
| "The current time is zero in Pending state."); |
| assert_percents_equal(animation.startTime, 0, |
| "The start time is zero in Pending state."); |
| |
| await animation.ready; |
| // Verify initial start and current times in Playing state. |
| assert_percents_equal(animation.currentTime, 0, |
| "The current time is zero in Playing state."); |
| assert_percents_equal(animation.startTime, 0, |
| "The start time is zero in Playing state."); |
| |
| // Now do some scrolling and make sure that the Animation current time is |
| // correct. |
| if (config.orientation == 'vertical') { |
| scroller.scrollTo({top: config.scrollTo}); |
| assert_equals(scroller.scrollTop, config.scrollTo); |
| } else { |
| scroller.scrollTo({left: config.scrollTo}); |
| assert_equals(scroller.scrollLeft, config.scrollTo); |
| } |
| |
| await waitForNextFrame(); |
| assert_percents_approx_equal( |
| animation.timeline.currentTime, |
| config.expectedCurrentTime, |
| scrollRange, |
| "The timeline current time corresponds to the scroll position of " + |
| "the scroller."); |
| assert_percents_approx_equal( |
| animation.currentTime, |
| config.expectedCurrentTime, |
| scrollRange, |
| "The animation current time corresponds to the scroll position of " + |
| "the scroller."); |
| assert_percents_approx_equal( |
| animation.effect.getComputedTiming().localTime, |
| config.expectedCurrentTime, |
| scrollRange, |
| "Effect local time corresponds to the scroll position of the " + |
| "scroller."); |
| }, description); |
| } |
| |
| // start is @ 50px |
| // end is @ 1050px |
| // both have 50px heights |
| // scroller has 500px heights |
| // For each test the expected start/end is in the comment to help with the |
| // verification. |
| // |
| // Note: expectedCurrentTime values are percentages. They are used as such: |
| // CSS.percent(expectedCurrentTime) |
| const tests = { |
| // offsets: [100, 1100] |
| "at start": { |
| scrollTo: 100, |
| expectedCurrentTime: 0, |
| }, |
| // offsets: [100, 1100] |
| "after start": { |
| scrollTo: 200, |
| expectedCurrentTime: 10, |
| }, |
| // offsets: [100, 1100] |
| "at middle" : { |
| scrollTo: 600, |
| expectedCurrentTime: 50, |
| }, |
| // offsets: [100, 1100] |
| "at end" : { |
| scrollTo: 1099, |
| expectedCurrentTime: 99.9, |
| }, |
| // offsets: [100, 1100] |
| "after end" : { |
| scrollTo: 1150, |
| expectedCurrentTime: 100, |
| }, |
| // offsets: [75, 1075] |
| "with threshold 0.5" : { |
| // give threshold to both start and end to keep scrollRange |
| // 1000 which simplifies the calculation. |
| start: {threshold: 0.5}, |
| end: {threshold: 0.5}, |
| scrollTo: 600 - 25, |
| expectedCurrentTime: 50, |
| }, |
| // offsets: [50, 1050] |
| "with threshold 1.0": { |
| start: {threshold: 1.0}, |
| end: {threshold: 1.0}, |
| scrollTo: 600 - 50, |
| expectedCurrentTime: 50, |
| }, |
| // offset: [100, 550] |
| "with end edge" : { |
| end: {edge: "end"}, |
| scrollTo: 325, |
| expectedCurrentTime: 50, |
| }, |
| // offset: [100, 600] |
| "with end edge and threshold 1.0": { |
| end: { |
| threshold: 1.0, |
| edge: "end" |
| }, |
| scrollTo: 350, |
| expectedCurrentTime: 50, |
| }, |
| }; |
| |
| for (let orientation of ['vertical', 'horizontal']) { |
| for (let testName in tests) { |
| const description = `Animation start and current times are correct given |
| element-based offsets for orienation ${orientation} and ${testName}.`; |
| const config = tests[testName]; |
| config.orientation = orientation; |
| createScrollAnimationTest(description, config); |
| } |
| } |
| </script> |