Отрисовка графических примитивов с помощью canvas


Уже далеко не новый html-элемент canvas сегодня поддерживается во всех нормальных браузерах. Если вы используете FireFox, Opera или Google Chrome последних версий, то проблем возникнуть не должно. Даже IE9 поддерживает canvas.

Сам элемент выглядит вот так:

<canvas id=”canv” width=640height=480”></canvas>


Если атрибуты width и height не заданы, то по умолчанию элемент создаётся размером 300 на 150 пикселей. При изменении высоты и ширины через CSS-свойства картинка будет масштабироваться.

Аварийное содержимое

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

Делается это очень просто: аварийное содержимое заключается в тег < canvas >. Вот так:

<canvas id="”canv”" width="”640”" height="”480”">
 Нужно шагать в ногу со временем!<br />
 Обновите, пожалуйста, браузер.
</canvas>


или так:

<canvas id="”canv”" width="”640”" height="”480”">
 <img src="”images/img.jpg”" alt="" />
</canvas>


Всё, что заключено в теге canvas пользователь увидит только тогда, когда его браузер не поддерживает этот элемент, в обратном случае браузер проигнорирует содержимое этого тега.

Получение контекста отрисовки

Изначально canvas пустой (полностью прозрачный). Для того, чтобы начать рисовать нам понадобится получить контекст отрисовки. Делается это вот так:

var canv = document.getElementById('canv'),
  g = canv.getContext(‘2d’);


Объект контекста и будет содержать методы для рисования. Для его получения мы использовали метод getContext. В качестве параметра он принимает строку ‘2d’, указывающею на то, что мы получаем двухмерный контекст отрисовки. Вероятно, что в скором будущем можно будет получать и трёхмерный контекст. Пока это возможно только в некоторых экспериментальных сборках Opera.

Проверка поддержки

Если браузер не поддерживает canvas, то при попытке получить контекст отрисовки возникнет ошибка. Чтобы этого не случилось, нужно проверять, существует ли метод getContext и получать контекст отрисовки и рисовать, только если он существует.

var canv = document.getElementById(‘canv’),
if(canv.getContext) {
  var g = canv.getContext(‘2d’);
  // далее рисуем
} else {
  // просим прльзователя обновить наконец-то браузер
}

Пространство координат

Чтобы начать рисовать на canvas, нужно иметь представления о системе координат холста. По-умолчанию она расположена не так, как мы привыкли. Ось OY направлена вниз, ось OX направлена вправо, а начало координат располагается в левом верхнем углу холста. Чем больше координата x объекта, тем правее он расположен, чем больше координата y — тем ниже.

Рисуем прямоугольники

Посмотреть демо

Для отрисовки прямоугольников существует два метода: fillRect(x, y, width, height) и srokeRect(x, y, width, height). Первый метод рисует заполненный прямоугольник, второй его границы. Первые два параметра x и y обоих методов задают положение верхнего левого угла прямоугольника, вторые два высоту и ширину прямоугольника. Для того, чтобы очистить прямоугольную область, сделав её полностью прозрачной используется метод clearRect(x,y,width,height). Нарисуем что-нибудь, используя эти методы. В примере я опустил проверку поддержки и аварийное содержимое для краткости, но я всё же настоятельно рекомендую их использовать.

<html>
  <head>
    <title>Rectangles</title>
    <script type="text/javascript">
      window.onload = function () {
        var canv = document.getElementById('canv'),
          g = canv.getContext('2d');
        g.fillRect(25, 25, 250, 250);
        g.clearRect(200, 200, 75, 75);
        g.strokeRect(210, 210, 85, 85);
      }
    </script>
  </head>
  <body>
    <canvas id="canv" width="640" height="480"></canvas>
  </body>
</html>

Рисуем прямые линии

Чтобы рисовать линии используют методы moveTo(x, y) и lineTo(x, y). Метод moveTo можно воспринимать как установку «кисти» в точку, координаты которой указаны в параметрах метода. Метод lineTo рисует линию из текущей точки, которая задаётся методом moveTo в точку, с координатами, указанными в параметрах метода. В отличие от прямоугольников, линии не появляются на холсте сразу после вызова соответствующего метода. Для того, чтобы они отобразились на холсте необходимо вызвать метод stroke. Всё, что мы нарисовали, используя метод lineTo, висит в оперативной памяти, даже после отрисовки. Метод stroke отрисовывает всё это. Чтобы избежать повторной отрисовки и освободить память используется метод beginPath. Если в ходе выполнения скрипта линии рисуются впервые, то этот метод можно не вызывать, но я рекомендую всё же это делать всё время, так как не всегда можно однозначно определить, не весит ли в памяти что-то не отрисованное.

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

var canv = document.getElementById('canv'),
  g = canv.getContext('2d');
 
g.beginPath();
 
//Перемещаемся в начальную точку рисования
g.moveTo(240, 240);
 
//Рисуем крышу
g.lineTo(320, 160);
g.lineTo(400, 240);
 
//Рисуем правую стену
g.lineTo(400, 400);
 
//Рисуем фундамент
g.lineTo(240, 400);
 
//Рисуем левую стену
 g.lineTo(240, 240);
 
//Рисуем черту под крышей
g.lineTo(400, 240);
 
//Не забываем про этот метод!
g.stroke();


Посмотреть демо

Для того чтобы закрасить отрисованный контур вместо метода stroke() используют метод fill(). Нарисуем заполненный треугольник

Посмотреть демо

var canv = document.getElementById('canv'),
  g = canv.getContext('2d');
 
g.beginPath();
 
g.moveTo(70, 400);
g.lineTo(570, 400);
g.lineTo(320, 70);
g.lineTo(70, 400);
 
g.fill();

Рисуем дуги

Для рисования дуг используется метод arc(x, y, radius, startAngle, endAngle, anticlockwise). x и y — это координаты центра круга, radius – радиус круга, затем начальный и конечный угол. anticlockwise – булево значение показывающее в каком направлении рисуется дуга. Если он равняется true, то дуга рисуется против часовой стрелки, если false, то по часовой.
Стоит обратить внимание на то, что углы задаются в радианах а не в градусах. Для перевода из градусов в радианы можно написать вот такую функцию:

function degToRad(deg) {
  return Math.PI * deg / 180;
}


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

Посмотреть демо

var canv = document.getElementById('canv'),
  g = canv.getContext('2d');
 
g.beginPath();
 
g.arc(320, 240, 200, 0, degToRad(360) /* Math.PI * 2 */, true);
 
g.stroke();

Рисуем кривые Безье и квадратичные кривые

Демо кривых Безье | Демо квадратичных кривых

Что это такое, лучше чем я объяснит википедия. Для рисования квадратичных кривых используется метод quadraticCurveTo(cp1x, cp1y, x, y). Здесь cp1x, cp1y – координаты контрольной точки, а x, y – координаты конечной точки. У кривой Безье, которая рисуется методом bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) две контрольные точки с координатами cp1x, cp1y и cp2x, cp2y. Для отрисовки этих кривых необходимо использовать метод stroke(), так же как и при отрисовки прямых и дуг. Нарисуем квадратичную кривую.

var canv = document.getElementById('canv'),
  g = canv.getContext('2d'),
 
 //Начальная точка
x0 = 20,
y0 = 300,
 
//Конечная точка
x = 620, 
y = 300,
 
//Контрольная точка
cpX = 250,
cpY = 100;          
 
g.beginPath();
 
g.moveTo(x0, y0);
g.quadraticCurveTo(cpX, cpY, x, y);
 
//Нарисуем прямые линии от начальной точки к контрольной
g.moveTo(x0, y0);
g.lineTo(cpX, cpY);
 
//и от контрольной точки к конечной
g.lineTo(x, y);
 
g.stroke();


Контрольная точка соединина с конечной и начальной точками для наглядности. Так проще понять зачем она нужна.

Нарисуем кривую Безье. Для наглядности опять соединим контрольные точки, здесь их две, с начальной и конечной точками соответсвенно.

var canv = document.getElementById('canv'),
  g = canv.getContext('2d'),
 
//Начальная точка
x0 = 20,
y0 = 300,
 
//Конечная точка
x = 620, 
y = 300,
 
//Первая контрольная точка 
cp1x = 100,
cp1y = 100,
 
//Вторая контрольная точка
cp2x = 300,
cp2y = 450;
 
g.beginPath();
 
g.moveTo(x0, y0);
g.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
 
//Нарисуем прямые линии от начальной точки к первой контрольной
g.moveTo(x0, y0);
g.lineTo(cp1x, cp1y);
 
//и от конечной к второй контрольной
g.moveTo(x, y);
g.lineTo(cp2x, cp2y);
 
g.stroke();


Сегодня я познакомил вас с самыми основами рисования на canvas‘e. Этот элемент уже используется для создания анимации, построения графиков и диаграмм, и даже для создания игр. Возможно, canvas со временем вытеснит flash, но пока отрисовка на canvas жутко тормозит и ест ресурсы, но браузеры совершенствуются и ситуация меняется. API для отрисовки неудобный, но уже есть мощные фреймворки такие как libCanvas и jCanvaScript, призванные облегчить работу на canvas.

Скачать демо и исходники

  • maxim

    вцелом неплохо, на первом курсе еще увлекался созданием игр на Turbo C, но мне всегда не нравилось что там стандартное разрешение 640х480 =) canvas в связке с js, наконец-то решит мою проблему, спасибо за статью.