SVG или Canvas? Сложности выбора

в категориях:
Версия для печатиВерсия для печати

Новые веб-технологии все шире используются браузерами, появляются решения, доступные для многих браузеров, например, Raphaёl для поддержки SVG, и ExCanvas для Canvas. Даже Internet Explorer начал понимать SVG — а какую поддержку мы можем увидеть в будущем! Наличие нескольких похожих технологий создают проблемы выбора подходящего решения.

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

Scalable Vector Graphics (SVG)

SVG — векторный графический формат, основанный на XML. SVG-контент может быть статическим, динамическим, интерактивным и анимированным — он очень гибок. Вы также можете изменять оформление SVG с помощью CSS и определять поведение объектов с помощью SVG DOM. И конечно, так как текст внутри SVG сохраняется в файле, он остается относительно доступным для использования. Также SVG-контент можно вставить непосредственно в (X)HTML с использованием элемента object.

Пример круга, созданного с помощью SVG

Ниже представлен пример круга, нарисованного с помощью SVG с использованием радиального градиента и простой анимации:

<svg version="1.1"
  width="320" height="320"
  xmlns="http://www.w3.org/2000/svg">
  <defs>
    <radialGradient id="circleGrad">
      <stop offset="0%"   stop-color="rgb(255, 255, 0)" />
      <stop offset="100%" stop-color="rgb(  0, 255, 0)" />
    </radialGradient>
  </defs>

  <ellipse fill="url(#circleGrad)" stroke="#000" cx="50%"
  cy="50%" rx="50%" ry="50%">
    <animate attributeName="rx" values="0%;50%;0%" dur="2s"
      repeatCount="indefinite" />
    <animate attributeName="ry" values="0%;50%;0%" dur="2s"
      repeatCount="indefinite" />
  </ellipse>
</svg>

Обратите внимание на то, что анимация в настоящее время работает только в Opera и браузерах, основанных на движке Webkit.

С помощью SVG вы можете получить намного больше, чем просто векторную графику и анимацию. Вы можете разработать высокоинтерактивное веб-приложение с программированием, расширенными анимационными событиями, фильтрами и почти всем, что захотите.

HTML5 Canvas

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

  • 2D-подход,
  • 3D-подход (WebGL).

Первый лучше внедрён и доступен во всех современных веб-браузерах (за исключением IE), в то время как второй находится на ранней стадии определения, имея лишь несколько экспериментальных реализаций.

Мы рассмотрим только 2D Canvas, так как она наиболее широко распространена. 2D Canvas позволяет вам использовать мощный API для выполнения быстрых операций рисования на растровых 2D-поверхностях. Не существует каких-либо файловых форматов, и вы можете рисовать только с использованием скриптов. При рисовании не используются узлы DOM — все состоит из пикселей. Это означает, что вы можете сконцентрироваться на рисовании без ограничений сложности изображения.
 

В примере ниже тот же круг, нарисованный с помощью канвы HTML 5:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Пример анимации на HTML-канве</title>
    <script type="text/javascript"><!--
window.addEventListener('load', function () {
  // Получить элемент канвы.
  var canvas = document.getElementById('myCanvas'),
      w = 4,
      h = 4,
      zoompx = 6,
      step = 'zoomin';

  if (!canvas || !canvas.getContext) {
    return;
  }

  // Получить 2d окружение канвы.
  var ctx = canvas.getContext('2d');
  if (!ctx) {
    return;
  }

  var K = 4*((Math.SQRT2-1)/3);

setInterval(function () {
  if (step == 'zoomin') {
    w += zoompx;
    h += zoompx;
  } else if (step == 'zoomout') {
    w -= zoompx;
    h -= zoompx;
  }

  if (w > canvas.width) {
    w = canvas.width;
    step = 'zoomout';
  } else if (w < 4) {
    w = 4;
    step = 'zoomin';
  }

  if (h > canvas.height) {
    h = canvas.height;
    step = 'zoomout';
  } else if (h < 4) {
    h = 4;
    step = 'zoomin';
  }

  // Создать радиальный градиент: x0, y0, r0, x1, y1, r1.
  // Начальные координаты (x0,y0) и радиус r0,
  // за которыми следуют конечные координаты (x1,y1) и радиус r1.
  var gradient = ctx.createRadialGradient(
      Math.round(w/2), Math.round(h/2), 0, Math.round(w/2), Math.round(h/2),
      Math.round(Math.min(w, h)/2));

  gradient.addColorStop(0, "#ff0");
  gradient.addColorStop(1, "#0f0");

  // Использование градиента в свойстве fillStyle.
  ctx.fillStyle = gradient;

  // Радиус и центр.
  var cx = w/2,
      cy = h/2,

      // Радиус*Kappa, для узлов кривых Безье
      rx = cx*K,
      ry = cy*K;

  ctx.setTransform(1, 0, 0, 1, 0, 0);

  ctx.clearRect(0, 0, canvas.width, canvas.height);

  ctx.setTransform(1, 0, 0, 1, Math.round((canvas.width - w) / 2),
    Math.round((canvas.height - h) / 2));

  ctx.beginPath();

  // startX, startY
  ctx.moveTo(cx, 0);

  // Узлы: cp1x, cp1y, cp2x, cp2y, destx, desty
  // обход по часовой стрелке: верхняя, правая, нижняя, левая
  ctx.bezierCurveTo(cx + rx, 0, w, cy - ry, w, cy);
  ctx.bezierCurveTo(w, cy + ry, cx + rx, h, cx, h);
  ctx.bezierCurveTo(cx - rx, h, 0, cy + ry, 0, cy);
  ctx.bezierCurveTo(0, cy - ry, cx - rx, 0, cx, 0);

  ctx.fill();
  ctx.stroke();
  ctx.closePath();
}, 20);
}, false);
    // --></script>
  </head>
  <body>
    <p><canvas id="myCanvas" width="320" height="320">Ваш браузер не поддерживает HTML 5 Canvas.</p>
  </body>
</html>

В Canvas 2D нет специальных функций для анимации — вы просто выполняете операции рисования определенным образом и в определенное время. Поэтому отрисовка круга выполняется заданной функцией каждые несколько миллисекунд.

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

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

Лучшим вариантом использования для канвы стал бы вывод динамической информации, например, интерактивных графиков и графиков анализа изображений. Например, ниже представлена демонстрация вычисления и отображения гистограмм изображений с использованием Canvas 2D API (для просмотра демо кликните по изображению):

Гистограмма изображения, создаваемая с помощью HMTL 5 Canvas

В этом примере загружается изображение из элемента img и выполняется подсчет пикселей с помощью Canvas 2D API. Подсчет пикселей выполняется для каждого из каналов изображения в выбранном пользователем цветовом пространстве (RGB, HSV или CMYK). Как только изображение было проанализировано, второй элемент canvas используется для отображения гистограммы на основе полученных данных.

Для чего необходим Canvas 3D? С помощью Canvas 3D вы можете рисовать 3D-объекты с текстурами и шейдерами и анимировать их. Вы можете сделать 3D-игры и веб-приложения 3D-моделирования (например, визуализацию продукции — автомобили, запчасти и т.п.). Веб-браузер выполняет отрисовку сцены с использованием аппаратного обеспечения, если это возможно.

Сравнение SVG и HTML 5 Canvas

Следующие таблицы дадут вам представление о преимуществах и недостатках SVG и Canvas:

Преимущества

Canvas SVG
  • Высокая производительность при отрисовке любых 2D объектов.
  • Стабильная производительность — всё есть пиксель. Производительность падает только при увеличении разрешения изображения.
  • Можно сохранить полученное изображение в PNG или JPG файл.
  • Лучше всего подходит для создания растровой графики (например, в играх, фракталов и т.п.), редактирования изображений и операций, требующих манипулирования на уровне пикселей.
  • Нет зависимости от разрешения — SVG лучше подходит для кроссплатформенных пользовательских интерфейсов, так как позволяет масштабировать изображение при различных разрешениях экрана.
  • SVG очень хорошо поддерживает анимацию. Элементы могут быть анимированы с использованием описательного синтаксиса или с помощью JavaScript.
  • Можно получить полный контроль над каждым элементом, используя SVG DOM API в JavaScript.
  • SVG хранится в формате XML, что предоставляет больше возможностей браузерам по обеспечению доступности SVG документов по сравнению с элементом canvas. Таким образом, SVG выглядит лучшим решением для пользовательских интерфейсов веб-приложений.

Недостатки

Canvas SVG
  • Отрисовка основана на пикселях.
  • Не существует API для анимации. Вам придется прибегать к использованию таймеров и других событий для обновления канвы.
  • Слабые возможности по рендерингу текста.
  • Возможно, не самый лучший выбор, когда доступность имеет решающее значение. Канва предоставляет вам поверхность для рисования в выбранном контексте (2D и 3D). Можно указать альтернативный контент внутри элемента canvas, который будет показан браузером при невозможности отображения графики. Кроме того, вы можете выполнить проверку доступности выбранного Canvas API с помощью JavaScript. На основе этого вы можете обеспечить различную функциональность для пользователей браузеров с разной поддержкой HTML 5 Canvas.
  • HTML 5 Canvas не подходит для создания веб-сайтов или интерфейсов веб-приложений, так как пользовательские интерфейсы обычно должны быть динамическими и интерактивными, а Canvas требует от вас постоянной перерисовки каждого элемента в интерфейсе.
  • Низкая скорость рендеринга при увеличении сложности документа (рисунка), так как используется модель DOM
  • Скорее всего, SVG не подходит для таких приложений как игры. Возможно лучшим выбором будет комбинация HTML Canvas + SVG.

Какую из технологий выбрать?

Каждая технология имеет свою область применения.

HTML 5 Canvas следует использовать для:

  • Редактирования изображений: обрезки, изменения размеров, фильтров (удаления эффекта красных глаз, создания эффекта сепии, изменения цветности или яркости)
  • Создания растровой графики: визуализации данных, создания фракталов и графиков функций.
  • Анализа изображений: создания гистограмм и т.п.
  • Создания игровой графики, такой как спрайты и фоны.

SVG следует использовать для:

  • Создания пользовательских интерфейсов веб-приложений, независимых от разрешения экрана.
  • Высокоинтерактивных анимированных пользовательских интерфейсов.
  • Графиков и диаграмм.
  • Редактирования векторных изображений.

Когда не следует использовать эти технологии? Существуют обычные решения на основе HTML и CSS для таких вещей, как закругленные углы, переходные эффекты, тени и прозрачность. Так же следует рассмотреть библиотеки JavaScript, например, jQuery UI. Спросите себя, нужны ли вам SVG или Canvas для решения задач вашего проекта, или можно обойтись HTML и CSS.

Заключение

В этой статье мы рассмотрели различия между двумя, казалось бы, аналогичными веб-технологиями — SVG и HTML5 Canvas. Каждая технология имеет свои сильные и слабые стороны, поэтому важно определить для себя необходимый функционал. Однако часто их объединение в рамках одного приложения может дать хорошие результаты.

Статья основана на публикации "SVG or Canvas? Choosing between the two".
Ваша оценка: Нет Средняя: 8.8 (32 голосов)

Комментарии

Спасибо! Очень полезная и доступная статья!

Здравструйте!статьи не плохие, но объяснени мало, почему нет элементарной статьи как можно нарисовать прямоугольник с закругленными углами?

Проще всего использовать какую-нибудь библиотеку, например, Raphael. В ней есть метод addRoundedCorner, который подойдет для рисования закругленных углов.

Функция отрисовки прямоугольника с закругленными углами canvas

На чистом JS можно создать функцию:

/**
* Функция отрисовки прямоугольника с закругленными углами.
* Если не указывать последние три параметра, функция нарисует прямоугольник
* без заливки с радиусом углов в 5 пикселей
* @param {CanvasRenderingContext2D} ctx
* @param {Number} x Верхняя левая координата x
* @param {Number} y Верхняя левая координата y
* @param {Number} width Ширина прямоугольника
* @param {Number} height Высота прямоугольника
* @param {Number} radius Радиус углов. По умолчанию 5;
* @param {Boolean} fill Нужна ли заливка прямоугольника?
* @param {Boolean} stroke Нужна ли граница у прямоугольника?
*/
function roundRect(ctx, x, y, width, height, radius, fill, stroke) {
    if (typeof stroke == "undefined" ) {
      stroke = true;
    }
    if (typeof radius === "undefined") {
    radius = 5;
  }
  ctx.beginPath();
  ctx.moveTo(x + radius, y);
  ctx.lineTo(x + width - radius, y);
  ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
  ctx.lineTo(x + width, y + height - radius);
  ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
  ctx.lineTo(x + radius, y + height);
  ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
  ctx.lineTo(x, y + radius);
  ctx.quadraticCurveTo(x, y, x + radius, y);
  ctx.closePath();
  if (stroke) {
    ctx.stroke();
  }
  if (fill) {
    ctx.fill();
  }
}

Отрисовка прямоугольника с помощью созданной функции:

// Предполагается, что элемент с "rounded-rect" имеет размеры 500x350
var ctx = document.getElementById("rounded-rect").getContext("2d");
// При таком вызове прямоугольник будет иметь только границу и углы с радиусом в 5 пикселей
roundRect(ctx, 5, 5, 50, 50);
// Чтобы изменить окраску прямоугольника измените параметры контекста canvas
ctx.strokeStyle = "rgb(255, 0, 0)";
ctx.fillStyle = "rgba(255, 255, 0, .5)";
roundRect(ctx, 100, 5, 100, 100, 20, true);
// или такие цвета
ctx.strokeStyle = "#2d6";
ctx.fillStyle = "#abc";
roundRect(ctx, 100, 200, 200, 100, 50, true);

Результат работы скрипта:

А ещё можно воспользоваться CSS3: border-radius: 5px 5px 5px 5px; ))

Ну CSS3 это конечно хорошо. Но в SVG то его не встроишь )

Как можно использовать SVG для отображения динамических мнемосхем можно посмотреть на сайте svgmnemo.ru

Как с помощью canvas отрисовывать различные гаджеты на веб страницах - jsgadget.ru