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.

6d07e6d95a43357254698ce9723350e6?s=128

Vladimir Agafonkin

April 26, 2013
Tweet

Transcript

  1. Vladimir Agafonkin High Performance Data Visualizations April 2013

  2. rain.in.ua

  3. agafonkin.com /mourner

  4. None
  5. None
  6. data visualization

  7. None
  8. None
  9. None
  10. None
  11. None
  12. None
  13. not static anymore

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

  15. None
  16. None
  17. None
  18. navigating through data

  19. filtering

  20. demand for real-time interactivity is increasing

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

    the browser
  22. lots of data + lots of rendering = big performance

    problem
  23. pure JS fast rendering, DOM slow

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

  25. data processing rendering

  26. data processing rendering

  27. None
  28. data reduction

  29. search

  30. loading data once searching data lots of times

  31. search index

  32. grid

  33. tree data structures •binary heap •binary search tree •range tree

    •k-d tree •quadtree •R-tree
  34. points – quadtree

  35. rectangles – R-tree

  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
  37. kothic.org/js

  38. collision detection

  39. Crossfilter (many dimensions)

  40. geometric clipping

  41. polyline clipping Cohen-Sutherland algorithm

  42. polygon clipping Sutherland-Hodgeman algorithm

  43. polyline simplification

  44. distance-based simplification

  45. Douglas-Peucker simplification

  46. mourner.github.com/simplify-js

  47. clustering grouping objects which are close to each other

  48. None
  49. None
  50. hierarchical clustering once for all zoom levels

  51. data loading and processing

  52. UI JS browser freezes on heavy calculations UI

  53. Web Workers

  54. <script src='data.js'></script> <script> ... worker.postMessage(HUGE_DATA_ARRAY); ... </script> loading and sending

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

    data loading UI
  56. importScripts('data.js'); ... onmessage = function (e) { var result =

    searchData(e.data.query); postMessage(result); } Loading in Worker
  57. UI Worker JS browser freezes when receiving data from Worker

    data loading UI UI
  58. var array = new Float16Array(len); ... var buffer = array.buffer;

    postMessage(buffer, [buffer]); // buffer stops being available transferable objects (Chrome, Firefox)
  59. UI Worker JS browser doesn't freeze, data is sent as

    ArrayBuffer data loading UI UI
  60. function addNumbers(a, b) { 'use asm'; a = a |

    0; // int b = +b; // double return +(a + b); // double } bright future — asm.js
  61. bright future — asm.js •useful for computational bottlenecks •FF Nightly;

    V8 on the way •backwards compatibility!
  62. rendering backends SVG, Canvas, WebGL

  63. SVG •fast native events for interactivity •easy to update separate

    objects •slows down the browser (with a large number of objects)
  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
  65. Canvas •expensive to redraw with each update •hard to implement

    interactivity
  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
  67. low number of objects: use SVG lots of stuff to

    draw: use Canvas
  68. Canvas Performance

  69. redraw partially

  70. draw once to an offscreen canvas and copy

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

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

    drawStar(); ctx.drawImage(star, 10, 20); ctx.drawImage(star, 50, 70); ...
  73. minimize stroke/fill

  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);
  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();
  76. generate or manipulate raw pixel data in a Worker

  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
  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
  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
  80. hover lookup table

  81. canvas + pixel color

  82. UTFGrid •65535 symbols •each symbol is 4х4 pixels •1-3 KB

    per 256х256 tile in average
  83. Thanks! Questions? Vladimir Agafonkin agafonkin@gmail.com