HTML5 INSIGHT


* Это четвертая статья (не считая практических отступлений) из серии погружения в HTML5, рассказывающей об основах HTML5. Рано или поздно они сложатся в единое изложение, которое можно будет удобно читать, сидя на диванчике и перелистывая странички поглядывая в свой Kindle.*

Canvas and SVG

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

История развития графики в интернете требует, конечно, отдельного повествования, но важно отметить, что приход HTML5 (и многих новых модулей CSS3) представляет собой значительный поворот в этой истории. HTML5 многое переворачивает с ног на голову и активно побуждает дизайнеров и разработчиков пересматривать свои взгляды на используемые технологии и подходы.

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

Контекст технологий и возможностей

Нам интересны два аспекта, делающих использование Canvas и SVG особенно интересным и перспективным: традиционно используемые практики и производительность. Давайте начнем с первого.

Практики и традиции

Как мы помним из введения, мастерство обращения с растрами и векторами, создания шедевров анимации и решения других интересных задач, связанных с графическим дизайном, постоянно развивалось и передавалость от мастера подмастерью через усные традиции, практику и летописные рассказы.

В мире до HTML5 можно выделить три основных направления работы с графикой (со своими возможностями и ограничениями):

  • Статичная графика. Филигранное искусство работы с каждым пикселем, оптимизации до последнего байта. Веселые анимированные гифки и упорная борьба за прозрачность в старых браузерах. И, конечно, генерация графики на сервере.
  • Flash, flash, flash. Широко расправивший крылья мир богатых анимаций и программируемой графики в вебе, игрушек в браузере и неожиданных всплывающих баннеров. Целое поколение флеш-аниматоров и флеш-разработчиков!
  • JavaScript, HTML, CSS. В орбиту используемых инструментов включаются возможности CSS и JavaScript для динамичного изменения графики и создания различных эффектов. Спрайты и наложения изображений. И куда же без сотни хитрых способов сделать скругленные уголки?

Узнали себя?

Я повторюсь, годами (!) нарабатывались практики, набивались шишки, искались обходные пути и хитрые приемы — и все это, чтобы сделать хорошо конечному пользователю, то есть нам с вами. Не все было идеально, не все было гладко, многих возможностей хотелось, но не хватало.

В сущности, сильно не хватало двух вещей — векторной графики, широко поддерживаемой всеми браузерами, и возможности генерировать графические изображения на клиенте без необходимости использовать сервер либо Flash или Silverlight. И тут…

Бум!

Появляется HTML5 со встроенным API для генерации графики на клиенте и интеграцией с давно существующим форматом для векторной графики — SVG. Как только маркетинговая машина заработала на полную катушку, все производители браузеров включились в игру под названием “HTML5”. А разработчикам и дизайнерам теперь нужно учить новые технологии, придумывать новые возможности их применения и адаптировать и интегрировать наработанные ранее практики в новом контексте.

(Причины, по которым я акцентирую столь большое внимание на наработанном опыте банальны: во-первых, мы становимся свидетелями большой трансформации в вебе, в ходе которой менеяется и обновляется технологический стек, а значит, пора браться за учебники; и, во-вторых, накопленная практика не пропадает - но быстрыми темпами переносится на платформу HTML5 и адаптируется в новых реалиях. Не пропустите момент!)

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

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

Причем если раньше производительность браузера рассматривалась преимущественно в контексте скорости движка JavaScript и иногда манипуляций с DOM, то теперь узким горлышком становился движок рендеринга. И с этим надо было что-то делать.

Рыбки. Рыбки произвели фурор! Когда Microsoft показала первую предварительную версию грядущего IE9 с аппаратным ускорением графики, это многих (в том числе производителей других браузеров) заставило хорошо задуматься. Конечно, всегда есть над чем еще работать, но это действительно был огромный рывок вперед в области динамичной графики в вебе.

Хотелки разработчиков и дизайнеров начали воплощаться в жизнь. Причем сегодня работа активно ведется с двух направлений: со стороны технологий и стандартов и со стороны их реализации и повышения производительности. Давайте смотреть, что к чему.

Что такое Canvas и почему это круто?

Canvas — это растровый холст, на котором можно рисовать через специальный API для JavaScript, предоставляющий базовые возможности: отрисовку примитивов и текста, побитовый доступ к изображению, вывод изображений и афинные преобразования контекста отрисовки.

Спецификации

API для Canvas описывается в отдельной спецификации – HTML Canvas 2D Context, в то время как спецификация HTML5 задает непосредственно сам холст, вставляемый на страницу с помощью тега <canvas>.

Нюанс, который также является важным и активно обсуждается в W3C, — обеспечение Accesibility с Canvas, но это, определенно, не тема для отдельного обсуждения, выходящего за рамки данного введения.

Так в чем крутость Canvas?

Есть три вещи, которые мне особенно нравятся в Canvas:

  1. Понятность. Canvas прост. Если вы знаете JavaScript и имели опыт работы с графикой через примитивные 2D-API, разобраться с Canvas вам не составит труда. API Canvas действительно прост: есть около 40 методов и 20 атрибутов, которые вы легко можете разбить для себя на несколько групп (см. например, вот эту шпаргалку).
  2. Скорость. Canvas быстр. Примитивен и потому быстр. С поддержкой аппаратного ускорения и потому быстр. Canvas спроектирован так, чтобы быть быстрым, хотя какие-то вещи и могут на первый взгляд показаться непрактичными (например, нужно сначала нарисовать весь путь, прежде чем его прочертить).
  3. Интеграция. Canvas сочетаем — это обычный html(5) элемент и его можно вставить в любоем место страницы. Canvas можно комбинировать с видео, изображениями и другими canvas. Ему можно даже сделать круглые уголки.

Давайте смотреть примеры!

Как готовить Canvas?

Мы рассмотрим три примера, которые хорошо показывают характер взаимодействия с Canvas и некоторые базовые возможности.

Stop? It is just the beginning!

В этом примере мы нарисуем простой знак Stop. Для начала нам нужен холст, на котором мы будем рисовать:

<canvas id="myCanvas" width="200" height="200" />

Зная id canvas-элемента, необходимо получить контекст для рисования:

var ctx = document.getElementById("myCanvas").getContext("2d");

Вся остальная работа осуществляется уже относительно этого контекста:

// Ширина и высота холста
var width = ctx.canvas.width;
var height = ctx.canvas.height;
            
// Радиус и центр круга
var radius = 0.4 * width;
var cx = width / 2;
var cy = height / 2;
            
// Делаем путь для круга от 0 до 2PI
ctx.beginPath();
ctx.arc(cx, cy, radius, 0, Math.PI * 2);
ctx.closePath();
            
// Устанавливаем отрисовку с тенью
ctx.shadowBlur = 10;
ctx.shadowColor = "black";
            
// Устанавливаем ширину и цвет линии и отрисовываем
ctx.lineWidth = 25;
ctx.strokeStyle = "#f00";
ctx.stroke();
            
// Убираем тень
ctx.shadowColor = "transparent";
            
// Создаем радиальный градиент для заливки
var gradient = ctx.createRadialGradient(cx, cx, 0, cx, cy, radius);
gradient.addColorStop(0, "#ddd");
gradient.addColorStop(1, "#eee");
            
// Устанавливаем градиент и делаем заливку
ctx.fillStyle = gradient;
ctx.fill();
            
// Устанавливаем стили текста и центрирование
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.font = "bold 55px 'Segoe UI', 'Tahoma', sans-serif";
ctx.fillStyle = "#333";
            
// Выводим надпись
ctx.fillText("STOP", cx, cy);

Результат:

В этом примере надо обратить на три момента:

  1. Сначала создается путь и только потом он отрисовывается или заливается с нужной закраской. Это важно с точки зрения оптимизации, так как, фактически, API для Canvas побуждает сначала целиком подготовить путь и только после этого с ним что-то делать.
  2. Практически все парамерты носят глобальный характер, например, если тень явно не отключить, все последующие отрисовки будут с тенью. Установленный стиль линии будет работать для всех послудующих отрисовок линий и т.д. (В Canvas также есть возможность запоминать и восстанавливать текущие настройки глобальных параметров.)
  3. Для установки стилей есть различные варианты: задание цвета в формате, аналогичном правилам CSS, создание градиента и использование шаблона.

Папоротник

Переходим к классике основ изучения компьютерной графики! Давайте посмотрим, как нарисовать фрактальный лист папоротника с помощью Canvas.

Как и в предыдущем примере мы работаем с небольшим canvas-элементом:

<canvas id="myCanvas" width="200" height="200" />

Для описания папоротника нам понадобится матрица афинных преобразований, каждое из которых будет применяться с некоторой вероятностью — разобраться в математических тонкостях оставляю на усмотрение читателя.

// Афинные преобразования для каждой из вероятностей
var barnsleyMatrix = [[    0,   0,     0, 0.16, 0,    0],
                      [ 0.85, 0.04,-0.04, 0.85, 0, 1.60],
                      [ 0.20,-0.26, 0.23, 0.22, 0, 1.60],
                      [-0.15, 0.28, 0.26, 0.24, 0, 0.44]];
            
// Суммы вероятностей (0.01, 0.85, 0.07, 0.07)
var probability = [0.01, 0.86, 0.93, 1.0];
            
// Контекст для работы
var ctx = document.getElementById("myCanvas").getContext("2d");
            
// Ширина и высота холста
var width = ctx.canvas.width;
var height = ctx.canvas.height;
            
// Пиксели для изображения
var pixels = ctx.createImageData(width, height);
            
var iterations = 50000;
var p, n;
var x = 0.0;            
var y = 0.0;
var xn, yn, xp, yp, j;
            
// Итерационный процесс
for (var i = 0; i < iterations; i++) {
    p = Math.random();                
    n = 0; while (p > probability[n]) n++;
                
    // Новые координаты
    xn = barnsleyMatrix[n][0] * x + barnsleyMatrix[n][1] * y + barnsleyMatrix[n][4];
    yn = barnsleyMatrix[n][2] * x + barnsleyMatrix[n][3] * y + barnsleyMatrix[n][5];
    x = xn;
    y = yn;
                
    // Переводим в экранные координаты
    xp = width/2 + Math.floor( x * 20);                
    yp = height - Math.floor(y * 20);
                
    // Находим место в одномерном массиве пикселей
    j = (yp * width + xp) * 4;
    // Устанавливаем значения для компонент RGBA
    pixels.data[j + 0] = 0;
    pixels.data[j + 1] = 180;
    pixels.data[j + 2] = 0;
    pixels.data[j + 3] = 255;
}

// Записываем итоговый массив пикселей 
ctx.putImageData(pixels, 0, 0);

Результат:

В этом примере надо обратить внимание на два момента:

  1. Доступ к пикселя осуществляется не в прямом виде, а через выгружаемый и записываемый массив пикселей (окно), причем операции чтения и записи разнесены в разные функции и во времени. Опять-таки, API побуждает разработчиков сначала произвести необходимые изменения в пикселях и уже после этого массово внести изменения вместо того, чтобы отдельно читать и записывать каждый из пикселей.
  2. Массив, с которым идет работа, одномерный (хотя у объекта типа ImageData и определены ширина и высота), причем в нем последовательно хранятся не просто пиксели, а значения по каждому из каналов для каждого из пикселей. Другими словами, на каждый пиксель приходится четыре элемента массива (RGBA) со значениями от 0 до 255.

Кстати, как я уже писал в начале, Canvas может легко сочетаться с обычными изображениями и даже видео, в частности, это означает, что на Canvas можно проектировать картинку или текущий кадр видео-потока. В сочетании с доступом к отдельным пикселям, это позволяет делать анализ изображений непосредственно на клиенте с помощью JavaScript.

Гипно-спираль

Наконец, давайте посмотрим на еще несколько важных аспектов работы с Canvas — трансформации контекста отрисовки. И для этого мы нарисуем гипнотическую спираль.

<canvas id="myCanvas" width="200" height="200" />

Прежде всего, нам понадобится функция для отрисовки спирали (тут вам уже практически все должно быть знакомо):

// Отрисовка спирали
function drawSpiral(context)
{
    var cx = 0;
    var cy = 0;

    // Количество звеньев
    var iterations = 500;

    context.moveTo(cx,cy);
    
    var x2 = cx, y2 = cy;

    for (var i = 0; i <= iterations; i++)
    {
        var angle = i / 10; // radians
        var radius = angle * 2;

        var x = cx + radius * Math.cos(angle);
        var y = cy + radius * Math.sin(angle);

        context.beginPath();
        
        var val = Math.floor(radius * 3);
        // Затухание спирали
        if (val > 255) val = 255;
        context.strokeStyle='rgb(' + val + ',' + val + ',' + (255) + ')';

        // Отрисовка звена
        context.moveTo(x2, y2);
        context.lineTo(x, y);        
        context.stroke(); 

        x2 = x;
        y2 = y;
    }
}

Теперь надо заставить ее вращаться – в принципе, для этого есть три решения:

  1. Можно просто поворачивать картинку (например, с помощью трансформаций CSS).
  2. Можно перерисовывать спираль, добавляя сдвиг угла поворота.
  3. Можно перерисовывать спираль как есть. Но виртуально поворачивать систему координат.

Последнее мы и будем делать.

// Контекст для работы
var ctx = document.getElementById("myCanvas").getContext("2d");
            
// Ширина и высота холста
var width = ctx.canvas.width;
var height = ctx.canvas.height;

// Стиль линии
ctx.lineCap = 'round';
ctx.lineWidth = 8; 
            
// Переносим начало координат в центр            
ctx.translate(width / 2, height / 2);
                    
// Ставим таймер
setInterval(function () {
    // Очищаем экран
    ctx.clearRect(-width / 2, -height / 2, width, height);
    // Поворачиваем систему координат
    ctx.rotate(-Math.PI / 180 );
    // Рисуем спираль
    drawSpiral(ctx);
}, 17);

Результат (в жизни она еще вращается):

В этом примере надо обрабить внимание на следующие моменты:

  1. Вместо того, чтобы поворачивать непосредственно спираль, мы виртуально поворачивали контекст отрисовки. Такой прием позволяет описать отрисовку спирали в удобных локальных координатах (заметили, что мы ее рисовали относительно центра cx = cy = 0?), а трансформацию вынести на внешний уровень. Также с помощью метода translate мы сместили начало координат в центр экрана.
  2. Canvas — примитивен. Canvas растровый и помнит только свое последнее состояние в виде массива пикселей. Мы не можем получить доступ к нарисованным линиям как отдельным объектам, которые можно было бы повернуть. Мы видим только последний слепок и чтобы нарисовать что-то новое (обновление экрана), надо делать перерисовку (через очистку экрана или поверх).

Canvas — это весело! Двигаемся дальше — к SVG.

Что такое SVG и почему это тоже круто?

SVG = Scalable Vector Graphics, или по-русски масштабируемая векторная графика, — стандарт (и язык) описания векторной и смешанной графики в формате XML. В спецификации HTML5 SVG присутствует как нативный тег <svg> с отсылкой уже на соответствующий стандарт.

Надо сказать, что SVG появился не сегодня, и не вчера, и не вместе с HTML5, а в общем-то давально давно – еще в 2001 году, а работы над SVG велись с 1999 года. Сегодня, SVG поддерживается большинством популярных векторных графических редакторов, из бесплатных рекомендую Inkscape.

SVG, как же я тебе рад!

Не вдаваясь в историю развития SVG (кстати, вторая редакция текущего стандарта, SVG 1.1, была окончательно одобрена 16 августа 2011 года), не могу не сказать пару слов о том, почему этот стандарт стал столь актуальным сегодня, хотя по факту использовался и заметно раньше. На мой взгляд, все дело в трех ключевых вещах:

  1. Маркетинг вокруг HTML5. SVG, формально включенный в состав HTML5, стал хорошей красной тряпочкой для демонстрации преимуществ новой версии стандарта. HTML5 позволяет работать с векторной графикой — это звучит слишком хорошо, чтобы умалчивать сей замечательный факт. Маркетинг, в свою очередь приводит ко второму фактору.
  2. Поддержка в браузерах. Производители браузеров не могут игнорировать тот факт, что им нужно реализовывать HTML5, если они хотят оставаться на плаву в браузерном рынке. Поэтому сегодня мы видим базовую поддержку SVG во всех основных браузерах, причем местами и с поддержкой аппаратного ускорения при отрисовке. Но маркетинга, конечно, было бы мало для того, чтобы браться за SVG, если бы не третий фактор.
  3. SVG — это круто! На самом деле, если еще несколько лет назад SVG рассматривался преимущество как стандарт для описания графики, то сегодня на него смотрят уже значительно шире. Потенциально, SVG — это не просто квадратики и кружочки с градиентными заливками, звездочки и фрагменты текста, но и возможность описания интерфейса для интерактивного взаимодействия, платформа для анимаций и визуализации данных. В контексте роста интереса к разработке веб-приложений роль SVG будет тоже расти.

К замечательным особенностям SVG также нужно отнести то, что базируясь на XML, вставленная в страницу SVG-графика имеет DOM-представление, которое можно изменять через JavaScript и настраивать отдельные свойства через CSS. Я уже говорил, что это круто?

Кухня SVG

Давайте начнем с простой задачи — посмотрим на примере, что из себя представляет SVG-графика и как ее вставить на страницу.

Show just begins!

Для начала нам понадобится SVG-картинка. Вы ее можете нарисовать в графическом редакторе или ручками в блокноте из известных тегов:

<?xml version="1.0" encoding="utf-8" ?>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200px" height="200px" viewBox="0 0 200 200">
    <circle cx="102" cy="102" r="80" style="fill:#333" />
    <circle cx="100" cy="100" r="80" style="fill:#00aad4" />
    <circle cx="100" cy="100" r="65" style="fill:#eee" />
    <text x="40" y="110" style="font-size:22px;fill:#000000;font-family:Segoe UI;" >Don`t STOP!</text>
</svg>

Как видно из кода, у нас есть три кружка и некоторая надпись. Теперь, чтобы вставить это изображение на страницу, достаточно сослаться на соответствующий файл, например, в теге img:

<img src="dont-stop.svg" />

В результате вы должны увидеть такую картинку:

Изображения в формате SVG можно также вставлять через теги object или embed, однако, что в этом случае, что в случае с img важно помнить, что вставленная картинка не будет предоставлять наружу возможность взаимодействовать через JavaScript или SVG.

Обратите также внимание на то, что описание стилей для различных элементов очень сильно похоже на привычную вам работу с CSS для обычных элементов HTML-разметки.

Также важным моментом является то, что описание SVG принципиально текстовое, а значит может индексироваться поисковиками, которые умеют вытаскивать из картинок текстовую информацию (например, внутренние подписи).

Давайте сделаем что-нибудь с анимацией?

Покачаемся?

На сайте “The Noun Project” собрана большая коллекция различных SVG иконок. Среди них должны быть качели. В качелях спрятано пасхальное яйцо — при наведении мыши качели начинают качаться! Как это сделано?

Начнем с того, как выглядят качели изнутри (так выгляди SVG-файл, экспортированный из Adobe Illustrator):

<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 15.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
	 width="100px" height="54.805px" viewBox="0 0 100 54.805" enable-background="new 0 0 100 54.805" xml:space="preserve">
<g id="rotator" transform="rotate(0)">
	<circle cx="14.466" cy="17.737" r="4.264" />
	<circle cx="77.027" cy="4.167" r="4.264" />
	<path d="M 77.207 27.417 l -1.003 4.827 l 4.959 1.267 l 4.274 -7.878 L 100 22.474 l -1.143 -5.267 l -5.006 1.085 c 1.573 -3.747 -1.045 -5.289 -1.045 -5.289 L 82.312 6.087 l -4.217 3.005 l -4.084 6.25 c 0 0 -1.974 3.023 -0.126 4.636 l 0.192 2.604 L 24.779 33.273 l -0.903 -2.447 c 1.013 -2.233 -2.036 -4.167 -2.036 -4.167 l -6.306 -3.996 l -5.082 -0.989 L 3.764 32.316 c 0 0 -1.747 2.488 1.239 5.246 L 0 38.648 l 1.142 5.269 l 14.562 -3.158 l 7.155 5.398 l 3.989 -3.207 l -2.913 -3.978 L 77.207 27.417 Z M 20.043 34.301 l -5.588 -2.679 l 1.379 -4.267 l 5.61 2.643 l 1.367 3.702 L 20.043 34.301 Z M 78.814 21.554 l -2.771 0.602 l -0.29 -3.938 l 4.014 -4.728 l 3.022 3.31 L 78.814 21.554 Z" />
</g>
	<polygon points="49.999,33.319 44.807,37.859 44.807,54.804 50,54.804 55.193,54.804 55.193,37.859" />
</svg>
</svg>

(Конечно, если быть до конца честным, это не от файл, который вы можете скачать напрямую с сайта. И если вы скачали файл, то легко увидите разницу. Содержимое этого примера можно вытащить из текста страницы ;) Я также добавил в этом примере id для группирующего элемента g.)

В этом примере верхняя часть качелей отделена от нижней и объединена в общую группу. Именно она нас и интересует. Вы легко можете заметить атрибут transform со свойством “rotate(0)” и, наверняка, уже догадались, что будет дальше.

Внутри SVG-документа можно писать код на JavaScript! Вставьте сразу после тега svg вставьте следующий код:

<script type="text/javascript">
    window.onload = function() {    
        var g = document.getElementById("rotator");
        
        var i = 0;
        var timer = setInterval(function() {
            var rad = i++ / 360 * Math.PI * 2;
            var rotateVal = 14 * Math.sin(10 * rad - Math.PI / 2) + 12;
            g.setAttribute("transform", "rotate(" + rotateVal + " 50 27)");      
        }, 40);    
    };</script>

Осталось запустить документ. Правда, если вы его вставить картинкой (img), качели вращаться не будут, так как браузер не разрешит исполнение JavaScript-кода внутри картинки. Другое дело вставленный объект!

<img src="seesaw.svg" />        
<embed src="seesaw.svg" type="image/svg+xml" width="100" height="55" />                
            

Результат:

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

Давайте теперь вставим SVG непосредственно внутрь страницы?

Играем в Громова и Собянина!

Первым делом, вам понадобится карта административного деления Московской области.

Я не буду приводить ее внутренее содержимое тут, но из содержимого файла нам надо извлечь все, кроме заголовочного тега xml-файла и подчистить содержание внутри тега svg. Также можно удалить defs-блок вместе с CSS-правилами. В таком виде его можно спокойно вставить внутрь обычной html-страницы:

<svg width="400px" height="400px" viewBox="0 0  25220 23850">
    <g id="Layer_x0020_1">
        <metadata id="CorelCorpID_0Corel-Layer"/>
        <g id="_143023512">
    ... 
</svg>

В начале страницы давайте добавим несколько стилей, которые нам понадобятся дальше:

<style>
    .moscow, .fil7 { fill: red; }
    .fil1 {fill:none}
</style>
            

Теперь самое время перейти к тому, чтобы добавить немного логики. Чтобы упростить себе задачу, давайте добавим на страницу ссылку на jQuery:

<script src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.5.1.min.js" type="text/javascript"></script>

Теперь нужно написать небольшую логику, которая по нажатию на тот или иной регион будет перекрашивать его в другой цвет, включая или не включая в состав Москвы:

$(function(){
    $("#_143023512 polygon").each(function (i) {
        $(this).click(function(){
            var classes = this.getAttribute("class");

            if (new RegExp('\\bmoscow\\b').test(classes)) {
                classes = classes.replace(" moscow", "");
            } else {
                classes = classes + " moscow";
            }

            this.setAttribute("class", classes);	                    
        });
    }); 
});

Теперь вы можете сами решить, какими будут новые границы Москвы! (А если найдете детальную карту мира, сможете вообще перекроить все страны!)

Из этого примера нужно сделать два вывода:

  1. SVG отлично встраивается в HMTL5-документы и интегрируется с CSS и JavaScript через DOM.
  2. Сегодня не все так гладко, как хотелось бы. В частности, т.к. между интерфейсами для доступа к css-классам элементов SVG и HTML есть различия, полноценно натравить на SVG популярные библиотеки оказывается проблематичным.

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

Canvas vs. SVG

Из наших примеров, вы, наверняка, уже прочувствовали ключевые различия, поэтому мне остается только суммировать все в одном месте.

  • Canvas — растровый холст с доступом к отдельным пикселям, хранящий только последнее свое состояние, которое можно вытащить в виде массива значений цвета и прозрачности (RGBA) для разных пикселей. SVG — векторное масштабируемое изображение с доступом к отдельным объектам, легко поддающееся индексации.
  • Для работы с Canvas есть специальный API с набором примитивных функций. Для работы с внутренностями SVG можно использовать DOM и CSS.
  • JS-код для Canvas пишется отдельно от элемента <canvas>. JS-код для SVG можно как писать отдельно, так и вставлять прямо внутрь SVG-документа.
  • И то, что мы не обсуждали подробно: на Canvas можно спроектировать изображение или видео, но не элемент SVG.

Что и когда следует использовать?

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

Canvas безальтернативно следует использовать для обработки изображений и видео, хорошо подохдит для сложных сцен с множеством объектов и можно хитро использовать в веб-рекламе.

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

Обе технологии, можно спокойно применять для отрисовки графиков и диграмм и для двумерных игрушек.

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

В остальном — надо смотреть на то, с помощью чего конкретную вашу задачу будет решить проще всего.

p.s. Пожалуйста! Пожалуйста, никогда не делайте баннеры на HTML5.

p.p.s. Как бы там ни было, злая сторона меня подсказывает, что на рекламе средствами HTML5 можно сделать неплохой бизнес ;)