Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Cover Flow in JavaScript and CSS 3-D

Cover Flow in JavaScript and CSS 3-D

Presented at HTML5 Developer Conference Autumn 2014.

With the support for buttery-smooth GPU-accelerated 3-d effect with CSS, modern browsers allow an implementation of a stunning fluid and dynamic user interface. To ensure that the performance is still at the 60 fps level, certain best practices needs to be followed: fast JavaScript code, usage of requestAnimationFrame, and optimized GPU compositing.

This talk aims to show a step-by-step guide to implement the infamous Cover Flow effect with JavaScript and CSS 3-D. We will start with the basic principle of custom touch-based scrolling technique, the math & physics behind momentum effect, and the use of perspective transformation to build a slick interface. Don’t worry, the final code is barely 200 lines!

Ariya Hidayat

October 21, 2014
Tweet

More Decks by Ariya Hidayat

Other Decks in Programming

Transcript

  1. Cover Flow in JavaScript and CSS 3-D
    @ariyahidayat
    Oct 21, 2014
    #HTML5DevConf

    View Slide

  2. Steve Jobs, 2007

    View Slide

  3. Newton’s
    laws of motion

    View Slide

  4. View Slide

  5. Optimized JavaScript
    requestAnimationFrame
    Event throttling

    View Slide

  6. ariya.github.io/kinetic
    #kineticscrolling
    https://speakerdeck.com/ariya

    View Slide

  7. Drag-and-Scroll
    1

    View Slide

  8. http://ariya.github.io/kinetic/1/

    View Slide

  9. Text
    “Clipped” via
    overflow:hidden
    http://ariya.ofilabs.com/2013/08/javascript-kinetic-scrolling-part-1.html
    80 lines of JavaScript
    Illusion of
    scrolling

    View Slide

  10. No Native Browser Scrolling
    view = document.getElementById('view');
    if (typeof window.ontouchstart !== 'undefined') {
    view.addEventListener('touchstart', tap);
    view.addEventListener('touchmove', drag);
    view.addEventListener('touchend', release);
    }
    view.addEventListener('mousedown', tap);
    view.addEventListener('mousemove', drag);
    view.addEventListener('mouseup', release);
    Intercept
    mouse events
    Intercept
    touch events

    View Slide

  11. Steady
    Pressed
    Scrolling
    touchstart
    touchend
    touchmove
    touchend

    View Slide

  12. Tap vs Release
    function tap(e) {
    pressed = true;
    reference = ypos(e);
    e.preventDefault();
    e.stopPropagation();
    return false;
    }
    function release(e) {
    pressed = false;
    e.preventDefault();
    e.stopPropagation();
    return false;
    }

    View Slide

  13. Drag: Delta + CSS Transform
    if (pressed) {
    y = ypos(e);
    delta = reference - y;
    reference = y;
    scroll(offset + delta);
    }
    function scroll(y) {
    offset = (y > max) ? max : (y < min) ? min : y;
    view.style[xform] = 'translateY(' + (-offset) + 'px)';
    }

    View Slide

  14. Scroll Threshold
    delta = reference - y;
    if (delta > 2 || delta < -2) {
    reference = y;
    scroll(offset + delta);
    }

    View Slide

  15. User taps the
    screen
    pressed = true
    (touch) reference = 20
    (view) offset = 100
    User drags 7 px up
    (touch) y = 13
    (touch) delta = 7
    (view) offset = 107
    translate the document by 7
    px
    User releases
    finger
    pressed = false

    View Slide

  16. Drag-and-Scroll Technique
    Intercept browser events
    Track position + apply CSS transform
    Illusion of scrolling

    View Slide

  17. Kinetic F/X
    2

    View Slide

  18. http://ariya.github.io/kinetic/2/
    Momentum Effect
    Flick List
    Kinetic Scrolling

    View Slide

  19. http://ariya.ofilabs.com/2013/11/javascript-kinetic-scrolling-part-2.html
    Automatic
    scrolling
    Manual
    scrolling
    120 lines of JavaScript

    View Slide

  20. Steady
    touchstart
    Pressed
    Manual
    Scrolling
    Automatic
    Scrolling
    touchend
    timer tick
    touchmove
    touchend and
    zero speed
    touchend and
    positive speed
    timer tick
    decelerate to zero speed
    touchstart

    View Slide

  21. Tap Drag
    Release
    (Quick) Move Release
    Flick Gesture

    View Slide

  22. Manual Scrolling Automatic Scrolling
    Track touch position
    Scroll the view
    Compute the “launch”
    velocity
    Scroll the view
    Reduce the velocity

    View Slide

  23. Continuous Velocity Tracking
    function tap(e) {
    pressed = true;
    reference = ypos(e);
    velocity = amplitude = 0;
    frame = offset;
    timestamp = Date.now();
    clearInterval(ticker);
    ticker = setInterval(track, 100);
    e.preventDefault();
    e.stopPropagation();
    return false;
    }
    Call track()
    10 times/second
    Rate throttling

    View Slide

  24. Velocity = Change of Position
    function track() {
    var now, elapsed, delta, v;
    now = Date.now();
    elapsed = now - timestamp;
    timestamp = now;
    delta = offset - frame;
    frame = offset;
    v = 1000 * delta / (1 + elapsed);
    velocity = 0.8 * v + 0.2 * velocity;
    }
    instantaneous velocity
    ~ 100 ms
    optional filter

    View Slide

  25. Automatic Scrolling
    Exponential decay
    time
    scroll
    offset

    View Slide

  26. Slow Down, a.k.a. Deceleration
    time
    velocity

    View Slide

  27. Stopped
    Decelerating

    View Slide

  28. Time Constant
    velocity reduced
    by 63%

    View Slide

  29. Scroll offset
    at a given time
    Final scroll offset
    Amplitude
    (how far the final scroll offset is)
    Time constant

    View Slide

  30. amplitude = 0.7 * velocity;
    target = offset + amplitude;
    requestAnimationFrame(autoScroll);
    Setup for Automatic Scrolling

    View Slide

  31. function autoScroll() {
    var elapsed = Date.now() - timestamp;
    scroll(target - amplitude * Math.exp(-elapsed / timeConstant));
    requestAnimationFrame(autoScroll);
    }
    Continuous Automatic Scrolling

    View Slide

  32. 6 × time constant
    The list will stop after 1.95 seconds

    View Slide

  33. The flick (=launch velocity) determines
    how far the list will stop
    It does not impact
    when the list will stop scrolling
    1
    2

    View Slide

  34. Kinetic Scrolling Unmasked
    Intercept browser events
    Track position + velocity
    Kinetic F/X
    Auto scroll with exponential decay

    View Slide

  35. Snap-to-Grid
    3

    View Slide

  36. http://ariya.github.io/kinetic/3/
    List items
    Target position

    View Slide

  37. Date Picker
    The scrolling can’t stop halfway

    View Slide

  38. Adjustment of Final Position
    http://ariya.ofilabs.com/2013/12/javascript-kinetic-scrolling-part-3.html
    Possible choices

    View Slide

  39. As Simple As...
    function autoScroll() {
    var elapsed = Date.now() - timestamp;
    scroll(target - amplitude * Math.exp(-elapsed / timeConstant));
    target = Math.round(target / snap) * snap;
    requestAnimationFrame(autoScroll);
    }

    View Slide

  40. As Simple As...
    function autoScroll() {
    var elapsed = Date.now() - timestamp;
    scroll(target - amplitude * Math.exp(-elapsed / timeConstant));
    target = Math.round(target / snap) * snap;
    requestAnimationFrame(autoScroll);
    }
    Integer multiples of snap

    View Slide

  41. Swipe with Parallax
    4

    View Slide

  42. View Slide

  43. View Slide

  44. http://ariya.github.io/kinetic/4/

    View Slide

  45. Different Distance, Different Speed
    http://ariya.ofilabs.com/2013/12/javascript-kinetic-scrolling-part-4.html

    View Slide

  46. function scroll(offset) {
    var slow = Math.round(offset / 2);
    var fast = Math.round(offset);
    ...
    }
    snap = screen width

    View Slide

  47. Cover Flow
    5

    View Slide

  48. CSS with GPU Compositing
    http://ariya.ofilabs.com/2013/06/optimizing-css3-for-gpu-compositing.html

    View Slide

  49. http://ariya.github.io/kinetic/5/

    View Slide

  50. View Slide

  51. 200 lines of JavaScript
    http://ariya.ofilabs.com/2014/01/javascript-kinetic-scrolling-part-5-cover-flow-effect.html
    No transformation
    translateX(-110px)
    translateZ(-150px)
    rotateY(60deg)
    translateX(110px)
    translateZ(-150px)
    rotateY(-60deg)

    View Slide

  52. translateX(-110px) translateX(-110px)
    translateZ(-150px)
    translateX(-110px)
    translateZ(-150px)
    rotateY(60deg)
    Perspective 3-D

    View Slide

  53. Model View Decoupling
    Touch events
    3-D View
    CSS transform

    View Slide

  54. Final Words

    View Slide

  55. Kinetic Scrolling
    Parallax Effect

    View Slide

  56. Thank You
    shapesecurity.com
    @ariyahidayat

    View Slide