Во-первых, потребовалось меньшее количество кода для создания на svg.
Во-вторых, простота и удобство создания кода. У svg логика строится на отдельных объектах, их свойствах и методах. Например, чтобы определить объект под курсором, нужно создать обработчик события для данного объекта (circle для станций метро), в котором можно поменять его свойства — цвет, масштаб (на картинке для значка станции «Ходынское поле» применен метод scale) и др. У канваса логика отрисовки построена на перерисовке всей карты. И для выделения отдельных объектов нужно перерисовывать и масштабировать всю карту. Кроме этого, канвас не хранит отрисованные объекты в памяти, их нужно отдельно сохранять в переменных (в dbcartajs в объекте mflood) и самому следить за ними (добавлять, удалять). SVG-изображение хранит отрисованные объекты в DOM-модели и к ним можно обращаться напрямую.
В-третьих, возможностей в svg намного больше, чем в канвасе, например, анимация, фильтры для изображений.
В-четвертых, совместимость с браузерами. У SVG она выше. C SVG я проблем не заметил. В канвасе некоторые свойства в Firefox 3.x и новых версиях работают по разному (например setDashLine, isPointInPath). Internet Explorer до 9 версии и Safari до 4 версии канвас вообще не поддерживали.
И svg, и канвас могут манипулировать готовыми изображениями (png, jpeg). Правда, только канвас может обращаться к нему попиксельно. И это, как и скорость отрисовки, пожалуй, его главная особенность.
В общем, кому интересно, смотрите примеры на egaxegax.github.io.
Комментарии (20)
Keyten
05.10.2015 00:33-1Первые 3 «во-первых» легко решаются библиотеками для canvas.
egaxegax
05.10.2015 01:02Какими, например? И как? У каждой библиотеки своя область применения.
Keyten
06.10.2015 00:49Ну это естественно.
LibCanvas, Fabric, Graphics2D, PaperJS хотя бы. Первое, что вспомнилось.
Они общего назначения, есть и специализированные.
Во-первых, потребовалось меньшее количество кода для создания на svg.
Сравниваем:
<rect x="10" y="10" width="200" height="200" fill="red"/> <path d="M10,10 L200,200 L400,10" fill="blue"/>
Пример для canvas будет на Graphics2d, т.к. я её лучше всего знаю, да и там короче всех, пожалуй:
var rect = ctx.rect(10, 10, 200, 200, 'red'); // либо: var rect = ctx.rect({ x: 10, y: 10, width: 200, height: 200, fill: 'red' }); var path = ctx.path([[10, 10], [200, 200], [400, 10]], 'blue');
А многие библиотеки (Fabric, например) и SVG-пути поддерживают.
Во-вторых, простота и удобство создания кода. У svg логика строится на отдельных объектах, их свойствах и методах. Например, чтобы определить объект под курсором, нужно создать обработчик события для данного объекта (circle для станций метро), в котором можно поменять его свойства — цвет, масштаб (на картинке для значка станции «Ходынское поле» применен метод scale) и др. У канваса логика отрисовки построена на перерисовке всей карты. И для выделения отдельных объектов нужно перерисовывать и масштабировать всю карту. Кроме этого, канвас не хранит отрисованные объекты в памяти, их нужно отдельно сохранять в переменных (в dbcartajs в объекте mflood) и самому следить за ними (добавлять, удалять). SVG-изображение хранит отрисованные объекты в DOM-модели и к ним можно обращаться напрямую.
Та-даам.
var station = ctx.circle({ cx: 50, cy: 50, radius: 10, fill: 'red', stroke: 'red 2px' }); station.on('mouseover', 'animate', 'stroke', 'blue', 1000); station.on('mouseout', 'animate', 'stroke', 'red', 1000);
Вот так ещё можно:
station.on('mouseover', function(e){ this.animate('stroke', 'blue', 1000); this.scale(1.3); }); station.on('mouseout', function(e){ this.animate({ stroke: 'blue', scale: 1 / 1.3 }, 1000); });
В общем-то, на всех 4-х из мною перечисленных это спокойно реализуется.Keyten
06.10.2015 01:00Ах да, и забыл:
В-третьих, возможностей в svg намного больше, чем в канвасе, например, анимация, фильтры для изображений.
Анимацию в G2D я уже показал, в LibCanvas тоже есть, и в Fabric.
Фильтры в Fabric:
fabric.Image.fromURL('image.jpg', function(img) { img.filters.push(new fabric.Image.filters.Grayscale()); img.applyFilters(canvas.renderAll.bind(canvas)); canvas.add(img); });
Фильтры в g2d:
var image = ctx.image('image.jpg', 10, 10); image.filter('pixel', function(r, g, b){ var mid = (r + g + b) / 3; return [mid, mid, mid, 1]; });
Тут пример с Grayscale, встроенных в G2D пока нет.
Да и вообще реализовать, в общем-то, несложно, в отличие от SVG есть прямой доступ к пикселям.egaxegax
06.10.2015 23:57Приятно получить комментарий тоже от разработчика библиотеки для канваса. Только почему ни один пример не работает на http://graphics2d.js.org? Хотелось бы увидеть что-нибудь из вышеописанного в действии. В проекте graphics2d примеров тоже нет.
Keyten
09.10.2015 23:03Всё пофиксил, благодарю. Добавил ещё один пример, теперь можно оценить соотношение прыгающих зайчиков и FPS :).
Сейчас очень многое изменяю, хочется сделать более общей и более функциональной (а ещё добавить WebGL-рендер), поэтому последние версии немного неюзабельны, а на сайте многое немного не работает. Думаю, к ноябрю закончу.
MTonly
05.10.2015 00:49+1А ещё SVG автоматически адаптирует своё качество в зависимости от плотности точек дисплея (например, на 4K-мониторе с системным масштабом 200%). Векторная графика есть векторная графика.
Devgru
05.10.2015 13:00Для канвы это тоже делается на раз-два, см. функцию getRetinaRatio здесь.
MTonly
05.10.2015 19:32+1Ну да, можно выводить растровое изображение пропорционально бОльших размеров, вписывая его в пропорционально меньшую область (и надеясь на точное попадание каждого логического пиксела в пиксел физический — для нештриховой графики сейчас так и приходится делать), но зачем, если можно просто использовать векторную графику, именно для штриховых изображений подходящую идеально и адаптирующуюся под любую плотность точек автоматически и с гарантированным качеством? (Вопрос риторический.)
Lirein
05.10.2015 07:42+2На маломощном нетбуке наблюдаю обратную ситуацию — канвас версия очень сильно тормозит при масштабировании, очень инертная по задержкам (при наведении курсора на станцию) и т.п. SVG версия по сравнению с ней летает, скорость загрузки тоже немного выше чем Canvas версии.
Linux Mint 17.2, amd64, Firefox, Atom D525egaxegax
05.10.2015 23:30Да действительно, я уже и забыл, что в последних версиях канвасной карты метро я заменил отрисовку линий по координатам на фоновую картинку-скриншот с линиями. Отрисовываются только точки (прямоугольники) станций. Загружаться карта стала немного медленнее чем раньше (до v1.8). Зато намного быстрее стала работать на смартфоне особенно при перетаскивании и масштабировании. А SVG и правда быстрее.
alexpp
05.10.2015 09:38А можете дополнить карту дополнительными элементами — ССВ и депо? Например отсюда — trackmap.ru
stalkerg
Это проблема конкретной вашей реализации, а не самого канваса.
egaxegax
В канвасе можно перерисовать отдельный фрагмент. Но перерисованный фрагмент наложится на изображение. Можно стереть часть изображения перед наложением фрагмента, но тогда появится пустые области. Кроме того, довольно сложно каждый раз вычислить область наложения особенно при выводе текста несколько раз в одной области. Поэтому я имел в виду перерисовку всей картинки как базовый вариант работы с канвасом в динамике.
janitor
Ну, если правильная архитектура приложения, то ничего сложного нет.
stalkerg
При создании игр все эти проблемы давно давным решили…
Дам совет — лучше карту рисовать в буфер и скролиннг реализовывать уже по этому буферу, а не рисовать каждый раз, с отключением текста. :)
TimsTims
Ждём статью)
stalkerg
Мне бы собраться с мыслями и про Вангеры написать (там к слову этот подход во всю, каждый объект сам за собой чистил).