Эта статья посвящена особой возможности HTML - тегу Canvas. Этот тег необычен тем, что не управляет параметрами визуализации текста, как, например, "<i>это слово будет выделено курсивом</i>", а дает возможность нарисовать на странице любое изображение, используя команды javascript.
Фактически до появления canvas, если вам было необходимо разместить на сайте динамическое изображение, например, график посещений сайта по дням недели, то вы либо создавали php-скрипт (благо, даже на бесплатных хостингах давно есть поддержка библиотеки gd2 графических функций, таких, как линия, прямоугольник, эллипс и другие). Либо вы создавали flash-ролик, который также с помощью своих функций рисовал изображение. В отдельных случаях можно было использовать средства java applet или activex. Чем плохи три последних подхода: flash, как и java applet, требует установленного плагина (и в случае java applet очень немаленького размера), activex - работают только под IExplorer и только под Windows (не говоря о том, что у многих пользователей эта дырявая и, прямо скажем, опасная технология просто отключена). И еще, например, у меня на работе корпоративный proxy-сервер вырезает из страниц flash-ролики. Конечно, это не показатель, но все же.
Подход номер один, когда картинку генерирует php код, универсален и надежен, правда, потребляет слишком много избыточного трафика для некоторых задач. Например, если вы создаете приложение, которое рисует график функции z=f(x,y), то большая часть получившегося изображения будет залита одним цветом фона и лишь небольшая часть картинки будет отображать линии графика функции. Для эксперимента я создал картинку размером 1024*768 с нарисованной линией синусоиды. Ее размеры в разных форматах были таковы: gif - 8 Кб, jpeg - 33 Кб, png - зашкалил за 210 Кб.
Последнее замечание: наше приложение будет гораздо удобнее, если пользователь сможет получать графики функций без подключения к Интернету, что в случае dial-up или повременной оплаты самое то.
Будем считать, что я вас убедил в полезности подхода с переносом генерации изображения с сервера на сторону клиента, а теперь пару слов об истории и текущей ситуации с HTML Canvas. Тег canvas не входил ни в один из стандартов, его придумала и реализовала в своем браузере Safari компания Apple. Идею подхватила группа разработчиков Mozilla и добавила поддержку тега canvas в движок html-рендеринга Gecko, используемого в Firefox и смежных продуктах. Затем инновацию поддержала компания Opera Software, и, начиная с 9-й версии, браузер Opera также знает тег Canvas. Самые "активные" разработчики самого "передового" браузера (я говорю про IExplorer) в это время как всегда спали. К счастью, Novell и Google начали проекты по реализации плагина, поддерживающего Canvas для IExplorer-а. Добавилась ли поддержка Canvas в новомодном 7-м IExplorer, я не знаю, т.к. нигде упоминаний в Интернете об этом я не нашел, а попробовать не могу из-за нежелания выкачивать сей монструозный продукт. Следует отметить, что данный тег планируют внести в перспективный пятый стандарт html.
Самый простой пример использования Сanvas - это просто вставить его в тело html-документа, не забыв про fallback. Проще говоря, если браузер клиента не поддерживает данный тег, то он должен увидеть некоторое поясняющее сообщение. В примере ниже это размещенное внутри тега Сanvas изображение. Очень важно дать Сanvas-у идентификатор - для этого служит атрибут id, если вы так не сделаете, то не сможете из javascript обращаться к Canvas и рисовать на нем. В качестве стилевого оформления я задал области Canvas границу черного цвета, это только для удобства дальнейшей работы.
<html><head> <script> <!-именно здесь будут размещаться функции, которые рисуют на canvas-> </script> </head> <body> <canvas id="canva" width="400" height="400" style="border: 1px solid black;"> <img src="no_canvas_sorry.jpg" /> </canvas> <button onclick="draw()">draw!</button> <!-эта кнопка вызывает некоторую функцию рисования -> </body></html>
Следующий шаг - это создание функции, которая будет вызываться при нажатии на кнопку button. Функция должна получить доступ к объекту "canva", для этого мы применим стандартный метод getElementById ("тот самый идентификатор объекта, который вы, надеюсь, не забыли задать"). Затем следует проверить, что браузер умеет рисовать, следует попросить его для Canvas вернуть так называемый контекст рисования (проще говоря, место, где рисуют). И затем, вооружившись справочником функций, можно начинать непосредственно рисовать. Самое простое - это создать прямоугольник, закрашенный некоторым цветом, при этом вы можете задать цвет как привычный rgb, или же rgba - буква "a" на конце дает нам возможность задать alpha-компоненту или прозрачность. Для того чтобы нарисовать прямоугольник, есть три функции: fillRect, strokeRect, clearRect, - которые, соответственно, рисуют прямоугольник сплошным цветом, только границу прямоугольника, очищают часть области рисования. Все эти функции получают в качестве параметра координаты левого верхнего угла прямоугольника и его размеры.
function draw(){ var canvas = document.getElementById('canva'); if (canvas.getContext){ var ctx = canvas.getContext('2d'); // предупреждая следующий вопрос, нет, трехмерного контекста // рисования нет, рисовать можно только на плоскости ctx.fillStyle = "rgb(200,0,0)"; ctx.fillRect (10, 10, 55, 50); ctx.fillStyle = "rgba(0, 0, 200, 0.5)"; ctx.fillRect (30, 30, 55, 50); ctx.fillStyle = "rgb(0,0,0)"; // черный цвет ctx.fillRect(100,100,100,100); ctx.clearRect(125,125,60,60); ctx.strokeRect(150,150, 120,120); } }
Если вам необходимо нарисовать более сложную фигуру, то следует использовать Path. Path - это просто путь, по которому водится виртуальный карандаш. Путь должен начаться, карандаш проводит несколько линий (дуг, кривых Безье, прямоугольников и т.д.), затем путь закрывается (этот шаг необязателен, например, вы сами довели линию от последней точки к первой). И последний шаг - это запуск отрисовки либо контура Path, либо ее закраска, как вариант рисуется и контур, и фоновая закраска одновременно.
Для того чтобы нарисовать линию, вы используете две базовые функции moveTo(x,y) и lineTo(x,y). Первая из них поднимает невидимый карандаш и перемещает его в точку (x,y), а вторая перемещает карандаш в точку (x,y), уже ведя карандаш по "листу". Если вам хочется нарисовать круг, дугу, то используйте функцию arc(x, y, radius, startAngle, endAngle, anticlockwise), ее параметры, соотвественно, координаты центра круга или дуги, затем идет радиус, параметры startAngle и endAngle - задают начало и конец дуги в радианах (и это важно), последним идет параметр anticlockwise - логический признак того, будет ли дуга рисоваться по часовой или против часовой стрелки. В примере ниже я рисую две звезды, одна из которых отображается в виде контура, вторая - в виде заливки сплошным цветом, также рисуется пример дуги. Для того чтобы задать цвет контура, используется свойство strokeStyle.
function draw(){ var canvas = document.getElementById('canva'); if (canvas.getContext){ var ctx1 = canvas.getContext('2d'); var ctx2 = canvas.getContext('2d'); ctx1.beginPath (); ctx2.beginPath (); var deltaI = 0.1; ctx1.moveTo ( 200 + 100*Math.cos(0), 200 - 100*Math.sin(0) ); ctx2.moveTo ( 200 + 170*Math.cos(0), 200 - 170*Math.sin(0) ); for (var i = 0; i < 2 * Math.PI; i+= deltaI){ ctx1.lineTo ( 200 + 100*Math.cos(i ), 200 - 100*Math.sin(i) ); ctx1.lineTo ( 200 + 150*Math.cos(i + deltaI), 200 - 150*Math.sin(i + deltaI) ); ctx2.lineTo ( 200 + 170*Math.cos(i ), 200 - 170*Math.sin(i) ); ctx2.lineTo ( 200 + 190*Math.cos(i + deltaI), 200 - 190*Math.sin(i + deltaI) ); } ctx1.closePath (); ctx1.stroke (); ctx2.closePath (); ctx2.fillStyle="rgb(120,78,89)"; ctx2.fill(); } ctx1.strokeStyle = "rgba(255,255,255,125)"; ctx1.beginPath (); ctx1.arc (200, 200,40, 45 * (Math.PI / 180), 315 * (Math.PI / 180), false); ctx1.closePath(); ctx1.stroke (); }
Обратите внимание на одновременное существование двух контекстов рисования. Все примеры кода данной статьи вы можете найти на сайте автора: black-zorro.com.
black zorro
![Версия для печати Версия для печати](https://www.kv.by/sites/all/modules/print/icons/print_icon.png)
Комментарии
(Не использую рекурсивную функцию как у меня:)
http://forum.vingrad.ru/forum/topic-248212/anchor-entry1798757/0.html
http://forums.realcoding.net/index.php?showtopic=22509