Senior JS Developer
0,2
рейтинг
23 мая 2011 в 03:59

Разработка → Canvas F.A.Q


Несколько дней назад я предложил позадавать на Хабре интересующие вопросы по Canvas. Под Хабракатом — ответы на 27 вопросов.


1. Зачем нужен Canvas, что это вообще такое, какова поддержка браузерами, какова основная область применения, насколько развиты фреймворки, примеры?


Canvas — низкоуровневое API для отрисовки графики. Поддерживается всеми современными браузерами. Естественно, не поддерживается устаревшими версиями IE (8 и ниже)
Фреймворки развиваются, хотя им ещё нужно повзрослеть. Базовые примеры можно найти на MDC. Более мощные примеры можно поискать на сайтах а-ля Chrome Experiments или в примерах приложений на фреймворках, например LibCanvas

2. Когда нужно использовать Canvas, а когда Flash?



Flash быстрее, кроссбраузернее, с хорошими инструментами и фреймворками.
Canvas сейчас используется, в основном, энтузиастами и экспериментаторами.
Особой причины уходить с рынка флешерам нету.
Но Canvas'ом занимаются такие крупные игроки, как Google, Mozilla, Apple, Microsoft, все они оптимизируют и ускоряют отрисовку Canvas, постепенно отмирают старые браузеры и приходят новые. Посмотрите на Firefox 2.0 и Firefox 4.0. За три года скорость увеличилась на порядок и основной скачок сделан именно с выходом четвёртой версии. Аналогично — Опера. Также, за это время успел появиться Хром и выпустить уже 12 мажорных версий своего браузера. В общем, у HTML5 и Canvas в частности — светлое будущее.

3. Когда использовать Canvas, а когда SVG?


Это холиварная тема. Есть разные взгляды на неё.
Почитайте это обсуждение: habrahabr.ru/blogs/javascript/114129/#comment_3678242
Посмотрите эту картинку:

Почитайте статью "Thoughts on when to use Canvas and SVG"

С одной стороны, при использовании Canvas необходимо будет реализовывать то, что уже реализовано в SVG. С другой стороны, в Canvas можно применить такие оптимизации, которые в SVG невозможны, например отрисовка из кеша.

На мобильных телефонах актуально использование CSS3 вместо SVG и Canvas, т.к. оно ускоряется аппаратно и очень плавно работает.

4. Какую литературу почитать?


Рекомендую начать с Mozilla Developers Network, там очень классно и с примерами описаны основы Canvas. После этого придумайте себе задание и постарайтесь его реализовать. API — очень простой, тут главное — опыт.

Есть свежая книжка "HTML5 Canvas" издательства O'Reilly Media. Я не читал, но O'Reilly обычно выпускают классные книжки.


5. Как сделать скриншот Canvas?


Есть небольшая библиотека canvas2image она позволяет сохранять Canvas что на сервер, что на клиент. На клиенте сохранение производится при помощи toDataURL. На сервере получается содержимое при помощи getImageData, транслируется в base64 код и отправляется POST-запросом. На сервере достаточно сделать что-то типа такого кода:

if (empty($_POST['data'])) exit;

$data = $_POST['data'];
$name = md5($data);
$file = "$path/$name.png";
if (!file_exists($file)) {
	$image = str_replace(" ", "+", $data);
	$image = substr($image, strpos($image, ","));
	file_put_contents($file, base64_decode($image));
}
echo $file;


Так же, ответ от azproduction
Если «Скриншот канваса === Сохранить канвас как картинку», то:

/* раз */ canvas.getAsFile("test.jpg", "image/jpeg"); // File https://developer.mozilla.org/en/DOM/File
/* два */ canvas.toDataURL(); // String формата data url

/* пример */
function test() {
 var canvas = document.getElementById("canvas");
 var f = canvas.mozGetAsFile("test.png");
 
 var newImg = document.createElement("img");
 newImg.src = f.toDataURL();
 document.body.appendChild(newImg);
}

Почитать

Важно Вы должны задать фиксированные размеры канваса (через width/height или style), иначе получете плохие данные из toDataURL


6. Интересуют методы улучшения быстродействия (поднятие fps).


Есть разные методы оптимизации, которые зависят от приложения. Три из них я описывал в топике Пятнашки на LibCanvas. Это:
* Обновление холста исключительно при необходимости
* Вместо перерисовки всего холста перерисовывать только изменившиеся куски
* Отрисовка объектов в буфер (что позволяет рисовать объект каждый кадр как набор пикселей, а не применять все фильтры и кучу матана)
Вам очень поможет профайлер в вашем любимом браузере.

7. Работа с видеозахватом


azproduction:
Если вы про захват видео с камеры:
API есть только в черновике спецификации Media Capture API ближайший релиз спецификации возможен в PhoneGap — возможно есть в транке. Работать с ним будет очень просто. Вешается обработчик на «устройство», каждый кадр передается в виде картинки в формате data uri:
function success(data) {
  var container = document.createElement("div");
  
  for (var i in data) {
    var img = document.createElement("img");
    img.src = data[i].url;
    container.appendChild(img);
  }
  document.body.appendChild(container);

}
 
function error(err) {
  if (err.code === err.CAPTURE_INTERNAL_ERR) {
    alert("The capture failed due to an internal error.");
  }
  else {
    alert("Other error occured.");
  }
}
 
navigator.device.capture.captureImage(success, error, { limit: 1 });



8. Каково самое эффективное решение на данный момент для попиксельного доступа при отрисовке произвольного изображения на Canvas (без WebGL)? Например, ручная прорисовка граней при построении 3D с использованием закраски по Гуро/Фонгу.


Посмотрите два топика:
habrahabr.ru/blogs/crazydev/93594
habrahabr.ru/blogs/crazydev/94519

Для попиксельного доступа есть только одно решение — использовать getImageData

9. Есть ли пути эффективно и кросплатформенно смасштабировать канву со всеми внутренностями под размеры экрана?


Попробуйте использовать css. canvas { width: 100%; height: 100%; }. Как-то так. Но js-код должен учитывать этот кусок, т.к. сместятся координаты.

10. Поддержка и быстродействие на Android/iOS устройствах


Поддерживается полностью. Правда, я на iPhone2 заметил неподдержку fillText, но это единственное.
Проблема с производительностью, но кое-что можно запустить. Пока для мобильников лучше использовать CSS3. Возможно, в будущем, что-то поменяется.

11. Интересует самый быстрый способ нарисовать точку (например, для графика). Однопиксельную и четырёхпиксельную, произвольного цвета.


Самый быстрый с точки зрения производительности — использовать fillRect для одиночных отрисовок и getImageData+putImageData для массовых отрисовок.

12. В каком виде хранится, отображается и перерисовывается «мир» в играх с видом сбоку (как playbiolab.com), т.е. игрок побежал вправо камера подвинулась вместе с ним и мир «подвинулся»


Я точно не знаю, как оно делается в biolab. Есть несколько путей. Можно наложить несколько слоёв canvas друг на друга, отрисовать на нижнем мир и отображать нужную часть при помощи CSS.

13. 3d-canvas


Three.js — 3d движок на Javascript

14. Редакторы — в чём писать?


Подходит любой редактор JavaScript. Раньше я пользовался Netbeans 7, сейчас перешёл на Jetbrains WebIde

15. База данных


Для хранения данных на стороне клиента есть два современных стандарта — webStorage и IndexedDB.
IndexedDB — это крутой интерфейс с кучей возможностей, описывался на Хабре, а webStorage — простое key-value хранилище

16. Canvas и IE


В IE до девятой версии не поддерживается. Все попытки сделать его поддерживаемыми можно назвать подходящими только для очень узкого круга задач и не дают вменяемой скорости.
Имхо, единственный вариант — это Google Chrome Frame, плагин, который устанавливается на полубраузер как Flash или SilverLight и превращает говно в конфетку Internet Explorer в современный браузер.

17. Как посчитать расстояние между нарисованными объектами, есть ли готовые решения


Зависит от объектов. Некоторые вещи делаются очень просто. Например, расстояние между точками считается по теореме Пифагора. Между кругами — считаем расстояние между точками от отнимаем радиусы. У более сложных фигур есть свои законы.
Кое-что (по крайней мере пересечения ректанглов/кругов/полигонов) уже есть в LibCanvas. Если у вас какие-то особые требования — необходимо искать алгоритмы. Я могу посоветовать вот что:
Известные алгоритмы определения столкновений и реакции на них во флэше.

18. Как и какими средствами лучше делать анимации на Canvas?


Недавно был неплохой топик "Анимация и Canvas". Также, в комментариях я рассказывал о своей реализации при помощи LibCanvas.

19. Работа с текстом в Canvas (в т.ч. анимирование)


Текст отрисовывается при помощи fillText/strokeText. Свои шрифты можно подключать при помощи CSS3.
На него воздействуют все правила — такие как тени, трансформации, установка цветов и т.п. К примеру, с помощью светлой тени на тёмном фоне, можно легко сделать светящийся текст

20. Работа с изображениями.


Как работать с изображениями очень классно описано на MDC.

21. Использование Бэк Буффера, как отрисовать один Canvas в другой.


Вы можете отрисовать какую-либо информацию в скрытый Canvas, который затем использовать точно так же как картинку (смотреть предыдущий пункт).
Буферизация позволяет ускорить отрисовку многократно. Например, отрисовать один градиент из буфера в 5 раз быстрее, чем отрисовать этот же градиент напрямую.
Использовать очень просто:
// Создаём буфер нужного размера:
var buffer = document.createElement('canvas');
buffer.width  = 64;
buffer.height = 32;
buffer.ctx    = buffer.getContext('2d');
// или при помощи LibCanvas:
var buffer = LibCanvas.Buffer(64, 32, true);

// Отрисовываем в него всё необходимое
buffer.ctx.fillRect(/* */)

// отрисовываем его на наш холст:
var ctx = canvas.getContext('2d');
ctx.drawImage( buffer, 0, 0 );


22. Анимация в канвасе происходит методом полной перерисовки. Таким образом информация обо всех объектах хранится в объекте JS и каждый раз перерисовывается, или можно как то создавать спрайты и слои?


Да, есть различные приёмы. Можно использовать буфера для того, чтобы не отрисовывать десятки мелких объектов, можно перерисовывать холст только частично, но чаще всего дешевле просто всё перерисовать, чем понять, что перерисовывать надо, а что — нет.

23. Хотелось бы узнать как с помощью canvas нарисовать 3д объект(желательно с учетом перспективы) и вращать?


HTML5 Experiment: A Rotating Solid Cube

24. Отрисовка SVG в Canvas


Можно при помощи CanVG. Смысла практически нету)

25. Насколько различается поддержка в браузерах или все следуют стандарту?


Различия минимальны. Обнаруживались мелкие баги, легкие несоответствия. Например, Опера не могла отрисовать прямоугольник с отрицательными размерами сторон:
ctx.fillRect(50, 50, -20, -20);

По разному сжимаются и поворачиваются картинки. Например, в Хроме при повороте на углах заметны зубья (нету сглаживания)

Зато он лучше, чем Fx и Opera растягивает картинки:


Есть ещё мелкие различия в JavaScript. Например, в некоторых браузерах sort реализует неустойчивую сортировку, так что, если элементы сортировать по Z-индексу, то элементы с одинаковым Z-индексом будут менятся местами.

Это очень мелкие нюансы. Большинство — скрыто за дружелюбным API фреймворков. Лично я разрабатываю только под один браузер и в большинстве случаев всё работает совершенно корректно и в остальных.

26. putImageData vs drawImage


Буду краток — putImageData значительно медленнее. Более того, с увеличением размеров картинки — увеличивается медлительность.

27. Мне было бы очень интересно послушать про типовые реализации основного функционала canvas-библиотек, таких как: эмуляция слоев, определение активного элемента (на котором в данный момент находится курсор), создание системы управления событиями и т. д.


Этот вопрос задавали мне чаще всего, потому для него — отдельный топик)

Вопросы без ответов


Ребята, кто может дать ответы на эти вопросы — прошу в комменты

1. Как вывести текст на canvas в IE (IE8- + excanvas.js)? Пробовал text.canvas.js с гуглокода — выводит ошибку про отсутствие нечто glyphs.
Я не использую эмуляцию в IE

2. Существуют ли какие-то секретные библиотеки, умеющие рисовать линии переменной толщины. В случае с прямыми это относительно несложно реализовать «костыльным» способом, а вот всякие кривые Безье — видимо, только на низком пиксельном уровне.

3. Существуют ли какие-то секретные библиотеки, умеющие рисовать градиентную раскраску линий. Ну то есть чтобы цвет плавно менялся между узлами вдоль линии, не обязательно прямой. Такая функция есть, например, в OpenGL.

Вывод


Если что-то непонятно — задавайте вопросы, будем дополнять) Если Ваш вопрос не отвечен или, даже, не задан — задавайте снова в комментариях. Если нету реги вы можете мне писать на email shocksilien@gmail.com
Понравился такой формат топика?
Павло @TheShock
карма
226,7
рейтинг 0,2
Senior JS Developer
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (22)

  • 0
    Существуют ли какие-то секретные библиотеки, умеющие рисовать градиентную раскраску линий. Ну то есть чтобы цвет плавно менялся между узлами вдоль линии, не обязательно прямой. Такая функция есть, например, в OpenGL.

    g = ctx.createLinearGradient(s.x, s.y, f.x, f.y);
    g.addColorStop(0, "red");
    g.addColorStop(1, "green");

    ctx.strokeStyle = g;


    • 0
      где s = startPoint и f = finalPoint
    • 0
      Да, этот вариант очевиден (вопрос из топика задан мной), но он работает только для прямых. А вот как быть с кривыми Безье? Да если к тому же градиент имеет более 2 колор-стопов, и они не совпадают с узлами кривой?

      Я размышлял, можно ли это накостылить существующим функционалом? Например, разбить кривую на мелкие сегменты и апроксимировать градиент мелкими линейными кусочками. Но как ни крути, это именно костыль, причем грубый:
      1. Много громоздкой математики
      2. Огромный объем мутного для чтения кода
      3. Проблемы со сглаживанием линии
      4. Проблемы с корректной отрисовкой концов линии
      5. Проблемы с полупрозрачными линиями
      6. Из-за пиксельных округлений дроблёная линия может немного искажаться по сравнений с исходной

      Ну и т.д. Думаю, полноценно решить этот вопрос можно только попиксельным рисованием, на гораздо долее низком уровне абстракции. Задача нетривиальна.
  • 0
    такие оптимизации, которые в SVG невозможны, например отрисовка из кеша
    Возможны.
    • 0
      Ну тут вопрос скорее стоит кто его поддерживает? Для svg есть хорошая библиотека raphael, как то ей пользовался, работает и в ie за счет использования VML.
      Говоря о canvas не думаю что кому-то охота мучиться с ie, да и плюшки канвы там работать не будут.

      Думаю что конкурент canvas сейчас больше SVG нежели флеш, так как на флеше обычно реализуют довольно сложные игрушки (да и удобней это там делать пока. объективно), нежели простую анимацию.

      Автору спасибо за пост, услышать конкретные ответы на насущные темы всегда полезно.
    • 0
      Работает только в Опере, управлять практически нереально, например я хочу сделать игру «танчики» с видом сверху. Я отрисовываю тело одного танка в буфер плюс башню в буфер и все танки рисуются не как векторные объекты, а как два спрайта. Как это сделать на SVG?
  • 0
    Упомянутая книжка от O'Reilly действительно неплохая. Там рассмотрены почти все базовые вопросы — работа с мышью, спрайтовая анимация, базовая физика (трение и гравитация), реализовано несколько простеньких игр. Есть даже про взаимодействие с video и работа со звуком:)
  • +1
    Canvas — низкоуровневое API для отрисовки графики. Поддерживается всеми современными браузерами. Естественно, не поддерживается IE.


    Павел, зачем в первой же строчке откровенная неправда?
    • +2
      Согласен, некорректно выразился. В ie9 поддерживается Canvas на том же уровне, что и в остальных современных браузерах.
  • +1
    Спасибо за статью. Очень полезная. Как раз у меня стажёр в этом направлении работает. Будет ему очень полезна.
  • 0
    вопрос немного не по теме: с помощью каких инструментов проще всего создавать покадровую анимацию(изображения)?
  • –3
    > Поддерживается всеми современными браузерами. Естественно, не поддерживается IE.

    Позже:
    > В IE до девятой версии не поддерживается.

    На самом деле некоторые функции, которых зачастую достаточно для чего-то простого, поддерживаются даже в ИЕ6 через эмуляцию посредством VML (библиотека гугла, вроде называется IE canvas)
    • 0
      п. 16 Все попытки сделать его поддерживаемыми можно назвать подходящими только для очень узкого круга задач и не дают вменяемой скорости.

      =) либа называется excanvas. Есть ещё либы на flash и activeX. Но они подходят только для совсем лёгких задач, имхо.
      • 0
        На самом деле тормоза будут только при каких то анимациях. А если просто отрисовать например график, то в том же ИЕ8 работает сносно, даже с какими-то несложными динамическими изменениями шкал. Так или иначе, суть моего коммента, что у вас написаны были взаимоисключающие параграфы. Я не призываю всех яростно использовать либы, просто констатировал факт.
  • –2
    Столько танцев с бубном вокруг тривиальных задач. Это мазохизм какой-то. По крайне мере с точки зрения флэшера. CSS для движения фона… Наложения канвасов один на другой для слоев… Полная перерисовка при анимации, буферизация отдельных объектов и частичная перерисовка. Да еще в разных браузерах по разному.
    • +3
      но в итоге canvas куда более естесственен для браузера, чем внешний модуль флэша
      • 0
        Ходить для человека гораздо более естественно чем ездить на авто.
    • +4
      Вы лукавите. Я, конечно, в Flash не эксперт, но как на счёт проблем с производительностью при большом количестве объектов без использования cacheAsBitmap? При этом он тоже не совсем идеален. Есть ещё всякие костыли типа интересного векторного HUE и тд)

      Да, возможно в Canvas есть свои заморочки, но не утверждайте, что Flash — идеален)

      И да при помощи LibCanvas половина того, что вы описали вообще абстрагируется в прозрачный интерфейс.

      // создание слоёв
      var layer = libcanvas.createLayer('units'); 
      
      // сдвиг слоя
      layer.shift(100, 100)
      


      Перерисовка тоже хитрая, буферизация — облегчённая. Браузеры — абстрагированы и все приведены к одному виду.

      А вам не всё-равно ли — там css или что-то ещё?
      • –3
        Да мне то все равно. Это вы же с бубном пляшете. Во флэше о производительности задумываются после 300 объектов на стейдже. а с канвасом после 10. Да и правильное использование cacheasbitmap все решает.

        TheShock Ты сделал так чтоб atom с mootools не ругался?
        • +1
          Ага. Подключаете Атом после Мутулз и они будут друг-друга дополнять)
  • НЛО прилетело и опубликовало эту надпись здесь
  • –1
    14. Редакторы — в чём писать?


    Visual Studio + Script#. Очень удобно на самом деле, кто недолюбливает JavaScript.

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.