Рисование в html5. Подготовка к рисованию. Стираем объекты из Canvas

Интерактивные фигуры

Холст является незапоминаемой (non-retained) поверхностью рисования. Это означает, что холст не отслеживает выполняемые на нем операции рисования, он фиксирует лишь конечный результат этих операций - набор разноцветных пикселей, составляющих его содержимое.

Например, если нарисовать красный квадрат в центре холста методом stroke() или fill(), как только завершится выполнение этого метода, квадрат станет ничем иным, как блоком красных пикселов. Он может казаться вам квадратом, но холст не обладает информацией об этом.

Такой подход позволяет сделать процесс рисования быстрым, но он также усложняет задачу создания интерактивной графики. Допустим, что нам нужно разработать более интеллектуальную версию программы рисования, которую мы рассмотрели в статье "Создание простой программы рисования" . В частности, мы хотим, чтобы кроме линий в ней также можно было бы рисовать прямоугольники. (Но это еще легко!)

Более того, мы хотим не только рисовать прямоугольники, но также и выбирать нарисованные прямоугольники, перетаскивать их на новое место, изменять их размеры, цвет и т.п. Но для того чтобы реализовать все эти возможности, нам нужно решить несколько проблем. Прежде всего, как нам узнать, что пользователь щелкнул на прямоугольнике? Потом, как нам узнать все подробности о данном прямоугольнике - его координаты, размер, цвет контура и заполнения? Наконец, как нам выяснить подробности обо всех прочих фигурах на холсте? Что нам необходимо знать, если мы хотим изменить прямоугольник и обновить холст?

Чтобы решить все эти проблемы и сделать холст интерактивным, нам нужно отслеживать все рисуемые на нем объекты. Потом, когда пользователь щелкнет в какой-либо точке холста, нужно определить, не попал ли он по одной из фигур. Этот процесс называется проверкой попадания (hit testing) . Если мы можем решить эти две задачи, решение остальных - модифицирование фигуры и обновление холста соответствующим образом - будет легким.

Отслеживание нарисованного содержимого

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

Для простоты, программа рисует только отдельные круги разного размера и цвета. Чтобы отслеживать отдельный круг, нам нужно знать его позицию на холсте (т.е. координаты центра), радиус и цвет заливки. Вместо того чтобы создавать несколько десятков переменных для хранения всей этой информации, нужно хранить четыре типа данных в одном компактном пакете. Таким пакетом будет пользовательский объект (custom object) .

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

Function Circle() { }

Мы хотим, чтобы наш объект мог хранить данные. Это делается посредством создания свойств с помощью ключевого слова this. Например, чтобы определить свойство radius объекта круга, присваивается значение выражению this.radius.

Можно пойти далее и передавать параметры функции Circle(). Таким образом создание объекта круга и установка его свойств осуществляется в одном шаге. В следующем коде приводится пример функции Circle(), позволяющей устанавливать параметры:

// Пользовательский объект Circle function Circle(x, y, radius, color) { this.x = x; this.y = y; this.radius = radius; this.color = color; this.isSelected = false; }

Свойство isSelected принимает значения true или false. Когда пользователь щелкает на круге, свойству isSelected присваивается значение true, вследствие чего код рисования знает, что у данного круга нужно нарисовать другой контур.

Объект круга с помощью этой версии функции Circle() можно создать посредством такого кода:

Var myCircle = new Circle(0, 0, 20, "red");

Вся идея создания программы рисования кругов заключается в том, чтобы можно было рисовать не один круг, а сколько угодно. Это означает, что только одного объекта круга будет недостаточно, и нам нужно создать массив для хранения всех кругов. В данном примере эту задачу выполняет следующая глобальная переменная:

// Этот массив хранит все окружности на холсте var circles = ;

Оставшийся код не представляет ничего сложного. Когда пользователь наживает кнопку "Добавить круг", чтобы создать новый круг, вызывается функция addRandomCircle(), которая создает новый круг произвольного размера и цвета в произвольном месте холста:

Function addRandomCircle() { // Устанавливаем произвольный размер и позицию круга var radius = randomFromTo(10, 60); var x = randomFromTo(0, canvas.width); var y = randomFromTo(0, canvas.height); // Окрашиваем круг произвольным цветом var colors = ["green", "blue", "red", "yellow", "magenta", "orange", "brown", "purple", "pink"]; var color = colors; // Создаем новый круг var circle = new Circle(x, y, radius, color); // Сохраняем его в массиве circles.push(circle); // Обновляем отображение круга drawCircles(); }

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

Function randomFromTo(from, to) { return Math.floor(Math.random() * (to - from + 1) + from); }

Последним шагом в этой последовательности будет собственно прорисовка текущей коллекции кругов на холсте. Для этого после создания нового круга функция addRandomCircle() вызывает функцию drawCircles(), которая в свою очередь перебирает массив кругов с помощью следующего кода:

Function drawCircles() { // Очистить холст context.clearRect(0, 0, canvas.width, canvas.height); // Перебираем все круги for(var i=0; i=0; i--) { var circle = circles[i]; // С помощью теоремы Пифагора вычисляем расстояние от // точки, в которой щелкнули, до центра текущего круга var distanceFromCenter = Math.sqrt(Math.pow(circle.x - clickX, 2) + Math.pow(circle.y - clickY, 2)) // Определяем, находится ли точка, в которой щелкнули, в данном круге if (distanceFromCenter

Этот пример можно улучшить множеством разнообразных способов и сделать его более интеллектуальным. Например, можно добавить панель инструментов с командами для редактирования выбранного круга, чтобы изменить его цвет или удалить с холста. Или же можно добавить возможность перетаскивания выбранного круга с одного места холста в другое. Для этого нужно просто отслеживать холст на событие onMouseMove, изменить соответствующим образом координаты круга, а потом вызвать функцию drawCircles(), чтобы обновить холст с кругом в новом месте:

Window.onload = function() { // Определение контекста рисования canvas = document.getElementById("drawingCanvas"); context = canvas.getContext("2d"); canvas.onmousedown = canvasClick; canvas.onmouseup = stopDragging; canvas.onmouseout = stopDragging; canvas.onmousemove = dragCircle; } ... function canvasClick(e) { ... if (distanceFromCenter

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

Canvas - API для рисования, недавно добавленный в HTML и поддерживается большинством браузеров (даже Internet Explorer 9). Canvas позволяет рисовать всё, что вы хотите прямо в браузере без использования плагинов, вроде Flash или Java. Canvas с его обманчиво простым API может революционно преобразовать создание веб-приложений для всех устройств, а не только десктопных.

Эти скриншоты позволят вам почувствовать вкус возможностей Canvas.

Что такое Canvas?

Canvas - API для двумерного рисования. По сути браузер даёт вам прямоугольную область на экране, в которой вы можете рисовать линии, фигуры, изображения, текст, практически всё что хотите. Canvas первоначально был создан Apple для их виджетов, но с тех пор был принят всеми разработчиками основных браузеров и теперь Canvas является частью спецификации HTML5. Вот небольшой пример, как выглядит некоторый код Canvas:

var canvas = document.getElementById("canvas"); var c = canvas.getContext("2d"); c.fillStyle = "red"; c.fillRect(100,100,400,300);

Данный прямоугольник нарисован функцией context.fillRect() .

Важно понимать, что Canvas предназначен для рисования пикселями. В нём нет фигур или векторов. Нет объектов для связывания с обработчиками событий. Это просто рисунки пикселями на экране. Как мы ещё увидим в этом и сила и слабость.

Как это связано с другими веб-технологиями?

Есть четыре способа нарисовать что-либо на веб-странице: Canvas, SVG, CSS и прямая анимация через DOM. Canvas содержит отличия от остальных трёх.

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

CSS в реальности предназначен для стилизации элементов. Поскольку DOM не содержит никаких объектов, которые рисуются в Canvas, вы не можете использовать CSS для их стилизации. CSS будет влиять только на прямоугольную площадь самого Canvas, так что вы можете установить границы, цвет фона и на этом всё.

Анимация через DOM : DOM или Document Object Model (объектная модель документа) определяет каждый объект на экране. Анимация с помощью CSS или JavaScript для передвижения объектов в некоторых случаях может быть более плавной, чем сделанной через Canvas, но это зависит от реализации вашего браузера.

Что? Где? Когда?

Итак, когда следует использовать Canvas вместо SVG, CSS или элементов DOM? Ну, Canvas по уровню ниже, чем другие, так что у вас больше контроля над рисованием и тратится меньше памяти, но взамен нужно писать больше кода. Используйте SVG, когда у вас имеются фигуры, которые вы хотите отобразить на экране, как на карте сделанной в Adobe Illustrator. Используйте CSS или DOM-анимацию, когда у вас есть большие статические области, которые вы хотите анимировать или желаете использовать трёхмерные преобразования. Для схем, графиков, динамических диаграмм и, конечно, видеоигр, Canvas - наилучший выбор. В дальнейшем мы обсудим несколько библиотек, которые позволяют делать вам больше штук, ориентированных на векторы и объекты, используя Canvas.

Прежде чем двигаться дальше, хочу пояснить, что когда я говорю о Canvas, то подразумеваю двумерный API. Также существует трёхмерный API в работах называемых WebGL. Я не собираюсь о нём рассказывать, потому что он всё ещё находится в разработке и браузеры поддерживают его довольно плохо. Также этот по существу OpenGL от JavaScript находится на более низком уровне чем Canvas и гораздо сложнее в использовании. Когда WebGL станет более зрелым, мы вернёмся к нему в следующих главах.

Поддержка в браузерах

И, наконец, прежде чем мы углубимся в работу с Canvas, давайте поговорим о том, где вы можете его использовать. К счастью Canvas это теперь стабильный API и большинство современных браузеров поддерживают его в некоторой мере. Поддерживает даже Internet Explorer начиная с версии 9 и очень хорошо.

9 10 9 3 4

Большинство мобильных платформ поддерживают Canvas, потому что в основном они основаны на WebKit, который уже давно имеет хорошую поддержку. Я знаю, что поддерживает WebOS, iOS, Android. Считаю, что BlackBerry тоже, по крайней мере, на PlayBook. Windows Phone 7 не поддерживает, но это может измениться в будущем обновлении.

iOS webOS Android BlackBerry Windows Phone 7
все все 2 PlayBook и OS 6.0

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

Простое рисование

Как я уже говорил ранее, Canvas - это просто API. Если вы уже делали работу с программированием на Flash или Java 2D, то это должно показаться довольно знакомым. Вы получаете указатель на графический контекст, устанавливаете некоторые свойства, такие как цвет текущей заливки или контура и затем рисуете несколько фигур. Вот некоторые примеры.

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

Ctx.fillStyle = "red"; //x, y, ширина, высота ctx.fillRect(20 ,30 ,40 ,50 );

Вот ещё один.

C.fillStyle = "#ccddff"; c.beginPath(); c.moveTo(50,20); c.lineTo(200,50); c.lineTo(150 ,80 ); c.closePath(); c.fill(); c.strokeStyle = "rgb(0,128,0)"; c.lineWidth = 5 ; c.stroke();

В этом примере мы устанавливаем текущий цвет заливки, создаём контур, а затем заливаем и обводим его. Следует отметить, что контекст отслеживает цвет заливки и цвет обводки отдельно. Также обратите внимание на разные формы указания цвета. fillStyle и strokeStyle может быть любым корректным цветом из CSS, таким как шестнадцатеричным, названием или функцией rgb() .

Контуры

Canvas напрямую поддерживает только прямоугольник. Чтобы нарисовать любую другую фигуру необходимо сделать это самостоятельно с помощью контуров. Контуры это фигуры, созданные кучей прямых или изогнутых отрезков линий. В Canvas вы должны вначале определить контур через beginPath() , затем залить его или использовать как маску. Вы определяете каждый отрезок такими функциями как moveTo() , lineTo() и bezierCurveTo() . В данном примере фигура рисуется с помощью moveTo() , затем идёт кривая Безье и несколько линий. После создания контура он заливается и обводится.

C.fillStyle = "red"; c.beginPath(); c.moveTo(10,30); c.bezierCurveTo(50 ,90 ,159 ,-30 ,200,30); c.lineTo(200,90); c.lineTo(10,90); c.closePath(); c.fill(); c.lineWidth = 4; c.strokeStyle = "black"; c.stroke();

Пара слов о системе координат. Canvas ведёт отсчёт от левого верхнего угла с осью у, которая ведёт вниз. Это традиционно для компьютерной графики, но если вы хотите указать другую точку отсчёта, то можете сделать это через трансформацию, о которой мы расскажем позже. Ещё одна важная вещь - спецификация определяет координаты в левом верхнем углу пикселя. Это означает, что если вы рисуете вертикальную линию шириной в один пиксель, начиная с 5.0, то на самом деле это охватывает половину соседних пикселей (от 4.5 до 5.5). Чтобы обойти это сместите ваши координаты по оси х на 0.5. Тогда это даст вам линию, которая идёт с 5.0 до 6.0. В качестве альтернативы вы можете использовать ширину линии, указав 2 или 4.

Изображения

Canvas может выводить изображения через функцию drawImage .

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

Ctx.drawImage(img, 0,0); //normal drawing ctx.drawImage(img, //draw stretched 0,0,66,66, //source (x,y,w,h) 100,0,103 ,100 //destination (x,y,w,h)); ctx.drawImage(img, //draw a slice 20 ,10 ,20 ,20 , //source coords (x,y,w,h) 250,0,250,50//destination coords (x,y,w,h));

Попробуйте поменять переменные, чтобы увидеть, как работает растяжение и обрезка. Чтобы растянуть изображение вы должны указать исходные и конечные координаты. Исходные координаты говорят drawImage какие пиксели взять из изображения. Поскольку рисунок выше имеет размеры 67x67 пикселей, то используя 0,0,66,66 мы отобразим изображение целиком. Конечные координаты говорят drawImage куда поместить пиксели на экране. Изменяя значения w и h можно растянуть и сжать изображение.

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

Текст

Canvas может также рисовать текст. Атрибуты шрифта такие же, как и в аналоге CSS, так что вы можете установить стиль, размер и семейство шрифта. Обратите внимание, что функция fillText(строка,x,y) использует базовую линию текста, а не его верхний край. Если вы поместите ваш текст в 0,0, то он нарисуется за пределами верхней части экрана. Так что опустите y на соответствующее значение.

Ctx.fillStyle = "black"; ctx.font = "italic "+96 +"pt Arial "; ctx.fillText("this is text", 20 ,150 );

Градиенты

Canvas может заливать фигуры градиентом вместо цвета. Вот линейный градиент:

200 ,0 ); grad.addColorStop(0, "white"); grad.addColorStop(0.5, "red"); grad.addColorStop(1, "black"); ctx.fillStyle = grad; ctx.fillRect(0,0,400,200);

Важно отметить, что градиент закрашивается в той же системе координат, какой рисуется фигура, а не внутренних координат фигуры. В данном примере фигура рисуется в 0,0. Если мы изменим фигуру на 100,100, то градиент будет по-прежнему находиться в начале экрана, так что окажется меньше градиента, вроде этого:

Var grad = ctx.createLinearGradient(0,0,200 ,0 ); grad.addColorStop(0, "white"); grad.addColorStop(0.5, "red"); grad.addColorStop(1, "black"); ctx.fillStyle = grad; ctx.fillRect(100,100,400,200);

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

Вот и все основы рисования. Давайте остановимся на достигнутом и выполним несколько упражнений в следующей главе. У вас уже должен быть установлен браузер и текстовый редактор. Я рекомендую использовать Chrome , поскольку он содержит хорошие инструменты отладки и jEdit , потому что он бесплатный и кросс-платформенный. Но вы можете использовать браузер и редактор по своему усмотрению.

Добрый день, уважаемые читатели.

Итак, приступим!

Что такое canvas и зачем он нужен?

Canvаs (холст) - элемент HTML5 для создания растрового двухмерного изображения. Обычно используется совместно с javascript .

Ширину и высоту canvas можно изменять.

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

Canvas так же используется в WebGL для аппаратного ускорения 3D графики. В результате можно создавать даже 3D игры, работающие в окне браузера.

Создание нашего canvas Canvas Текст показывается, если элемент не поддерживается var canvas = document.getElementById("test"); var ctx = canvas.getContext("2d"); /* Рисует контур прямоугольника на всю ширину и высоту canvas */ ctx.strokeRect(0, 0, canvas.width, canvas.height);

Создается canvas путем обычной вставки тега в html-код . Далее через обычный javascript мы получаем элемент и содержимое canvas (строка 10, 11) и рисуем обведенный прямоугольник, который растягивается на всю ширину и высоту canvas .

Примитивы в canvas

В canvas можно рисовать такие геометрические элементы, как:

  • Прямоугольники
  • Линии
  • Окружности, дуги
  • Различные кривые, эллипс
  • Прямоугольники

    Самая простая фигура для canvas — прямоугольник. Чтобы его нарисовать нам нужна всего одна строчка кода.

    StrokeRect(x, y, width, height); // пустой прямоугольник с обводкой

    Есть еще 2 варианта для рисования прямоугольников:

    FillRect(x, y, width, height) // Закрашенный прямоугольник clearRect(x, y, width, height) // Очищам область на холсте в виде прямоугольника заданного размера

    Ниже приведен пример использования этих 2-х способов:

    Ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.clearRect(50, 50, 300, 200); // вырезаем прямоугольник

    В результате мы нарисовали большой черный прямоугольник и вырезали область из точки (50, 50) размером 300 пикселей по ширине и 200 пикселей по высоте. Ниже представлено, как это будет выглядеть.

    Более интересный пример:

    Ctx.strokeRect(5, 5, 138, 138); ctx.fillRect(10, 10, 128, 128); for (i = 0; i