$30 off During Our Annual Pro Sale. View Details »

High Performance Data Visualizations

High Performance Data Visualizations

If you thought that building rich, interactive and mobile-friendly visualizations of high volume data with 100,000+ points just using the power of browser-side JavaScript was impossible, this talk by the creator of Leaflet will prove you wrong.

We’ll cover every important aspect of achieving peak performance and responsiveness for such kind of apps, including real-time data simplification, computational geometry and clustering algorithms, tree structures, fast collision detection, typed arrays, Web Workers and mixing Canvas with SVG.

Vladimir Agafonkin

April 26, 2013
Tweet

More Decks by Vladimir Agafonkin

Other Decks in Programming

Transcript

  1. Vladimir Agafonkin
    High Performance
    Data Visualizations
    April 2013

    View Slide

  2. rain.in.ua

    View Slide

  3. agafonkin.com
    /mourner

    View Slide

  4. View Slide

  5. View Slide

  6. data visualization

    View Slide

  7. View Slide

  8. View Slide

  9. View Slide

  10. View Slide

  11. View Slide

  12. View Slide

  13. not static anymore

    View Slide

  14. responding to user actions
    clicking, hovering, scrolling,
    touch gestures, etc.

    View Slide

  15. View Slide

  16. View Slide

  17. View Slide

  18. navigating through data

    View Slide

  19. filtering

    View Slide

  20. demand for real-time
    interactivity is increasing

    View Slide

  21. responsibility for processing data
    is shifting from the server
    to the browser

    View Slide

  22. lots of data
    +
    lots of rendering
    =
    big performance problem

    View Slide

  23. pure JS
    fast
    rendering, DOM
    slow

    View Slide

  24. rule #1
    the less stuff we render
    the better

    View Slide

  25. data
    processing
    rendering

    View Slide

  26. data processing rendering

    View Slide

  27. View Slide

  28. data reduction

    View Slide

  29. search

    View Slide

  30. loading data
    once
    searching data
    lots of times

    View Slide

  31. search index

    View Slide

  32. grid

    View Slide

  33. tree data structures
    •binary heap
    •binary search tree
    •range tree
    •k-d tree
    •quadtree
    •R-tree

    View Slide

  34. points – quadtree

    View Slide

  35. rectangles – R-tree

    View Slide

  36. var tree = new RTree();
    tree.insert(
    {x: 5, y: 10, w: 10, h: 15}, obj);
    ...
    tree.search(
    {x: 7, y: 7, w: 5, h: 5});
    github.com/imbcmdth/RTree

    View Slide

  37. kothic.org/js

    View Slide

  38. collision detection

    View Slide

  39. Crossfilter (many dimensions)

    View Slide

  40. geometric clipping

    View Slide

  41. polyline clipping
    Cohen-Sutherland algorithm

    View Slide

  42. polygon clipping
    Sutherland-Hodgeman algorithm

    View Slide

  43. polyline simplification

    View Slide

  44. distance-based simplification

    View Slide

  45. Douglas-Peucker
    simplification

    View Slide

  46. mourner.github.com/simplify-js

    View Slide

  47. clustering
    grouping objects which are
    close to each other

    View Slide

  48. View Slide

  49. View Slide

  50. hierarchical clustering
    once for all zoom
    levels

    View Slide

  51. data loading and
    processing

    View Slide

  52. UI JS
    browser freezes
    on heavy calculations
    UI

    View Slide

  53. Web Workers

    View Slide


  54. <br/>...<br/>worker.postMessage(HUGE_DATA_ARRAY);<br/>...<br/>
    loading and sending to Worker

    View Slide

  55. UI
    Worker JS
    browser freezes on data loading
    and sending
    data
    loading UI

    View Slide

  56. importScripts('data.js');
    ...
    onmessage = function (e) {
    var result =
    searchData(e.data.query);
    postMessage(result);
    }
    Loading in Worker

    View Slide

  57. UI
    Worker JS
    browser freezes when receiving
    data from Worker
    data
    loading
    UI
    UI

    View Slide

  58. var array = new Float16Array(len);
    ...
    var buffer = array.buffer;
    postMessage(buffer, [buffer]);
    // buffer stops being available
    transferable objects
    (Chrome, Firefox)

    View Slide

  59. UI
    Worker JS
    browser doesn't freeze,
    data is sent as ArrayBuffer
    data
    loading
    UI
    UI

    View Slide

  60. function addNumbers(a, b) {
    'use asm';
    a = a | 0; // int
    b = +b; // double
    return +(a + b); // double
    }
    bright future — asm.js

    View Slide

  61. bright future — asm.js
    •useful for computational
    bottlenecks
    •FF Nightly; V8 on the way
    •backwards compatibility!

    View Slide

  62. rendering backends
    SVG, Canvas, WebGL

    View Slide

  63. SVG
    •fast native events for
    interactivity
    •easy to update separate
    objects
    •slows down the browser (with
    a large number of objects)

    View Slide

  64. Canvas
    •doesn't affect browser
    performance after rendering
    •you can draw something once
    and copy
    •pixel data can be manipulated
    or generated in a Worker

    View Slide

  65. Canvas
    •expensive to redraw with
    each update
    •hard to implement
    interactivity

    View Slide

  66. WebGL
    •main way to visualize in 3D
    •very fast in 2D if you need to draw lots
    of sprites
    •performance gain vs Canvas-2D is
    questionable in other cases
    •much more difficult to use; limitations
    •no support in iOS and IE9-10

    View Slide

  67. low number of objects:
    use SVG
    lots of stuff to draw:
    use Canvas

    View Slide

  68. Canvas Performance

    View Slide

  69. redraw partially

    View Slide

  70. draw once to an offscreen
    canvas and copy

    View Slide

  71. function drawStar(ctx, x, y) {
    ...
    }
    drawStar(ctx, 10, 20);
    drawStar(ctx, 50, 70);
    ...

    View Slide

  72. function drawStar() {
    ...
    return canvas;
    }
    var star = drawStar();
    ctx.drawImage(star, 10, 20);
    ctx.drawImage(star, 50, 70);
    ...

    View Slide

  73. minimize stroke/fill

    View Slide

  74. function drawLine(x1, x2, y1, y2) {
    ctx.strokeStyle = 'red';
    ctx.beginPath();
    ctx.moveTo(x1, y1);
    ctx.lineTo(x2, y2);
    ctx.stroke();
    }
    drawLine(10, 20, 30, 40);
    drawLine(200, 10, 0, 50);
    drawLine(30, 40, 70, 0);

    View Slide

  75. function drawLine(x1, x2, y1, y2) {
    ctx.beginPath();
    ctx.moveTo(x1, y1);
    ctx.lineTo(x2, y2);
    }
    ctx.strokeStyle = 'red';
    drawLine(10, 20, 30, 40);
    drawLine(200, 10, 0, 50);
    drawLine(30, 40, 70, 0);
    ctx.stroke();

    View Slide

  76. generate or manipulate
    raw pixel data in a Worker

    View Slide

  77. var data =
    ctx.getImageData(0, 0, width, height).data;
    worker.postMessage(data, [data]);
    ...
    worker.onmessage = function (e) {
    var imageData =
    ctx.createImageData(width, height);
    imageData.data.set(e.data);
    ctx.putImageData(imageData, 0, 0);
    }
    Canvas + Worker

    View Slide

  78. var pixels = new Uint8ClampedArray(
    width * height);
    function drawPixel(x, y, r, g, b, a) {
    var i = 4 * (256 * y + x);
    pixels[i] = r;
    pixels[i + 1] = g;
    pixels[i + 2] = b;
    pixels[i + 3] = a;
    }
    ...
    postMessage(pixels.buffer, [pixels.buffer]);
    drawing pixels in a Worker

    View Slide

  79. var pixels = new Uint8ClampedArray(data);
    for (var x = 0; x < width; x++) {
    for (var y = 0; y < height; y++) {
    var i = 4 * (256 * y + x);
    pixels[i] = 2 * pixels[i];
    pixels[i + 1] = 2 * pixels[i + 1];
    pixels[i + 2] = 2 * pixels[i + 2];
    }
    }
    ...
    postMessage(pixels.buffer, [pixels.buffer]);
    processing pixels in a Worker

    View Slide

  80. hover lookup table

    View Slide

  81. canvas + pixel color

    View Slide

  82. UTFGrid
    •65535 symbols
    •each symbol is 4х4
    pixels
    •1-3 KB per 256х256
    tile in average

    View Slide

  83. Thanks!
    Questions?
    Vladimir Agafonkin
    [email protected]

    View Slide