Отрисовка SVG внутри HTML5 Canvas.


Года два назад в интернете начали появляться статьи, в которых сравнивали SVG и Canvas. В итоге сейчас не составляет особого труда найти сайт, на котором популярно объясняются плюсы и минусы использования SVG-изображений или отрисовки напрямую в Canvas.

Здесь я хотел обозначить совсем другую задачу – отобразить картинку в SVG-формате с помощью API Canvas-a. Другими словами, тема статьи не “SVG против Canvas”, а как рисовать SVG картинки внутри Canvas. Подобного рода задача возникнет, например, в случае, если у вас уже есть небольшой набор не слишком сложных SVG-файлов, и вы хотели бы их использовать, при этом ваш графический javascript-овый движок базируется на Canvas-e.

Можно выделить два основных похода:
1. Первый подход.
Парсить SVG файл JavaScript-ом и руками рисовать его в канву.
Один из самых популярных движков, которые реализуют подобный функционал это: http://code.google.com/p/canvg/

2. Второй подход.
На самом деле, многие браузеры умеют рисовать SVG файлы непосредственно в канву методом drawImage. Точно также как обычные растровые изображения (PNG, JPG и т.д.) – https://developer.mozilla.org/en-US/docs/Canvas_tutorial/Using_images.
Проблемы заключаются как всегда в том, что разные браузеры могут делать это по-разному.
В итоге пришлось провести небольшую работу для проверки отображение SVG внутри Canvas-a для различных браузеров. На момент публикации этой статьи получилась следующая картинка:

Попробуем запустить следующий пример:

<!DOCTYPE html>
<html>
  <head>
    <title>svg on canvas</title>
    <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
  </head>
  <body>
    <canvas id='example' width='150' height='100'></canvas>
    <script>
      var canvas = document.getElementById("example");
      var context = canvas.getContext("2d");
      context.fillRect(10, 10, canvas.width - 20, canvas.height - 20);
      var image = new Image();
      image.src = "./star.svg";
      image.onload = function() { 
           context.drawImage(image, 43, 18);  
      };
      context.drawImage(image, 43, 18);  

    </script>
  </body>
</html>

SVG-изображение: star.svg
В итоге получим следующую картинку:

Chrome, Safari, IE 9



Firefox

В Firefox мой пример отрисовался, но с некоторыми более сложными SVG-изображениями не справился.

Opera 12.02

Наиболее забавная ситуация обстоит с браузером Opera.
Многие поисковые системы показывают большое количество ссылок на сайты, которые содержат в себе фразу:
“В браузере Opera можно также рисовать изображения SVG внутри холста. Это достаточно сложный метод… и т.д.”
На самом деле, для текущей версии Opera это не совсем верно (версия 12.02, OS Windows 7) !
Opera не всегда может рисовать SVG изображения внутри Canvas (код описания ошибки: CORE-26856)

В августе 2012 выпущен тестовый релиз с множеством исправлений.
Скачать его можно здесь: http://my.opera.com/desktopteam/blog/2012/08/03/summer-core-update
Если запускать в нём, то рисунок покажется:

Кроме отрисовки в Opera есть проблема, связанная с тем, что для SVG изображений не срабатывает событие onload.

var img = new Image();
img.onload = function() { alert('onload'); }
img.src = "a.svg";

Напоследок хотелось сказать самое главное – соблюдайте осторожность при работе с SVG-картинами!

На протяжении нескольких  последних лет в браузерах находят различные уязвимости в безопасности, связанные как раз с отображением SVG внутри браузера. Конечно, многие браузеры с целью безопасности накладывают ограничения на работу с SVG, тем не менее не стоит полностью полагаться на них, поэтому желательно на этапе проектирования архитектуры учитывать различные аспекты, связанные с безопасной работой с SVG-изображениями.

Любое использование либо копирование материалов или подборки материалов сайта, элементов дизайна и оформления допускается лишь с разрешения правообладателя и только со ссылкой на источник: programador.ru

Телеграм канал: @prgrmdr
Почта для связи: vit [at] programmisty.com