CodeFest 2013. Агафонкин В. — Высокопроизводительные...

Post on 14-Nov-2014

609 views 4 download

Tags:

description

 

Transcript of CodeFest 2013. Агафонкин В. — Высокопроизводительные...

Владимир Агафонкин

высокопроизводительные визуализации данных

в браузере

март 2013

agafonkin.com

/mourner

rain.in.ua

визуализации данных

интерактивность

•реагирование на действия пользователя

интерактивность

•реагирование на действия пользователя

•навигация по данным

интерактивность

•реагирование на действия пользователя

•навигация по данным

•фильтрация данных

интерактивность

потребность в интерактивности увеличивается

ответственность за обработку данных всё больше смещается

от сервера к клиенту

чистый JS — быстро

рендеринг, DOM — медленно

правило №1чем меньше всего

отображаем, тем быстрее

обработка данных рендеринг

обработка данных рендеринг

•фильтрация объектовуменьшение данных

•фильтрация объектов•геометрическое отсечение

уменьшение данных

•фильтрация объектов•геометрическое отсечение•геометрическое упрощение

уменьшение данных

•фильтрация объектов•геометрическое отсечение•геометрическое упрощение•кластеризация (группировка)

уменьшение данных

фильтрация

поиск 2D-объектов

•поиск объектов в текущей прямоугольной видимой области

поиск 2D-объектов

•поиск объектов в текущей прямоугольной видимой области

•поиск объектов в точке (под курсором)

загрузка данных — 1 раз

поиск/фильтрация — много раз

сетка

древовидные структуры данных

•binary heap

•binary search tree

•range tree

•k-d tree

•quadtree

•R-tree

точки в quadtree

прямоугольники в R-tree

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

kothic.org/js

определение коллизий

Crossfilter (для многих измерений)

отсечение ломаных линийалгоритм Коэна-Сазерленда

отсечение полигоновалгоритм Сазерленда-Ходжмана

упрощение ломаных линий

упрощение по расстоянию

алгоритм Дугласа-Пекера

mourner.github.com/simplify-js

кластеризациягруппировка похожих объектов

иерархическая кластеризация

1 раз для всех масштабов

загрузка и обработка данных

UI JS UI

UI JS

браузер залипаетна объемных вычислениях

UI

Web Workers

<script src='data.js'></script>

<script>...worker.postMessage(HUGE_DATA_ARRAY);...</script>

загрузка и пересылка в Worker

UI

Worker JS

загрузка данных UI

UI

Worker JS

браузер залипает на загрузке и пересылке данных

загрузка данных UI

importScripts('data.js');

...

onmessage = function (e) { var result = searchData(e.data.query);

postMessage(result);}

загрузка в Worker

UI

Worker JSзагрузка данных

UIUI

UI

Worker JS

браузер залипает на получении данных

загрузка данных

UIUI

var array = new Float16Array(len);...

var buffer = array.buffer;

postMessage(buffer, [buffer]);

// с этого момента buffer недоступен

transferable objects(Chrome, Firefox)

UI

Worker JSзагрузка данных

UIUI

UI

Worker JS

браузер не залипает, данные пересылаются как ArrayBuffer

загрузка данных

UIUI

function addNumbers(a, b) { 'use asm';

a = a | 0; // int b = +b; // double

return +(a + b); // double}

светлое будущее — asm.js

светлое будущее — asm.js

•оптимизация узких мест вычислений

светлое будущее — asm.js

•оптимизация узких мест вычислений

•пока только в FF Nightly

светлое будущее — asm.js

•оптимизация узких мест вычислений

•пока только в FF Nightly

•обратная совместимость!

технологии рендерингаSVG, Canvas, HTML, WebGL

SVG

•быстрые нативные события для интерактивности

SVG

•быстрые нативные события для интерактивности

•легко обновлять отдельные объекты

SVG

•быстрые нативные события для интерактивности

•легко обновлять отдельные объекты

•тормозит страницу (при большом кол-ве объектов)

Canvas

•после отрисовки не влияет на отзывчивость страницы

Canvas

•после отрисовки не влияет на отзывчивость страницы

•повторяющиеся части можно отрисовать один раз и раскопировать

Canvas

•после отрисовки не влияет на отзывчивость страницы

•повторяющиеся части можно отрисовать один раз и раскопировать

•можно попиксельно рисовать/обрабатывать в Worker

Canvas

•дорого перерисовывать при каждом обновлении

Canvas

•дорого перерисовывать при каждом обновлении

•очень сложно с реализацией интерактивности

WebGL

•основной способ для 3D-визуализаций

WebGL

•основной способ для 3D-визуализаций

•очень быстро в 2D, если нужно отрисовать много спрайтов

WebGL

•основной способ для 3D-визуализаций

•очень быстро в 2D, если нужно отрисовать много спрайтов

•в остальных случаях преимущество в скорости перед Canvas-2D спорно

WebGL

•основной способ для 3D-визуализаций

•очень быстро в 2D, если нужно отрисовать много спрайтов

•в остальных случаях преимущество в скорости перед Canvas-2D спорно

•API намного сложнее и неудобнее

WebGL

•основной способ для 3D-визуализаций

•очень быстро в 2D, если нужно отрисовать много спрайтов

•в остальных случаях преимущество в скорости перед Canvas-2D спорно

•API намного сложнее и неудобнее

•поддержки в IE и iOS не ожидается

HTML

•удобно использовать для текста и элементов интерфейса

HTML

•удобно использовать для текста и элементов интерфейса

•очень удобно анимировать с помощью CSS Transitions

HTML

•удобно использовать для текста и элементов интерфейса

•очень удобно анимировать с помощью CSS Transitions

•тормозит страницу при большом кол-ве объектов

производительность Canvas

частичная перерисовка

частичная перерисовка

частичная перерисовка

function drawStar(x, y) { ... // нарисовать звезду в x, y}

drawStar(10, 20);drawStar(50, 70);...

function drawStar() { var canvas = document.createElement('canvas'); ... // нарисовать звезду return canvas;}

var star = drawStar();

ctx.drawImage(star, 10, 20);ctx.drawImage(star, 50, 70);...

копирование

группируйте отрисовку по стилям, минимизируйте stroke/fill

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);

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();

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

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]);

рисование пикселей в Worker

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]);

обработка пикселей в Worker

UTFGrid

UTFGrid

•65535 разных символов

UTFGrid

•65535 разных символов

•каждый символ — 4х4 пикселя

UTFGrid

•65535 разных символов

•каждый символ — 4х4 пикселя

•сетка + маппинг

UTFGrid

•65535 разных символов

•каждый символ — 4х4 пикселя

•сетка + маппинг

•в среднем 1-3 КБ на тайл 256х256

Спасибо!Вопросы?

Владимир Агафонкинagafonkin@gmail.com