Начинаем рисовать

Теперь попробуем осуществить давнюю мечту — изобразить на веб-странице наклонную линию (раньше для этого нужно было применять Flash или, прости Господи, ActiveX). Тут нам потребуется по-настоящему рисовать:

Var canvas = document. getElementById("myCanvas");

Var context = canvas. getContext("2d");

Context. beginPath():

Context. ioveTo(50,50);

Context. lineTo(250,250):

Context. stroke():

Все получилось (рис. 34). Но что мы сделали? Метод beginPath начинает построение траектории рисования на заданном контексте. При рисовании линии или контура у нас действительно получается путь (ну, например, черта карандаша, которым мы это все рисуем). Все отрезки этого пути хранятся в памяти контекста, и при каждом новом вызове beginPath память очищается, позволяя начать новую фигуру.

Рис. 34. Вот она — наклонная линия!

Метод moveTo() перемещает наш виртуальный карандаш в заданную координатами точку холста. Когда холст только инициализирован, или после вызова метода beginPath, начальная точка установлена в позиции (0,0), соответственно, этот метод применяется для перенесения стартовой позиции в нужное место.

LineTo() рисует линию до заданной точки. В качестве отправной точки служит сохраненная в контексте. Например, заданные moveTo() или аргумент предыдущего lineTo(), вызванного непосредственно перед этим.

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

Можем мы нарисовать теперь что-нибудь посложнее? Запросто! Вот, например, треугольник:

Context. beginPath();

Context. moveTo(50,50);

Context. lineTo(250,150);

Context. lineTo(50,250);

Context. lineTo(50,50);

Context. stroke();

Этот пример можно написать и так:

Context. lineTo(250,150); context. lineTo(50,250);0); context. flosePath(); context. stroke();

Метод closePath() всегда старается замкнуть получившийся контур, рисуя прямую линию от текущей точки до начальной.

С помощью этих трех методов можно рисовать ломаные любой сложности. Вот звезда:

Context. strokeStyle = ”red”;

Context. lineWidth = 10;

Context. lineCap = ‘square’;

Context. beginPath();

Context. moveTo(50,100);

Context. lineTo(240,100);

Context. lineTo(70,230);

Context. lineTo(140,30);

Context. lineTo(220,230);

Context. closePath();

Context. stroke();

Тут, кроме революционного цвета и толщины линий, задается отображение окончаний этих самых линий — свойство ineCap может принимать значения butt (по умолчанию), round, square, соответствующее непрямоугольному, закругленному и скошенному завершению линий (естественно, это имеет значение только при заданном параметре lineWidth). Звезду, нарисованную контуром (рис. 35), можно облагородить, поменяв метод отрисовки:

context. strokeStyle = ”red”; context. fillStyle = ”red”;

Context. closePath(); context. fill();

Рис. 35. Рисуем звезду

Все равно результат выглядит вполне пролетарски (рис. 36), а нарисовать серп с молотом я оставляю в качестве домашнего задания. Хотя стоп! Серп — это кривые, мы их еще не освоили, сейчас исправим.

Рис. 36. Заливка

Для рисования «правильных» кривых — дуг — у нас есть метод arc. Вот его синтаксис:

Аргументы тут — координаты центра окружности, радиус, начальный и конечный углы дуги (в радианах!) и флаг — указатель направления вращения. Всего этого вполне достаточно, впрочем, серп я рисовать не хочу, а вот рожицу — с удовольствием:

Var canvas = document. getElementById("myCanvas");

Var context = canvas. getContext("2d");

Context. fillStyle = "green";

Context. lineWidth = 10;

Context. strokeStyle = "green";

Context. lineCap = ’round’;

Context. beginPath();

Context. moveTo(240,130);

Context. arc(140,130,100,0,7,0);

Context. stroke();

Context. beginPath();

Context. moveTo(112,100);

Context. arc(100,100,12,0,7,0);

Context. moveTo(192,100);

Context. arc(180,100,12,0,7,0);

Context. fill();

Context. beginPath();

Context. moveTo(190,150);

Context. arc(140,150,50,0,3,0);

Context. moveTo(140,130);

Context. lineTo(140,150);

Context. stroke();

Результат — на рис. 37. На этом примере видна необходимость использования разных видов отрисовки.

Есть в арсенале canvas и метод рисования произвольных кривых, точнее, кривых Безье, причем есть возможность это делать в кубическом и квадратичном вариантах (четвертого и третьего порядка). Методы отрисовки кривых следующие:

QuadraticCurveTo(cp1x, cp1y, x, y); GezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)

Отличие между этими кривыми показано на рис. 38.

Рис. 37. Используем дуги в мирных целях

Рис. 38. Кривые Безье

Квадратичная кривая Безье имеет начальную и конечную точки (точки 1 и 2) и одну точку контроля (точка 3), в то время как кубическая кривая Безье использует две точки контроля.

Параметры x и y — это координаты конечной точки. cp1x и cp1y — координаты первой точки контроля, а cp2x и cp2y — координаты второй точки контроля.

Воспользуемся квадратичной кривой, чтобы пририсовать нашей рожице «говорящий пузырь»:

Context. beginPath(); context. lineWidth = 4; context. strokeStyle = "gray"; context. moveTo(275,75); context. quadraticCurveTo(225,75,225,112.5);

Context. quadraticCurveTo(225,150,250,150):

Context. quadraticCurveTo(250,170,184,175):

Context. quadraticCurveTo(260,170,265,150):

Context. quadraticCurveTo(325,150,325,112.5):

Context. quadraticCurveTo(325,75,275,75):

Context. stroke():

Результат — на рис. 39.

Рис. 39. Конструируем «голосовой пузырь»

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

Context. fillStyle = ”red”;

Context. beginPath():

Context. moveTo(37.5,20):

Context. bezierCurveTo(37.5,18.5,35,12.5,25,12.5):

Context. bezierCurveTo(10,12.5,10,31.25,10,31.25):

Context. bezierCurveTo(10,40,20,51,37.5,60):

Context. bezierCurveTo(55,51,65,40,65,31.25):

Context. bezierCurveTo(65,31.25,65,12.5,50,12.5):

Context. bezierCurveTo(42.5,12.5,37.5,18.5,37.5,20):

Context. fill():

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

Context. translate(258, 70); context. fillStyle = "red"; context. beginPath(); context. moveTo(37.5,20);

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

Context. font = "60px serif"; context. fillText ("I", -20, 56); context. font = "20px serif"; context. fillText ("Canvas", -9, 73);

Ну а теперь сделаем картинку чуть эстетичней. Во-первых, применим заливку к «голосовому пузырю»:

context. strokeStyle = "gray"; context. fillStyle = "rgba(0, 0, 200, 0.5)";

context. stroke();

Context. fill();

Тут для указания цвета заливки мы применяем метод rgba(), позволяющий использовать альфа-канал, отвечающий за прозрачность. Заливку сердца поменяем на градиентную:

Context. bezierCurveTo(42.5,12.5,37.5,18.5,37.5,20);

Var radgrad = context. createRadialGradient(10,20,20,50,20,50):

Radgrad. addColorStop(0, "#FF5F98");

Radgrad. addColorStop(0.75, "#FF0188");

Radgrad. addColorStop(1, "rgba(255,1,136,0)");

Context. fillStyle = radgrad;

Context. fill();

Context. beginPath();

Context. fillStyle = "red";

Применяя тут радиальную градиентную заливку, мы, возможно, стреляем из пушек по воробьям, но, по-моему, результат неплох (рис. 40). Что касается аргументов метода createRadialGradient(), то это координаты и радиусы двух окружностей для простирания градиента. Далее идут уже знакомые нам addColorStop(), присваивающие цвета.

Рис. 40. Добавляем текст

Ну, хватит издеваться над нашей рожицей. Посмотрим, что еще нам может предложить canvas.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *