Еще одно canvas руководство

Время на прочтение
5 мин

Количество просмотров 19K

Зачем еще одно руководство?

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

На эту страницу с поисковиков зашли

Canvas элемент

Canvas элемент имеет имя ‘canvas’ (ну кто бы мог подумать) и атрибуты ‘width’ и ‘height’, при чем стоит заметить что эти атрибуты не имеют отношения к CSS, они обозначают ширину и высоту canvas элемента в пикселях не на экране, а на координатной плоскости холста. К тому же текст внутри тега будет проигнорирован браузером с поддержкой canvas и показан в браузере без поддержки canvas.

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

<!doctype html>
<html>
		<head>
			<title>Тупая демка</title>
		</head>
		<body>
			<canvas id="cnv" width="600" height="600">Ставь нормальный браузер</canvas>
                        <script type="text/javascript" src='your_file.js'></script>
		</body>
</html>

Рисование на canvas происходит через контекст, который может быть получен вызовом метода canvas элемента getContext с аргументом ‘2d’.
Так что добавим в наш скрипт строку.

var ctx = document.getElementById('cnv').getContext('2d')

Прямоугольники

Прямоугольники в canvas это единственный примитив. Для работы с прямоугольниками существует всего 3 метода.

Заливаем прямоугольник

fillRect — рисует залитый прямоугольник, рассмотрим его аргументы

fillRect(float x, float y, float w, float h)

Где x и y это координаты верхнего левого угла, а w и h это ширина и высота соответственно. Давайте рассмотрим пример. Добавим в скрипт строку.

ctx.fillRect(200, 250, 200, 100)

Как многие догадались, после выполнения в центре холста будет нарисован прямоугольник шириной 200 пикселей и высотой 100 пикселей.

Обводим прямоугольник

strokeRect — работает точно также как и fillRect, но в отличие от него не заливает прямоугольник, а рисует только контуры. Добавим в скрипт строку.

ctx.strokeRect(150, 200, 300, 200)

Теперь вокруг залитого прямоугольника мы нарисовали контуры еще одного.

Отчищаем прямоугольник

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

ctx.clearRect(350, 300, 50, 50)

Таким образом мы обрезали часть залитого прямоугольника.

Пути

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

Начинаем путь

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

ctx.beginPath()

Идем к точке

moveTo(float x, float y)

— перемещает положение курсора на (x;y).
Добавим в наш скрипт строку:

ctx.moveTo(200,200)

Ведём линию к точке

lineTo(float x, float y)

— проводит линию от положения курсора к (x;y).
Для примера добавим в наш скрипт строку:

ctx.lineTo(400,400)

Обводим

Завершающим моментом будет вызов метода stroke чтобы показать линию на холсте. Так что добавим строку в скрипт:

ctx.stroke()

Теперь если открыть наш пример то мы увидим, что на холсте отрисовывается линия.

Замыкаем

Если мы рисуем какую нибудь фигуру и нам нужно сделать её замкнутой то мы можем применит метод closePath. Для примера нарисуем треугольник, для этого оставим в нашем файле только получение контекста и вставим туда следующие строки:

ctx.beginPath()
ctx.moveTo(200,200)
ctx.lineTo(400,400)
ctx.lineTo(200,400)
ctx.closePath()
ctx.stroke()

Если мы откроем файл что отрисовывается треугольник. При этом мы провели только две линии, а closePath нарисовал третью чтобы замкнуть фигуру.

Заливаем

Кроме отрисовки контуров мы можем еще и залить фигуру, для этого просто заменим в нашем скрипте вызова функции stroke на вызов fill. При это если вы заливаете фигуру то не обязательно явно замыкать фигуру вызывая closePath, ведь при вызове fill фигура замкнется автоматически.

Дуги

arc(float x, float y, float r, float startAngle, float endAngle, bool anticlockwise)

— нарисует дугу с центром в точке (x;y), радиусом — r, стартовым углом и конечным startAngle, endAngle соответственно и если anticlockwise = true то часть окружности идет против часовой стрелки, иначе по её направлению.
Примечание: углы измеряются в радианах
Давайте для примера нарисуем частично залитую окружность, для этого отчистим наш скрипт, оставим только получение контекста. Затем добавим следующие строки.

ctx.beginPath()
ctx.arc(200,300,70,0,Math.PI*0.85,false)
ctx.stroke()

ctx.beginPath()
ctx.arc(200,300,70,0,Math.PI*0.85,true)
ctx.fill()

Немного другие дуги

arcTo(float x1, float y1, float x2, float y2. float r)

— нарисует дугу с радиусом r заключенную между двумя отрезками — AB и BC, где точка A это положение курсора, B = (x1;y1) C = (x2;y2)
Давайте для примера оставим в скрипте только получение контекста и добавим следующие строки:

ctx.beginPath()
ctx.moveTo(200,300)
ctx.arcTo(300,100,400,300,50)
ctx.stroke()

Квадратичные кривые

quadraticCurveTo(float x1, float y1, float x2, float y2)

— нарисует квадратичную кривую образованную тремя точками (положение курсора, (x1;y1), (x2;y2)).
Для примера посмотрим что выполнить следующий код:

ctx.beginPath()
ctx.moveTo(100,100)
ctx.quadraticCurveTo(200,200,50,200)
ctx.stroke()

Кривые Безье

bezierCurveTo(float x1, float y1, float x2, float y2, float x3, float y3)

— нарисует кубическу кривую Безье. Для примера добавим в наш скрипт следующий код:

ctx.beginPath()
ctx.moveTo(100,100)
ctx.bezierCurveTo(200,200,100,300,50,100)
                   ctx.stroke()

Опять о прямоугольниках

rect(float x, float y, float w, float w)

— работает абсолютно идентично fillRect и strokeRect, но в отличие от них только добавляет прямоугольник в путь.

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

Это точка на фигуре?

isPointInPath(float x, float y)

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

ctx.beginPath()
ctx.rect(200,200,100,200)
console.log(ctx.isPointInPath(250,250))
console.log(ctx.isPointInPath(100,100))

Данный скрипт должен вывести в отладочную консоль сначала true, а затем false.

Ограничиваем область отрисовки


Кроме функции stroke и fill для работы с путями существует еще и функция clip, она ничего не рисует но тем не менее выполняет важную роль, после её вызова любой объект будет рисоваться только когда он находится в области на которой определен путь, давайте рассмотрим небольшой пример:


ctx.beginPath()
ctx.arc(200,300,70,0,Math.PI*2,true)
ctx.stroke()  //Нарисуем круг по которому определим область пути
ctx.clip()       //Ограничим область для рисования областью путя

ctx.beginPath()
ctx.moveTo(100,320)
ctx.lineTo(500,320)
ctx.lineTo(100,250)
ctx.stroke() //Нарисуем парочку линий, при чем они будут видны только внутри круга

В ближайшем будущем (в теории по части в два дня)

Стилизация, градиенты и тени
Отрисовка картинок и текста
Трансформация и композиция
Анимация и манипуляция imageData

Время на прочтение
4 мин

Количество просмотров 12K

Введение

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

Сделаем наш холст разноцветным


Как вы уже заметили в canvas есть два типа операции отрисовки fill и rect и у каждого есть свои настройки стилей. Для их изменения нужно менять свойства контекста fillStyle и strokeStyle, эти свойства в качестве значения могут принимать не только цвета, но и другие значения которые мы рассмотрим позже. А сейчас мы рассмотрим как поменять цвет. Для этого нужно просто присвоить свойствам fillStyle и strokeStyle новый значения, в случае с цветами это будут строки, при этом canvas поддерживает следующие схемы описания цветов: orange, #FFA500, rgb(255,165,0), rgba(255,165,0,1).
Для примера нарисуем разноцветный круг, оставим в нашем скрипте только получение контекста, а затем добавим следующий код:

for(var i=0;i<6;i++){
    ctx.fillStyle = 'rgb(' + Math.round(Math.random()*255) + ',' + Math.round(Math.random()*255) + ',' + Math.round(Math.random()*255) +')'
    ctx.beginPath()
    ctx.arc(300,300,70,Math.PI/3*i,Math.PI/3*(i+1),false)
    ctx.lineTo(300,300)
    ctx.fill()
}

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

Поработаем с линиями

Мы также можем изменить некоторые параметры у линий для этого существует несколько свойств, давайте рассмотрим по порядку каждое из них.

Изменяем ширину линии

Значение ширины линии хранится в свойстве lineWidth контекста canvas и одна единица соответствует одному пикселю. Значение по умолчанию естественно 1.0

Стиль верхушки линий


Стиль верхушки линии хранится в свойстве lineCap и для него существует три возможных значение: butt, round, sqare, стилем по умолчанию является butt.

Стиль соединения линий


Стиль соединения линий хранится в свойстве lineJoin и может принимать три возможных значение: miter, round, bevel, стилем по умолчанию является miter.

Еще немного о miter

Мы можем ограничить длину огромного хвоста miter с помощью свойства miteLimit которое по умолчанию принимает значение 10.

Отбросим тени


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

shadowOffsetX = 0.0
shadowOffsetY = 0.0
shadowBlur = 0.0
shadowColor = "transparent black"

Для примера отбросим две тени на друг друга в ограниченной области рисования и посмотрим что произойдет:

ctx.beginPath()
ctx.arc(200,300,70,0,Math.PI*2,true)
ctx.stroke()
ctx.clip()

ctx.shadowOffsetX = -10
ctx.shadowOffsetY = -10
ctx.shadowBlur = 2
ctx.shadowColor = 'black'

ctx.beginPath()
ctx.moveTo(100,320)
ctx.lineTo(500,320)
ctx.moveTo(500,180)
ctx.lineTo(100,370)
ctx.stroke()

Используем градиенты

Как в прошлой части мы рассмотрели пути так и в этой мы рассмотрим градиенты.

Линейные градиенты

Создание объекта градиента

createLinearGradient(float x1, float y1, float x2, float y2)

— создаст объект линейного градиента проходящего из точки (x1;y1) в точку (x2;y2), добавим в наш код строку:

var gr = ctx.createLinearGradient(0,0,150,150)

Добавляем цвета в градиент

addColorStop(float offset, string color)

— добавит в наш градиент цвет color с отступом offset который принимает значения от 0 до 1.
Добавим в наш скрипт строки:

gr.addColorStop(0.0,'blue')
gr.addColorStop(0.5,'red')
gr.addColorStop(1.0,'green')

Применим градиент как стиль заливки

Свойство fillStyle контекста canvas может принимать в качестве значения не только цвет, но и градиент, добавим в скрипт строку:

ctx.fillStyle = gr

Финальный шаг, рисуем залитый прямоугольник

Добавим в наш скрипт последнюю строку:

ctx.fillRect(0,0,150,150)

Радиальные градиенты


При работе с радиальными градиентами отличие от линейных заключается только в создании.

createRadialGradient(float x1, float y1, float r1, float x2, float y2, float r2)

— создаст радиальный градиент с плавным переходом цвета из окружности с центром в точке (x1;y1) и радиусом r1 в окружность с центром точке (x2;y2) и радиусом r2. Для примера нарисуем шарик и сделаем псевдо-освещение:

ctx.shadowOffsetX = 10
ctx.shadowOffsetY = 15
ctx.shadowBlur = 10
ctx.shadowColor = '#0F0'

var gr = ctx.createRadialGradient(60,60,15,75,75,75)

gr.addColorStop(0.0,'#0F0')
gr.addColorStop(1.0,'#0DA805')

ctx.fillStyle = gr

ctx.beginPath()
ctx.arc(75,75,75,0,Math.PI*2,false)
ctx.fill()

Используем шаблоны

Кроме цветов и градиентов fillStyle и strokeStyle в качестве значения могут принимать и так называемые шаблоны, шаблоны можно сделать из того же самого canvas элемента, изображения или видео. Для примера будем использовать изображение. Шаблон создается методом createPattern(object any, string repeat), repeat может принимать следующие значения:«repeat»,«repeat-x»,«repeat-y»,«no-repeat». Значением по умолчанию является «repeat». Для примера запустим следующий скрипт:

var img = new Image()
img.src = 'brick.jpg'

var ptr = ctx.createPattern(img,'repeat')
ctx.fillStyle = ptr;

ctx.fillRect(50,50,100,100)

Время на прочтение
5 мин

Количество просмотров 18K

Зачем еще одно руководство?

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

На эту страницу с поисковиков зашли

Canvas элемент имеет имя ‘canvas’ (ну кто бы мог подумать) и атрибуты ‘width’ и ‘height’, при чем стоит заметить что эти атрибуты не имеют отношения к CSS, они обозначают ширину и высоту canvas элемента в пикселях не на экране, а на координатной плоскости холста. К тому же текст внутри тега будет проигнорирован браузером с поддержкой canvas и показан в браузере без поддержки canvas.

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

<!doctype html>
<html>
		<head>
			<title>Тупая демка</title>
		</head>
		<body>
			<canvas id="cnv" width="600" height="600">Ставь нормальный браузер</canvas>
                        <script type="text/javascript" src='your_file.js'></script>
		</body>
</html>

Рисование на canvas происходит через контекст, который может быть получен вызовом метода canvas элемента getContext с аргументом ‘2d’.
Так что добавим в наш скрипт строку.

var ctx = document.getElementById('cnv').getContext('2d')

Прямоугольники

Прямоугольники в canvas это единственный примитив. Для работы с прямоугольниками существует всего 3 метода.

Заливаем прямоугольник

fillRect — рисует залитый прямоугольник, рассмотрим его аргументы

fillRect(float x, float y, float w, float h)

Где x и y это координаты верхнего левого угла, а w и h это ширина и высота соответственно. Давайте рассмотрим пример. Добавим в скрипт строку.

ctx.fillRect(200, 250, 200, 100)

Как многие догадались, после выполнения в центре холста будет нарисован прямоугольник шириной 200 пикселей и высотой 100 пикселей.

Обводим прямоугольник

strokeRect — работает точно также как и fillRect, но в отличие от него не заливает прямоугольник, а рисует только контуры. Добавим в скрипт строку.

ctx.strokeRect(150, 200, 300, 200)

Теперь вокруг залитого прямоугольника мы нарисовали контуры еще одного.

Отчищаем прямоугольник

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

ctx.clearRect(350, 300, 50, 50)

Таким образом мы обрезали часть залитого прямоугольника.

Пути

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

Начинаем путь

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

ctx.beginPath()

Идем к точке

moveTo(float x, float y)

— перемещает положение курсора на (x;y).
Добавим в наш скрипт строку:

ctx.moveTo(200,200)

Ведём линию к точке

lineTo(float x, float y)

— проводит линию от положения курсора к (x;y).
Для примера добавим в наш скрипт строку:

ctx.lineTo(400,400)

Обводим

Завершающим моментом будет вызов метода stroke чтобы показать линию на холсте. Так что добавим строку в скрипт:

ctx.stroke()

Теперь если открыть наш пример то мы увидим, что на холсте отрисовывается линия.

Замыкаем

Если мы рисуем какую нибудь фигуру и нам нужно сделать её замкнутой то мы можем применит метод closePath. Для примера нарисуем треугольник, для этого оставим в нашем файле только получение контекста и вставим туда следующие строки:

ctx.beginPath()
ctx.moveTo(200,200)
ctx.lineTo(400,400)
ctx.lineTo(200,400)
ctx.closePath()
ctx.stroke()

Если мы откроем файл что отрисовывается треугольник. При этом мы провели только две линии, а closePath нарисовал третью чтобы замкнуть фигуру.

Заливаем

Кроме отрисовки контуров мы можем еще и залить фигуру, для этого просто заменим в нашем скрипте вызова функции stroke на вызов fill. При это если вы заливаете фигуру то не обязательно явно замыкать фигуру вызывая closePath, ведь при вызове fill фигура замкнется автоматически.

Дуги

arc(float x, float y, float r, float startAngle, float endAngle, bool anticlockwise)

— нарисует дугу с центром в точке (x;y), радиусом — r, стартовым углом и конечным startAngle, endAngle соответственно и если anticlockwise = true то часть окружности идет против часовой стрелки, иначе по её направлению.
Примечание: углы измеряются в радианах
Давайте для примера нарисуем частично залитую окружность, для этого отчистим наш скрипт, оставим только получение контекста. Затем добавим следующие строки.

ctx.beginPath()
ctx.arc(200,300,70,0,Math.PI*0.85,false)
ctx.stroke()

ctx.beginPath()
ctx.arc(200,300,70,0,Math.PI*0.85,true)
ctx.fill()

Немного другие дуги

arcTo(float x1, float y1, float x2, float y2. float r)

— нарисует дугу с радиусом r заключенную между двумя отрезками — AB и BC, где точка A это положение курсора, B = (x1;y1) C = (x2;y2)
Давайте для примера оставим в скрипте только получение контекста и добавим следующие строки:

ctx.beginPath()
ctx.moveTo(200,300)
ctx.arcTo(300,100,400,300,50)
ctx.stroke()

Квадратичные кривые

quadraticCurveTo(float x1, float y1, float x2, float y2)

— нарисует квадратичную кривую образованную тремя точками (положение курсора, (x1;y1), (x2;y2)).
Для примера посмотрим что выполнить следующий код:

ctx.beginPath()
ctx.moveTo(100,100)
ctx.quadraticCurveTo(200,200,50,200)
ctx.stroke()

Кривые Безье

bezierCurveTo(float x1, float y1, float x2, float y2, float x3, float y3)

— нарисует кубическу кривую Безье. Для примера добавим в наш скрипт следующий код:

ctx.beginPath()
ctx.moveTo(100,100)
ctx.bezierCurveTo(200,200,100,300,50,100)
                   ctx.stroke()

Опять о прямоугольниках

rect(float x, float y, float w, float w)

— работает абсолютно идентично fillRect и strokeRect, но в отличие от них только добавляет прямоугольник в путь.

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

Это точка на фигуре?

isPointInPath(float x, float y)

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

ctx.beginPath()
ctx.rect(200,200,100,200)
console.log(ctx.isPointInPath(250,250))
console.log(ctx.isPointInPath(100,100))

Данный скрипт должен вывести в отладочную консоль сначала true, а затем false.

Ограничиваем область отрисовки


Кроме функции stroke и fill для работы с путями существует еще и функция clip, она ничего не рисует но тем не менее выполняет важную роль, после её вызова любой объект будет рисоваться только когда он находится в области на которой определен путь, давайте рассмотрим небольшой пример:


ctx.beginPath()
ctx.arc(200,300,70,0,Math.PI*2,true)
ctx.stroke()  //Нарисуем круг по которому определим область пути
ctx.clip()       //Ограничим область для рисования областью путя

ctx.beginPath()
ctx.moveTo(100,320)
ctx.lineTo(500,320)
ctx.lineTo(100,250)
ctx.stroke() //Нарисуем парочку линий, при чем они будут видны только внутри круга

В ближайшем будущем (в теории по части в два дня)

Стилизация, градиенты и тени
Отрисовка картинок и текста
Трансформация и композиция
Анимация и манипуляция imageData

Зачем еще одно руководство?

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

На эту страницу с поисковиков зашли

Canvas элемент

Canvas элемент имеет имя ‘canvas’ (ну кто бы мог подумать) и атрибуты ‘width’ и ‘height’, при чем стоит заметить что эти атрибуты не имеют отношения к CSS, они обозначают ширину и высоту canvas элемента в пикселях не на экране, а на координатной плоскости холста. К тому же текст внутри тега будет проигнорирован браузером с поддержкой canvas и показан в браузере без поддержки canvas.

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

<!doctype html>
<html>
		<head>
			<title>Тупая демка</title>
		</head>
		<body>
			<canvas id="cnv" width="600" height="600">Ставь нормальный браузер</canvas>
                        <script type="text/javascript" src='your_file.js'></script>
		</body>
</html>

Рисование на canvas происходит через контекст, который может быть получен вызовом метода canvas элемента getContext с аргументом ‘2d’.
Так что добавим в наш скрипт строку.

var ctx = document.getElementById('cnv').getContext('2d')

Прямоугольники

Прямоугольники в canvas это единственный примитив. Для работы с прямоугольниками существует всего 3 метода.

Заливаем прямоугольник

fillRect — рисует залитый прямоугольник, рассмотрим его аргументы

fillRect(float x, float y, float w, float h)

Где x и y это координаты верхнего левого угла, а w и h это ширина и высота соответственно. Давайте рассмотрим пример. Добавим в скрипт строку.

ctx.fillRect(200, 250, 200, 100)

Как многие догадались, после выполнения в центре холста будет нарисован прямоугольник шириной 200 пикселей и высотой 100 пикселей.

Обводим прямоугольник

strokeRect — работает точно также как и fillRect, но в отличие от него не заливает прямоугольник, а рисует только контуры. Добавим в скрипт строку.

ctx.strokeRect(150, 200, 300, 200)

Теперь вокруг залитого прямоугольника мы нарисовали контуры еще одного.

Отчищаем прямоугольник

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

ctx.clearRect(350, 300, 50, 50)

Таким образом мы обрезали часть залитого прямоугольника.

Пути

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

Начинаем путь

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

ctx.beginPath()

Идем к точке

moveTo(float x, float y)

— перемещает положение курсора на (x;y).
Добавим в наш скрипт строку:

ctx.moveTo(200,200)

Ведём линию к точке

lineTo(float x, float y)

— проводит линию от положения курсора к (x;y).
Для примера добавим в наш скрипт строку:

ctx.lineTo(400,400)

Обводим

Завершающим моментом будет вызов метода stroke чтобы показать линию на холсте. Так что добавим строку в скрипт:

ctx.stroke()

Теперь если открыть наш пример то мы увидим, что на холсте отрисовывается линия.

Замыкаем

Если мы рисуем какую нибудь фигуру и нам нужно сделать её замкнутой то мы можем применит метод closePath. Для примера нарисуем треугольник, для этого оставим в нашем файле только получение контекста и вставим туда следующие строки:

ctx.beginPath()
ctx.moveTo(200,200)
ctx.lineTo(400,400)
ctx.lineTo(200,400)
ctx.closePath()
ctx.stroke()

Если мы откроем файл что отрисовывается треугольник. При этом мы провели только две линии, а closePath нарисовал третью чтобы замкнуть фигуру.

Заливаем

Кроме отрисовки контуров мы можем еще и залить фигуру, для этого просто заменим в нашем скрипте вызова функции stroke на вызов fill. При это если вы заливаете фигуру то не обязательно явно замыкать фигуру вызывая closePath, ведь при вызове fill фигура замкнется автоматически.

Дуги

arc(float x, float y, float r, float startAngle, float endAngle, bool anticlockwise)

— нарисует дугу с центром в точке (x;y), радиусом — r, стартовым углом и конечным startAngle, endAngle соответственно и если anticlockwise = true то часть окружности идет против часовой стрелки, иначе по её направлению.
Примечание: углы измеряются в радианах
Давайте для примера нарисуем частично залитую окружность, для этого отчистим наш скрипт, оставим только получение контекста. Затем добавим следующие строки.

ctx.beginPath()
ctx.arc(200,300,70,0,Math.PI*0.85,false)
ctx.stroke()

ctx.beginPath()
ctx.arc(200,300,70,0,Math.PI*0.85,true)
ctx.fill()

Немного другие дуги

arcTo(float x1, float y1, float x2, float y2. float r)

— нарисует дугу с радиусом r заключенную между двумя отрезками — AB и BC, где точка A это положение курсора, B = (x1;y1) C = (x2;y2)
Давайте для примера оставим в скрипте только получение контекста и добавим следующие строки:

ctx.beginPath()
ctx.moveTo(200,300)
ctx.arcTo(300,100,400,300,50)
ctx.stroke()

Квадратичные кривые

quadraticCurveTo(float x1, float y1, float x2, float y2)

— нарисует квадратичную кривую образованную тремя точками (положение курсора, (x1;y1), (x2;y2)).
Для примера посмотрим что выполнить следующий код:

ctx.beginPath()
ctx.moveTo(100,100)
ctx.quadraticCurveTo(200,200,50,200)
ctx.stroke()

Кривые Безье

bezierCurveTo(float x1, float y1, float x2, float y2, float x3, float y3)

— нарисует кубическу кривую Безье. Для примера добавим в наш скрипт следующий код:

ctx.beginPath()
ctx.moveTo(100,100)
ctx.bezierCurveTo(200,200,100,300,50,100)
                   ctx.stroke()

Опять о прямоугольниках

rect(float x, float y, float w, float w)

— работает абсолютно идентично fillRect и strokeRect, но в отличие от них только добавляет прямоугольник в путь.

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

Это точка на фигуре?

isPointInPath(float x, float y)

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

ctx.beginPath()
ctx.rect(200,200,100,200)
console.log(ctx.isPointInPath(250,250))
console.log(ctx.isPointInPath(100,100))

Данный скрипт должен вывести в отладочную консоль сначала true, а затем false.

Ограничиваем область отрисовки


Кроме функции stroke и fill для работы с путями существует еще и функция clip, она ничего не рисует но тем не менее выполняет важную роль, после её вызова любой объект будет рисоваться только когда он находится в области на которой определен путь, давайте рассмотрим небольшой пример:


ctx.beginPath()
ctx.arc(200,300,70,0,Math.PI*2,true)
ctx.stroke()  //Нарисуем круг по которому определим область пути
ctx.clip()       //Ограничим область для рисования областью путя

ctx.beginPath()
ctx.moveTo(100,320)
ctx.lineTo(500,320)
ctx.lineTo(100,250)
ctx.stroke() //Нарисуем парочку линий, при чем они будут видны только внутри круга

В ближайшем будущем (в теории по части в два дня)

Стилизация, градиенты и тени
Отрисовка картинок и текста
Трансформация и композиция
Анимация и манипуляция imageData

Время на прочтение
3 мин

Количество просмотров 5.2K

Введение

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

Рисование изображений

Объект изображения

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

var img = new Image()
img.src = 'path.png'

Загрузим изображение

Теперь стоит заметить что прежде чем рисовать изображение его стоит загрузить для этого добавим обработчик события load для объекта img, добавим его после создания объекта, в итоге получится такой вот код:

var img       = new Image()
img.onload =  function(){
    //Тут ваш код для работы с контекстом
}
img.src       = 'path.png'

Нарисуем изображение

drawImage(object img, float x, float y)

— нарисует изображение с исходным размером так чтобы его верхний левый угол был в точке (x;y).

Масштабируем

drawImage(object img, float x, float y, float w, float h)

— работает также но вместо исходного размера рисует с шириной w и высотой h.

Обрежем

drawImage(object img, float sx, float sy, float sw, float sh, float cx, float cy, float cw, float ch)

— нарисует часть изображения шириной sw и высотой sh расположенную в точке (sx,sy) в исходном изображении на canvas с шириной cw и высотой ch в точке (cx,cy)

Рисование текста

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

Нарисуем залитым

ctx.fillText(string text, float x, float y)

— нарисует текст в точке (x;y).
Примечание: функция fillText имеет необязательный аргумент maxWidth, но он паршиво работает в FF и вообще не работает в Chrome.

Изменим шрифт


Свойство контекста font управляет стилем текста и имеет синтаксис схожий с css, для примера добавим в наш скрипт следующие строки:

ctx.font = "bold italic 30px sans-serif"
ctx.fillText("Привет Хабр",300,300)

Управлять цветом и не только мы можем через свойства fillStyle и strokeStyle

Нарисуем контуры


Внимательный читатель вероятнее всего логически догадался что для рисования контуров текста применяется функции strokeText, заменим в нашем примере fillText на strokeText.

Выравняем по горизонтали

Для выравнивания текста существует свойство textAlign, оно может принимать пять возможных значения:

  • left — текст выравнивается слева
  • right — текст выравнивается справа
  • center — текст выравнивается по центру
  • start — (значение по умолчанию) текст выравнивается от начала линии слева для письма слева на право и выравнивается справа для письма справа налево
  • end — текст выравнивается от начала линии справа для письма слева на право и выравнивается слева для письма справа налево

Линия основания текста

Для управления линией основания текста существует свойство textBaseline, оно может принимать следующие значения:top,hanging,middle,alphabetic,ideographic,bottom. Смысл этих значений легче показать чем описать, поэтому на WhatWG была найдена картинка:
image

Измерим ширину

measureText(string text)

— вернет специальный объект TextMetrics который на данный момент обладает только одним свойством — width — ширина текста в пикселях.

Сохранение изображений на стороне клиента

Для сохранения изображений существует аж три метода (getAsFile,getBlob,toDataURL), но мы рассмотрим лишь toDataURL поскольку именно он наиболее хорошо поддерживается браузерами. Стоит заметить что метод применяется не к контексту, а к canvas элементу, впрочем его можно получить как свойство ‘canvas’ контекста, также этот метод принимает как аргумент тип изображения (по умолчанию ‘png’). Этот метод вернет изображение в формате base64.

Сохранить нельзя восстановить

Если какое-то свойство контекста изменить то оно повлияет на все последующие, для упрощения жизни разработчикам в спецификации есть два метода контекста save и restore.
save — сохраняет текущее состояние
restore — восстанавливает последнее сохраненное
Рассмотрим простой пример:

ctx.save()
ctx.textAlign = 'center'
ctx.font = "bold italic 30px sans-serif"
ctx.strokeText("Привет Хабр",300,300)
ctx.restore()
ctx.fillText("Привет Хабр",400,400)

Как видно, вместо того чтобы сбрасывать все свойства на начальные мы просто использовали save и restore

Знакомство с новым элементом
Первый пример
Настройки цвета и размера
Прямоугольники
Линии и дуги
Окружности
Закруглённые углы
Кривые Безье
Функция clip() — ограничиваем область рисования
Тени
Градиенты
Прозрачность
Используем шаблоны
Треугольник Серпинского
Рисование изображений
Рисование текста
Комбинирование наложений

Знакомство с новым элементом

Canvas — это новый элемент HTML5, который предназначен для создания растрового изображения при помощи JavaScript. Само слово canvas переводится как холст или канва. Текст внутри тега будет проигнорирован браузером с поддержкой canvas и показан в браузере без поддержки canvas.


<canvas id="test" width="500" height="500">
    Здесь можно указать текст для тех,
    у кого не поддерживается тег canvas
</canvas>

У тега есть два атрибута — height (высота) и width (ширина). Если размеры не указать, то по умолчанию размер холста будет равен 150х300 пикселей. Canvas создает область фиксированного размера, содержимым которого управляют контексты. Атрибуты не имеют отношения к CSS, они обозначают ширину и высоту canvas в пикселях не на экране, а на координатной плоскости холста.

Не рекомендуется использовать CSS для установки высоты и ширины холста, так как в этом случае canvas подвергнется масштабированию. Задавайте размеры в элементе.

Также требуется установить обязательный идентификатор для обращению к элементу в JavaScript.

Также можно применить стиль, например, сделаем рамку вокруг холста и не будем устанавливать размеры, чтобы увидеть ширину и высоту по умолчанию.

Canvas


<canvas id="border" style = "border:2px solid black">Canvas</canvas>

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


var canvas = document.getElementById('my_canvas');
if (canvas.getContext){
    var context = canvas.getContext('2d');
}else{
    //  Сделать  что-то для  вывода  скрытого  содержимого 
    //  или  позволить  браузеру  вывести  текст элемента canvas
}

Мы находим элемент canvas по идентификатору, а затем вызываем метод getContext() с единственным параметром — строкой 2d. Если getContext() возвращает ответ, мы получаем 2D-контекст холста для добавления объектов.

Размер холста можно вычислить программно через свойства canvas.width и canvas.height.

Первый пример


  <canvas height='320' width='480' id='first_example'>Пример</canvas>
  <script>
    var canvas = document.getElementById("first_example");
    var context = canvas.getContext('2d');
    context.fillRect(0, 0, canvas.width, canvas.height);
  </script>

Пример

Если открыть созданный пример браузером, то увидим область с чёрным прямоугольником. Это и есть тот самый холст, на котором нарисован прямоугольник, размеры которого равны размерам элемента canvas. Если бы мы не рисовали чёрный прямоугольник, то у нас был бы прозрачный холст. Размеры задаются в пикселях, а отсчёт идёт от верхнего левого угла. На холсте можно рисовать различные фигуры. Можно указать отрицательные значения для координат, ошибки не произойдёт, но смысла в этом нет — фигуры не будут видны на экране.

Настройки цвета и размера

Стили для заливки и обводки имеют глобальный параметр. Если вы задали какое-то свойство, то оно применится для всех элементов, если не был после этого изменен. Например, мы сначала задали зелёный цвет для заливки и синий для обводки. Если после этого мы нарисуем несколько фигур, то они все будут иметь зелёный фон и синюю обводку.

За заливку отвечает свойство fillStyle. По умолчанию для заливки используется чёрный цвет. За цвет и стиль обводки отвечает свойство strokeStyle.

Цвет задается точно так же как и в CSS (четыре способа)


// все четыре строки задают оранжевый цвет заливки
context.fillStyle = "orange";
context.fillStyle = "#FFA500";
context.fillStyle = "rgb(255,165,0)";
context.fillStyle = "rgba(255,165,0,1)"

Есть ещё редко используемый способ через HSL — hsl(219, 58%, 93%).

Установим желаемые настройки — укажем, что мы хотим красный цвет (#FF0000) и толщину в 3 пиксела для обводки и зеленый цвет (#00FF00) для заливки:


context.strokeStyle = '#FF0000'; // Цвет обводки
context.lineWidth = 3; // Ширина линии
context.fillStyle = '#00FF00'; // Цвет заливки

Прямоугольники

Начнем с прямоугольника. В canvas есть два вида прямоугольников — залитые и незалитые (обводка). Предусмотрены три функции для рисования прямоугольников.

  • strokeRect(x, y, ширина, высота) — рисует границы прямоугольника
  • fillRect(x, y, ширина, высота) — рисует закрашенный прямоугольник
  • clearRect(x, y, ширина, высота) — Очищает область на холсте размер с прямоугольника заданного размера в указанной позиции

Функция clearRect() как бы вырезает кусок фигуры, за которым можно увидеть холст.


context.clearRect(10, 10, 200, 200); // Очистка области указанного размера и положения
context.clearRect(0, 0, canvas.width, canvas.height); // Очистка всего холста 

Нарисуем два вида прямоугольников.

Пример


var canvas = document.getElementById("rectangles");
var context = canvas.getContext('2d');

context.strokeStyle = '#FF0000'; // Цвет обводки
context.lineWidth = 3; // Ширина линии
context.fillStyle = '#00FF00'; // Цвет заливки

context.fillRect(10, 10, 390, 100);
context.strokeRect(40, 130, 200, 150);

Попробуйте нарисовать ещё один закрашенный прямоугольник и вырезать из него прямоугольник меньшего размера.

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

Наложение прямоугольников


<canvas id='rects'>Наложение прямоугольников</canvas>

<script>
    var canvas = document.getElementById("rects");
    var context = canvas.getContext('2d');
    canvas.height = 200;
    canvas.width = 300;
    
    context.fillStyle = "rgb(200, 0, 0)";
    context.fillRect(15, 15, 100, 100); 
    context.fillStyle = "rgb(0, 200, 0)";
    context.fillRect(30, 30, 100, 100);
    context.fillStyle = "rgb(0, 0, 200)";
    context.fillRect(45, 45, 100, 100);
</script>

Рисуем шахматную доску


<canvas id='chessboard'>Шахматная доска</canvas>

<script>
    var canvas = document.getElementById("chessboard");
    var context = canvas.getContext('2d');
    // Размеры холста
    canvas.width  = 300;
    canvas.height = 300;
    // Внешняя рамка для доски
    context.strokeRect(15, 15, 266, 266);
    // Внутренняя рамка для доски
    context.strokeRect(18, 18, 260, 260);
    // Закрашиваем внутреннюю область черным цветом
    context.fillRect(20, 20, 256, 256);
    for (i = 0; i < 8; i += 2)
      for (j = 0; j < 8; j += 2) {
        context.clearRect(20 + i * 32, 20 + j * 32, 32, 32);
        context.clearRect(20 + (i + 1) * 32, 20 + (j + 1) * 32, 32, 32);
      }
</script>

Шахматная доска

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

Раскрашиваем шахматную доску

Цветная шахматная доска


<canvas id='color_chessboard'>Цветная шахматная доска</canvas>

<script>
  var canvas = document.getElementById("color_chessboard");
  var context = canvas.getContext('2d');
  canvas.width  = 300;
  canvas.height = 300;
  context.strokeStyle = '#B70A02'; // меняем цвет рамки
  context.strokeRect(15, 15, 266, 266);
  context.strokeRect(18, 18, 260, 260);
  context.fillStyle = '#AF5200'; // меняем цвет клеток
  context.fillRect(20, 20, 256, 256);
  for (i = 0; i < 8; i += 2)
    for (j = 0; j < 8; j += 2) {
      context.clearRect(20 + i * 32, 20 + j * 32, 32, 32);
      context.clearRect(20 + (i + 1) * 32, 20 + (j + 1) * 32, 32, 32);
    }
</script>

Линии и дуги

Мы можем рисовать прямые и изогнутые линии, окружности и другие фигуры. Замкнутые линии можно заливать цветом. В отличии от рисования прямоугольников, рисование линий это не одна команда, а их последовательность. Так, сначала надо объявить начало новой линии с помощью beginPath(), а в конце сказать от том, что рисование линии заканчивается с помощью closePath(). У каждого отрезка линии есть начало и конец.

beginPath используется что бы «начать» серию действий описывающих отрисовку фигуры. Каждый новый вызов этого метода сбрасывает все действия предыдущего и начинает «рисовать» снова.

closePath является не обязательным действием и по сути оно пытается завершить рисование проведя линию от текущей позиции к позиции с которой начали рисовать.

Завершающий шаг — это вызов методов stroke или fill. stroke обводит фигуру линиями, а fill заливает фигуру сплошным цветом.

Также существуют такие методы как,

  • moveTo(x, y) — перемещает «курсор» в позицию x, y и делает её текущей
  • lineTo(x, y) — ведёт линию из текущей позиции в указанную, и делает в последствии указанную текущей
  • arc(x, y, radius, startAngle, endAngle, anticlockwise) — рисование дуги, где x и y центр окружности, далее начальный и конечный угол, последний параметр указывает направление

Давайте нарисуем ломаную, состоящую из двух отрезков:


context.beginPath();
context.moveTo(10, 10); // Начало линии 
context.lineTo(100, 100); // Узел линии  
context.lineTo(150, 100); // Конец линии 
context.closePath();

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


context.beginPath();  
context.moveTo(50, 50);  
context.lineTo(50, 250);  
context.lineTo(250, 250);  
context.closePath();  
context.fill();

Изменяем ширину линии

Значение ширины линии хранится в свойстве lineWidth контекста canvas и одна единица соответствует одному пикселю. Значение по умолчанию естественно 1.0

Стиль верхушки линий

Стиль верхушки линии хранится в свойстве lineCap и для него существуют три возможных значения:

  • butt (по умолчанию)
  • round
  • sqare

,

Стиль соединения линий

Стиль соединения линий хранится в свойстве lineJoin и может принимать три возможных значения:

  • miter (по умолчанию)
  • round
  • bevel

Мы можем ограничить длину огромного хвоста miter с помощью свойства miteLimit, которое по умолчанию принимает значение 10.

Рисуем корону

Корона


<canvas id='crown'>Корона</canvas>

<script>
    var canvas = document.getElementById("crown");
    var context = canvas.getcanvas('2d');
    canvas.height = 200;
    canvas.width = 200;
    context.beginPath();
    context.arc(80, 100, 56, 3/4 * Math.PI, 1/4 * Math.PI, true);
	//Заливаем дугу
    context.fill();
    context.moveTo(40, 140);
    context.lineTo(20, 40);
    context.lineTo(60, 100);
    context.lineTo(80, 20);
    context.lineTo(100, 100);
    context.lineTo(140, 40);
    context.lineTo(120, 140);
	// Обводим контур короны
    context.stroke();
</script>

Окружности

Окружности рисуются с помощью команды arc(ox, oy, radius, startAngle, endAngle, antiClockWise), где ox и oy — координаты центра, radius — радиус окружности, startAngle и endAngle — начальный и конечный углы (в радианах) для отрисовки окружности, а antiClockWise — направление движения при отрисовке (true для против часовой стрелке, false — против). С помощью arc() можно рисовать как круги и окружности, так и дуги и части окружности.

Окружность с радиусом в 100 пикселей:


context.beginPath();  
context.arc(250, 250, 100, 0, Math.PI * 2, false);  
context.closePath();
context.fill(); // Заливка окружности

Нарисуем разноцветный круг:

Код нарисует круг, состоящий из 6 сегментов с произвольными цветами, которые будут меняться при обновлении страницы


<canvas id="color_circle" width="300" height="200"></canvas>
 
<script>
    canvas = document.getElementById("color_circle");
    context = canvas.getContext("2d");
    
    for(var i = 0; i < 6;i++){
        context.fillStyle = 'rgb(' + Math.round(Math.random()*255) + ',' + Math.round(Math.random() * 255) + ',' + Math.round(Math.random()*255) +')'
    context.beginPath();
    context.arc(100, 100, 70, Math.PI/3 * i, Math.PI/3 * (i + 1), false)
    context.lineTo(100, 100);
    context.fill();
}
</script>

Нарисуем дольки апельсина или арбуза, а также другие варианты с использованием собственной процедуры.

Дольки


<canvas id='arc_demo'>Дольки</canvas>

<script>
  var canvas = document.getElementById("arc_demo");
  var context = canvas.getContext('2d');
  canvas.height = 200;
  canvas.width = 500;
  
  function drawArc(xPos, yPos, radius, startAngle, endAngle, anticlockwise, lineColor, fillColor)
  {
    var startAngle = startAngle * (Math.PI/180);
    var endAngle = endAngle * (Math.PI/180);
    var radius = radius;
    context.strokeStyle = lineColor;
    context.fillStyle = fillColor;
    context.lineWidth = 8;
    context.beginPath();
    context.arc(xPos, yPos, radius, startAngle, endAngle, anticlockwise);
    context.fill();
    context.stroke();
  }
  
  drawArc(50, 15, 40, 0, 180, false, "aqua", "yellow");
  drawArc(150, 15, 50, 350, 170, false, "green", "pink");
  drawArc(270, 70, 60, 0, 100, true, "red", "white");
  drawArc(400, 60, 50, 350, 20, true, "blue", "purple");
</script>

Теперь нарисуем круги из этих же фигур.

Дольки


<canvas id='circles_demo'>Дольки</canvas>

<script>
  var canvas = document.getElementById("circles_demo");
  var context = canvas.getContext('2d');
  canvas.height = 200;
  canvas.width = 500;
  
  function drawCircle(xPos, yPos, radius, lineColor, fillColor)
  {
    var startAngle = 0 * (Math.PI/180);
    var endAngle = 360 * (Math.PI/180);
    var radius = radius;
    context.strokeStyle = lineColor;
    context.fillStyle = fillColor;
    context.lineWidth = 8;
    context.beginPath();
    context.arc(xPos, yPos, radius, startAngle, endAngle, false);
    context.fill();
    context.stroke();
  }
  
  drawCircle(50, 45, 40, "aqua", "yellow");
  drawCircle(150, 55, 50, "green", "pink");
  drawCircle(270, 70, 60, "red", "white");
  drawCircle(400, 65, 50, "blue", "purple");
</script>

Частичная заливка окружности

Нарисуем частично залитую окружность.

Частично залитая окружность


<canvas id='part_circle'>Частично залитая окружность</canvas>

<script>
  var canvas = document.getElementById("part_circle");
  var context = canvas.getContext('2d');
  canvas.height = 400;
  canvas.width = 400;
  context.beginPath();
  context.arc(200, 200, 100, 0, Math.PI * 0.85, false)
  context.stroke();

  context.beginPath();
  context.arc(200, 200, 100, 0, Math.PI * 0.85, true);
  context.fill();
</script>

Много кругов

Нарисуем круги в случайном порядке.

круги в случайном порядке


<canvas id='random_circle'>круги в случайном порядке</canvas>

<script>
  var canvas = document.getElementById("random_circle");
  var context = canvas.getContext('2d');
  canvas.height = 400;
  canvas.width = 400;
  
  var numCircles = 500;
  var maxRadius = 20;
  var minRadius = 3;
  var colors =
      ["aqua", "black", "blue", "fuchsia", "green", "cyan", "lime", "maroon",
      "navy", "olive", "purple", "red", "silver", "teal", "yellow", "azure",
      "gold", "bisque", "pink", "orange"];
  var numColors = colors.length;
  
  // в цикле создаём круги
  for(var n = 0; n < numCircles; n++)
  {
    // в случайном порядке установим характеристики
    var xPos = Math.random() * canvas.width;
    var yPos = Math.random() * canvas.height;
    var radius = minRadius + (Math.random() * (maxRadius-minRadius));
    var colorIndex = Math.random() * (numColors - 1);
    colorIndex = Math.round(colorIndex);
    var color = colors[colorIndex];
    drawCircle(context, xPos, yPos, radius, color);
  }
  
  // функция для рисования круга
  function drawCircle(context, xPos, yPos, radius, color)
  {
    var startAngle = (Math.PI / 180) * 0;
    var endAngle = (Math.PI / 180) * 360;
    context.shadowColor = "gray";
    context.shadowOffsetX = 1;
    context.shadowOffsetY = 1;
    context.shadowBlur = 5;
    context.beginPath();
    context.arc(xPos, yPos, radius, startAngle, endAngle, false);
    context.fillStyle = color;
    context.fill();
  }
</script>

Clock

Закруглённые углы

Закруглённые углы рисуются при помощи функции arcto(), который содержит пять параметров.

  • xBeginning — координата X начала дуги
  • yBeginning — координата Y начала дуги
  • xEnd — координата X конца дуги
  • yEnd — координата Y конца дуги
  • Radius — радиус дуги

Закруглённые углы


<canvas id='arcto'>Закруглённые углы</canvas>

<script>
  var canvas = document.getElementById("arcto");
  var context = canvas.getContext('2d');
  canvas.height = 150;
  canvas.width = 400;
  
  var xPos = 25; 
  var yPos = 25; 
  var width = 150;
  var height = 75; 
  var radius = 30;
  
  context.strokeStyle = "blue"; 
  context.lineWidth = 20;
  context.lineCap = "square"; 
  context.shadowOffsetX = 3;
  context.shadowOffsetY = 3; 
  context.shadowBlur = 5;
  context.shadowColor = "gray";
  context.beginPath();
  context.moveTo(xPos, yPos);  
  context.lineTo(xPos + width - radius, yPos);
  context.arcTo(xPos + width, yPos, xPos + width, yPos + radius, radius);
  context.lineTo(xPos + width, yPos + height);
  context.stroke();
</script>

Кривые Безье

Имеются две функции, для построения кубической и квадратичной кривой Безье:

quadraticCurveTo(Px, Py, x, y)
bezierCurveTo(P1x, P1y, P2x, P2y, x, y)

x и y — это точки в которые необходимо перейти, а координаты P(Px, Py) в квадратичной кривой это дополнительные точки, которые используются для построения кривой. В кубической кривой соответственно две дополнительные точки.

Рисуем кривые Безье

Кривая Безье


<canvas id='bezier_demo'>Кривая Безье</canvas>

<script>
    var canvas = document.getElementById("bezier_demo");
    var context = canvas.getContext('2d');
    canvas.height = 200;
    canvas.width = 260;
    context.beginPath();
    context.moveTo(10, 15);
    context.bezierCurveTo(75, 55, 175, 20, 250, 15);
    context.moveTo(10, 15);
    context.quadraticCurveTo(100, 100, 250, 15);
    context.stroke();
</script>

Раскрашиваем кривые Безье

Раскрашиваем кривые Безье


<canvas id='color_bezier'>Раскрашиваем кривые Безье</canvas>

<script>
  var canvas = document.getElementById("color_bezier");
  var context = canvas.getContext('2d');
  canvas.height = 100;
  canvas.width = 260;
  context.strokeStyle = '#f00';
  context.beginPath();
  context.moveTo(10, 15);
  context.bezierCurveTo(75, 55, 175, 20, 250, 15);
  context.stroke();
  context.strokeStyle = '#0f0';
  context.beginPath();
  context.moveTo(10, 15);
  context.quadraticCurveTo(100, 100, 250, 15);
  context.stroke();
</script>

Это точка на фигуре?

Функция isPointInPath(float x, float y) вернёт значение true, если точка с переданными координатами находится внутри пути. Создадим путь в виде прямоугольника и проверим:

Пример 8

Данный скрипт должен вывести в отладочную консоль сначала true, а затем false.


<p><canvas id='example8'>Пример 8</canvas></p>

<script type="text/javascript">
  var example = document.getElementById("example8");
  var ctx = example.getContext('2d');
  example.height = 400;
  example.width = 400;
  ctx.beginPath();
  ctx.rect(200, 200, 100, 200);
  ctx.stroke();
  console.log(ctx.isPointInPath(250, 250));
  console.log(ctx.isPointInPath(100, 100));
</script>

Функция clip() — ограничиваем область рисования

Функция clip() ничего не рисует. После её вызова любой объект будет рисоваться только в том случае, когда он находится в области на которой определён путь. Нарисуем круг и ограничим область рисования этим кругом. Затем нарисуем две линии, которые будут видны только внутри круга:

Clip

Если закомментировать вызов функции clip(), то увидим, как на самом деле рисуются линии.

No clip


<canvas id='clip_demo'>Clip</canvas>

<script>
  var canvas = document.getElementById("clip_demo");
  var context = canvas.getContext('2d');
  canvas.height = 400;
  canvas.width = 600;
  context.beginPath();
  context.arc(200, 200, 150, 0, Math.PI * 2, true);
  context.stroke();  //Нарисуем круг по которому определим область пути
  context.clip();       //Ограничим область для рисования областью пути

  context.beginPath();
  context.moveTo(100, 320);
  context.lineTo(500, 120);
  context.lineTo(50, 250);
  context.stroke() //Нарисуем линии, которые будут видны только внутри круга
</script>

Тени

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

  • shadowOffsetX = 0.0
  • shadowOffsetY = 0.0
  • shadowBlur = 0.0
  • shadowColor = «transparent black»

Возьмем предыдущий пример и посмотрим на тени

Shadow


<canvas id='clip_shadow'>Shadow</canvas>

<script>
  var canvas = document.getElementById("clip_shadow");
  var context = canvas.getContext('2d');
  canvas.height = 400;
  canvas.width = 600;
  context.beginPath();
  context.arc(200, 200, 150, 0, Math.PI * 2, true);
  context.stroke();  //Нарисуем круг по которому определим область пути
  context.clip();       //Ограничим область для рисования областью пути
    
  context.shadowOffsetX = -10;
  context.shadowOffsetY = -10;
  context.shadowBlur = 2;
  context.shadowColor = 'black';

  context.beginPath();
  context.moveTo(100, 320);
  context.lineTo(500, 120);
  context.lineTo(50, 250);
  context.stroke() //Нарисуем линии, которые будут видны только внутри круга
</script>

Пример с прямоугольниками.

Shadow


<canvas id='rect_shadow'>Shadow</canvas>

<script>
  var canvas = document.getElementById("rect_shadow");
  var context = canvas.getContext('2d');
  canvas.height = 100;
  canvas.width = 600;
  
  var x1Pos = 25;
  var x2Pos = 200;
  var yPos = 10;
  var length = 150; var height = 50;
  
  // первый прямоугольник с тенью
  context.shadowOffsetX = 4;
  context.shadowOffsetY = 4;
  context.shadowBlur = 3;
  context.fillStyle = "deeppink";
  context.shadowColor = "gray";
  context.fillRect (x1Pos, yPos, length, height);
  
  // второй прямоугольник с тенью
  context.shadowOffsetX = 12;
  context.shadowOffsetY = 12;
  context.shadowBlur = 4;
  context.strokeStyle = "aqua";
  context.shadowColor = "lightgreen";
  context.lineWidth = 8;
  context.strokeRect (x2Pos, yPos, length, height);
</script>

Градиенты

Линейные градиенты

Сначала создаётся объект градиента при помощи функции createLinearGradient(float x1, float y1, float x2, float y2) из точки (x1; y1) в точку (x2; y2). Затем добавляются цвета при помощи функции addColorStop(float offset, string color), где offset — отступ со значениями от 0 до 1, а color — нужный цвет. Далее созданный градиент применяется как стиль заливки в свойстве fillStyle.


<canvas id="lineargradient" width="160" height="160"></canvas>
    
<script>
    var canvas = document.getElementById("lineargradient");
    var context = canvas.getContext("2d");
    var gradient = context.createLinearGradient(0, 0, 150, 150);
    gradient.addColorStop(0.0, 'blue');
    gradient.addColorStop(0.5, 'red');
    gradient.addColorStop(1.0, 'green');
    context.fillStyle = gradient;
    
    // рисуем залитый прямоугольник
    context.fillRect(0, 0, 150, 150);
        
</script>

Радиальные градиенты

Радиальный градиент создаётся с помощью функции createRadialGradient(float x1, float y1, float r1, float x2, float y2, float r2) — плавный переход цвета из окружности с центром в точке (x1; y1) и радиусом r1 в окружность с центром точке (x2; y2) и радиусом r2.

Нарисуем шар с псевдо-освещением


<canvas id="radialgradient" width="500" height="170"></canvas>
    
<script>
    var canvas = document.getElementById("radialgradient");
    var context = canvas.getContext("2d");
    
    context.shadowOffsetX = 10;
    context.shadowOffsetY = 15;
    context.shadowBlur = 10;
    context.shadowColor = '#0F0';
    
    var gradient = context.createRadialGradient(60, 60, 15, 75, 75, 75);
    gradient.addColorStop(0.0, '#0F0');
    gradient.addColorStop(1.0, '#0DA805');

    context.fillStyle = gradient;

    context.beginPath();
    context.arc(75, 75, 75, 0, Math.PI * 2, false);
    context.fill();
        
</script>

Прозрачность

Прозрачность задаётся через атрибут globalAlpha. Значения находятся в диапазоне от 0 до 1, где 0 — полная прозрачность, 1 — сплошной цвет.


<canvas id="transparent_demo" width="500" height="100"></canvas>
    
<script>
    var canvas = document.getElementById("transparent_demo");
    var context = canvas.getContext("2d");
    
    // первый объект
    var xPos = 20;
    var yPos = 20;
    var gap = -20;
    var width = 80; var height = 80;
    
    // тень
    context.shadowOffsetX = 4;
    context.shadowOffsetY = 4;
    context.shadowBlur = 3;
    context.shadowColor = "gray";
    
    // прозрачность
    context.globalAlpha = 1;
    context.fillStyle = "orange";
    context.fillRect (xPos + (0 * width) + (0 * gap), yPos, width, height);
    context.globalAlpha = .5;
    context.fillStyle = "blue";
    context.fillRect (xPos + (1 * width) + (1 * gap), yPos, width, height);
    context.globalAlpha = .25;
    context.fillStyle = "red";
    context.fillRect (xPos + (2 * width) + (2 * gap), yPos, width, height);
    context.globalAlpha = .25;
    context.fillStyle = "limegreen";
    context.fillRect (xPos + (3 * width) + (3 * gap), yPos, width, height);
    context.globalAlpha = .4;
    context.fillStyle = "magenta";
    context.fillRect (xPos + (4 * width)+(4 * gap), yPos, width, height);
    context.globalAlpha = .25;
    context.fillStyle = "gold";
    context.fillRect (xPos + (5 * width) + (5 * gap), yPos, width, height);
    context.globalAlpha = .4;
    context.fillStyle = "turquoise";
    context.fillRect (xPos + (6 * width) + (6 * gap), yPos, width, height);

Также прозрачность можно задать в атрибутах цвета:


context.fillStyle = "rgb(0, 0, 255, .5)";

Используем шаблоны

Кроме цветов и градиентов fillStyle и strokeStyle в качестве значения могут принимать и так называемые шаблоны. Шаблоны можно создать из того же самого canvas элемента, изображения или видео. Для примера будем использовать изображение. Шаблон создается методом createPattern(object any, string repeat), где repeat может принимать следующие значения:«repeat» (по умолчанию),«repeat-x»,«repeat-y»,«no-repeat».

Треугольник Серпинского


<canvas id="pascalCanvas" width="800" height="800"></canvas>
 
<script>
 
    function drawPixel(x, y, context) {
        context.fillRect(x, y, 1, 1);
    }
 
    var canvas = document.getElementById("pascalCanvas");
    var context = canvas.getContext("2d");
 
    // gradient style
    var gradient = context.createLinearGradient(0, 0, 0, canvas.height);
    gradient.addColorStop(0, "#00f");
    gradient.addColorStop(1, "#f30");
    context.fillStyle = gradient;
    //context.fillStyle = "#000";
 
    //Pascal's triangle
    var tr = new Array(canvas.height);
    for (i = 0; i < canvas.height; i++) {
        tr[i] = new Array(canvas.width);
        for (k = 0; k < canvas.width; k++) {
            if (k == 0)
                tr[i][k] = 1;
            else
                tr[i][k] = 0;
        }
    }
 
    for (i = 1; i < canvas.height; i++) {
        for (k = 1; k < canvas.width; k++) {
            tr[i][k] = (tr[i-1][k-1] + tr[i-1][k]) % 2;
        }
    }
 
    //draw
    for (i = 0; i < canvas.height; i++) {
        for (k = 0; k < canvas.width; k++) {
            if (tr[i][k] != 0)
            drawPixel(k, i, context);
        }
    }
</script>

Отсюда

Рисование изображений

Чтобы нарисовать изображение, нужно создать его объект с помощью конструктора Image, затем установить путь к изображению через свойство src полученного объекта.

Прежде чем рисовать изображение, его стоит загрузить. Для этого добавим обработчик события load для объекта img, добавим его после создания объекта.

Далее можно нарисовать изображение исходного размера с помощью функции drawImage(object img, float x, float y), где указывается его верхний левый угол в точке (x;y).

Для масштабирования используется другая версия функции — drawImage(object img, float x, float y, float w, float h) — в последних двух параметрах указывается ширина и высота.

Также можно обрезать картинку через ещё одну версию функции drawImage(object img, float sx, float sy, float sw, float sh, float cx, float cy, float cw, float ch) — нарисует часть изображения шириной sw и высотой sh расположенную в точке (sx,sy) в исходном изображении на canvas с шириной cw и высотой ch в точке (cx,cy).


var img = new Image()
img.onload =  function(){
    //Тут ваш код для работы с контекстом
}
img.src = 'path.png'

Выведем изображения с разными размерами.


<canvas id="images_demo" width="500" height="150" style = "border:2px solid black"></canvas>
    
<script>
    var canvas = document.getElementById("images_demo");
    var context = canvas.getContext("2d");
    
    var smallImageXPos = 40;
    var smallImageYPos = 55;
    var smallImageWidth = 75;
    var smallImageHeight = 75;
    var largeImageXPos = 225;
    var largeImageYPos = 10;
    var sourceCropX = 25;
    var sourceCropY = 25;
    var sourceCropWidthX = 50;
    var sourceCropWidthY = 50;
    var imageWidth = 80;
    var imageHeight = 80;
    
    var smallImage = new Image();
    var largeImage = new Image();
    
    smallImage.onload = function()
    {
        context.drawImage(smallImage, smallImageXPos, smallImageYPos);
        context.drawImage(smallImage, smallImageXPos + 80, smallImageYPos - 25,
        smallImageWidth, smallImageHeight);
    }
    
    largeImage.onload = function()
    {
        context.drawImage(largeImage, largeImageXPos, largeImageYPos);
         context.drawImage (largeImage, sourceCropX, sourceCropY,
        sourceCropWidthX, sourceCropWidthY,
        largeImageXPos + 140, largeImageYPos + 10,
        imageWidth, imageHeight);
    }
    
    smallImage.src = "../images/star.jpg";
    largeImage.src = "../images/star.jpg";

    context.shadowOffsetX = -3;
    context.shadowOffsetY = 3;
    context.shadowBlur = 8;
    context.shadowColor = "gray";
</script>

Нельзя вызывать метод drawImage(), если картинка не загружена в браузер. В примере я заранее вывел картинку при помощи тега img. Обычно, в подобных случаях используют вызов window.onload() или document.getElementById(«imageID»).onload.

Ваш браузер не поддерживает canvas


<canvas id="otherImage" width="250" height="300" style="border:1px solid #d3d3d3;">
    Ваш браузер не поддерживает canvas
</canvas>

<script>
window.onload = function() {
    var canvas = document.getElementById('otherImage');
    var context = canvas.getContext('2d');
    var image = new Image();

    image.onload = function() {
       context.drawImage(image, 30, 30);
    };
      
    image.src = 'http://developer.alexanderklimov.ru/android/images/android_cat.jpg';
}
</script>

Для сохранения изображений существует три метода (getAsFile,getBlob,toDataURL), самый удобный — toDataURL поскольку именно он наиболее хорошо поддерживается браузерами. Стоит заметить что метод применяется не к контексту, а к canvas элементу, впрочем его можно получить как свойство ‘canvas’ контекста, также этот метод принимает как аргумент тип изображения (по умолчанию ‘png’). Этот метод вернет изображение в формате base64.

Рисование текста

Существуют функции рисование текста. Залитый текст рисуется через функцию context.fillText(string text, float x, float y) в точке (x;y)

Функция fillText() имеет необязательный аргумент maxWidth, который не совсем корректно работает в некоторых браузерах.

Свойство контекста font управляет стилем текста и имеет синтаксис схожий с css:


// формат
// context.font = "style weight size face";

Не все атрибуты свойства font обязательно указывать. Если какой-то атрибут пропущен, то будет использоваться значение по умолчанию.

Для стилей используются следующие значения

  • normal(the default)
  • italic
  • oblique(similar to italic, usually associated with sans-serif faces)
  • inherit (style comes from the parent element)

Для веса используются значения:

  • normal(the default)
  • bold | bolder
  • lighter
  • 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900
  • inherit(weight comes from the parent element)

Для размеров:

  • px — pixels
  • pt — points
  • em

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

  • Sans-serif: Arial, Verdana
  • Serif: Georgia, Times New Roman, Times
  • Monospace: Courier New, Courier
    
context.font = "bold italic 30px sans-serif";
context.fillText("Hello Kitty", 300, 300);

Управлять цветом мы можем через свойства fillStyle и strokeStyle.

Для рисования контуров текста применяется функции strokeText() вместо fillText().

Для выравнивания текста существует свойство textAlign, оно может принимать пять возможных значений:

  • left — текст выравнивается слева
  • right — текст выравнивается справа
  • center — текст выравнивается по центру
  • start — (значение по умолчанию) текст выравнивается от начала линии слева для письма слева на право и выравнивается справа для письма справа налево
  • end — текст выравнивается от начала линии справа для письма слева на право и выравнивается слева для письма справа налево

<canvas id="textalign_demo" width="500" height="170" style = "border:2px solid black"></canvas>
    
<script>
    var canvas = document.getElementById("textalign_demo");
    var context = canvas.getContext("2d");
    var xPos = canvas.width/2;
    var yPos = 30;
    
    context.font = "15pt Arial";
    context.fillStyle = "blue";
    context.strokeStyle = "hotpink";
    context.lineWidth = 1;
    context.beginPath();
    context.moveTo(xPos, 0);
    context.lineTo(xPos, canvas.height);
    context.stroke();
    context.textAlign = "right";
    context.fillText("right", xPos, yPos * 1);
    context.textAlign = "end";
    context.fillText("end", xPos, yPos * 2);
    context.textAlign = "center";
    context.fillText("center", xPos, yPos * 3);
    context.textAlign = "left";
    context.fillText("left", xPos, yPos * 4);
    context.textAlign = "start";
    context.fillText("start", xPos, yPos * 5);
</script>

Для управления линией основания текста существует свойство textBaseline, оно может принимать следующие значения:

  • top
  • hanging
  • middle
  • alphabetic
  • ideographic
  • bottom

Измерить ширину текста можно через measureText(string text). Она вернет специальный объект TextMetrics, который обладает свойством width — ширина текста в пикселях.


<canvas id="drawtext_demo" width="500" height="170"></canvas>
    
<script>
    var canvas = document.getElementById("drawtext_demo");
    var context = canvas.getContext("2d");
    
    // центрируем текст
    var mText = "Hello Kitty!";
    var xPos = canvas.width/2;
    var yPos = canvas.height/2;

    context.font = "60pt Comic Sans MS";
    context.fillStyle = "lime";
    context.textAlign = "center";
    context.textBaseline = "middle";
    context.fillText(mText, xPos, yPos);
        
</script>

Комбинирование наложений

Наложение двух фигур можно осуществить при помощи свойства globalCompositeOperation, которое может принимать одно из значений.

  • source-over
  • source-in
  • source-out
  • source-atop
  • destination-over
  • destination-in
  • destination-out
  • destination-atop
  • lighter
  • copy
  • xor

Выведем все способы в таблице.


source-over

source-in

source-out

source-atop

destination-over

destination-in

destination-out

destination-atop

lighter

copy

xor

<table border="1" align="center">
  <tr>
    <td>
      <canvas id="source-over" width="120" height="110"></canvas><br/><l>source-over</l>
    </td>
    <td>
        <canvas id="source-in" width="120" height="110"></canvas><br/><l>source-in</l>
    </td>
    <td>
        <canvas id="source-out" width="120" height="110"></canvas><br/><l>source-out</l>
    </td>
    <td>
        <canvas id="source-atop" width="120" height="110"></canvas><br/><l>source-atop</l>
    </td>
  </tr>
  <tr>
    <td>
        <canvas id="destination-over" width="120" height="110"></canvas><br/><l>destination-over</l>
    </td>
    <td>
        <canvas id="destination-in" width="120" height="110"></canvas><br/><l>destination-in</l>
    </td>
    <td>
        <canvas id="destination-out" width="120" height="110"></canvas><br/><l>destination-out</l>
    </td>
    <td>
        <canvas id="destination-atop" width="120" height="110"></canvas><br/><l>destination-atop</l>
    </td>
  </tr>
  <tr>
      <td>
        <canvas id="lighter" width="120" height="110"></canvas><br/><l>lighter</l>
      </td>
      <td>
        <canvas id="copy" width="120" height="110"></canvas><br/><l>copy</l>
      </td>
      <td>
        <canvas id="xor" width="120" height="110"></canvas><br/><l>xor</l>
      </td>
    </tr>
</table>

<script>
    function drawShapes(type)
    {
        canvas = document.getElementById(type);
        context = canvas.getContext("2d");
        var squareOffset = 15;
        var squareSide = 70;
        var circleOffset = 73;
        var circleRadius = 35;

        context.fillStyle = "blue";
        context.fillRect(squareOffset, squareOffset, squareSide, squareSide);

        context.globalCompositeOperation = type;

        context.fillStyle = "red";
        context.beginPath();
        context.arc(circleOffset, circleOffset, circleRadius, 0, Math.PI * 2, true);
        context.fill();
    }
    
    drawShapes("source-over");
    drawShapes("source-in");
    drawShapes("source-out");
    drawShapes("source-atop");
    drawShapes("destination-over");
    drawShapes("destination-in");
    drawShapes("destination-out");
    drawShapes("destination-atop");
    drawShapes("lighter");
    drawShapes("copy");
    drawShapes("xor");
</script>
Реклама

Введение

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

Сделаем наш холст разноцветным


Как вы уже заметили в canvas есть два типа операции отрисовки fill и rect и у каждого есть свои настройки стилей. Для их изменения нужно менять свойства контекста fillStyle и strokeStyle, эти свойства в качестве значения могут принимать не только цвета, но и другие значения которые мы рассмотрим позже. А сейчас мы рассмотрим как поменять цвет. Для этого нужно просто присвоить свойствам fillStyle и strokeStyle новый значения, в случае с цветами это будут строки, при этом canvas поддерживает следующие схемы описания цветов: orange, #FFA500, rgb(255,165,0), rgba(255,165,0,1).
Для примера нарисуем разноцветный круг, оставим в нашем скрипте только получение контекста, а затем добавим следующий код:

for(var i=0;i<6;i++){
    ctx.fillStyle = 'rgb(' + Math.round(Math.random()*255) + ',' + Math.round(Math.random()*255) + ',' + Math.round(Math.random()*255) +')'
    ctx.beginPath()
    ctx.arc(300,300,70,Math.PI/3*i,Math.PI/3*(i+1),false)
    ctx.lineTo(300,300)
    ctx.fill()
}

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

Поработаем с линиями

Мы также можем изменить некоторые параметры у линий для этого существует несколько свойств, давайте рассмотрим по порядку каждое из них.

Изменяем ширину линии

Значение ширины линии хранится в свойстве lineWidth контекста canvas и одна единица соответствует одному пикселю. Значение по умолчанию естественно 1.0

Стиль верхушки линий


Стиль верхушки линии хранится в свойстве lineCap и для него существует три возможных значение: butt, round, sqare, стилем по умолчанию является butt.

Стиль соединения линий


Стиль соединения линий хранится в свойстве lineJoin и может принимать три возможных значение: miter, round, bevel, стилем по умолчанию является miter.

Еще немного о miter

Мы можем ограничить длину огромного хвоста miter с помощью свойства miteLimit которое по умолчанию принимает значение 10.

Отбросим тени


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

shadowOffsetX = 0.0
shadowOffsetY = 0.0
shadowBlur = 0.0
shadowColor = "transparent black"

Для примера отбросим две тени на друг друга в ограниченной области рисования и посмотрим что произойдет:

ctx.beginPath()
ctx.arc(200,300,70,0,Math.PI*2,true)
ctx.stroke()
ctx.clip()

ctx.shadowOffsetX = -10
ctx.shadowOffsetY = -10
ctx.shadowBlur = 2
ctx.shadowColor = 'black'

ctx.beginPath()
ctx.moveTo(100,320)
ctx.lineTo(500,320)
ctx.moveTo(500,180)
ctx.lineTo(100,370)
ctx.stroke()

Используем градиенты

Как в прошлой части мы рассмотрели пути так и в этой мы рассмотрим градиенты.

Линейные градиенты

Создание объекта градиента

createLinearGradient(float x1, float y1, float x2, float y2)

— создаст объект линейного градиента проходящего из точки (x1;y1) в точку (x2;y2), добавим в наш код строку:

var gr = ctx.createLinearGradient(0,0,150,150)

Добавляем цвета в градиент

addColorStop(float offset, string color)

— добавит в наш градиент цвет color с отступом offset который принимает значения от 0 до 1.
Добавим в наш скрипт строки:

gr.addColorStop(0.0,'blue')
gr.addColorStop(0.5,'red')
gr.addColorStop(1.0,'green')

Применим градиент как стиль заливки

Свойство fillStyle контекста canvas может принимать в качестве значения не только цвет, но и градиент, добавим в скрипт строку:

ctx.fillStyle = gr

Финальный шаг, рисуем залитый прямоугольник

Добавим в наш скрипт последнюю строку:

ctx.fillRect(0,0,150,150)

Радиальные градиенты


При работе с радиальными градиентами отличие от линейных заключается только в создании.

createRadialGradient(float x1, float y1, float r1, float x2, float y2, float r2)

— создаст радиальный градиент с плавным переходом цвета из окружности с центром в точке (x1;y1) и радиусом r1 в окружность с центром точке (x2;y2) и радиусом r2. Для примера нарисуем шарик и сделаем псевдо-освещение:

ctx.shadowOffsetX = 10
ctx.shadowOffsetY = 15
ctx.shadowBlur = 10
ctx.shadowColor = '#0F0'

var gr = ctx.createRadialGradient(60,60,15,75,75,75)

gr.addColorStop(0.0,'#0F0')
gr.addColorStop(1.0,'#0DA805')

ctx.fillStyle = gr

ctx.beginPath()
ctx.arc(75,75,75,0,Math.PI*2,false)
ctx.fill()

Используем шаблоны

Кроме цветов и градиентов fillStyle и strokeStyle в качестве значения могут принимать и так называемые шаблоны, шаблоны можно сделать из того же самого canvas элемента, изображения или видео. Для примера будем использовать изображение. Шаблон создается методом createPattern(object any, string repeat), repeat может принимать следующие значения:«repeat»,«repeat-x»,«repeat-y»,«no-repeat». Значением по умолчанию является «repeat». Для примера запустим следующий скрипт:

var img = new Image()
img.src = 'brick.jpg'

var ptr = ctx.createPattern(img,'repeat')
ctx.fillStyle = ptr;

ctx.fillRect(50,50,100,100)

В HTML5 определён элемент <canvas> как «растровый холст, который может быть использован для отображения диаграмм, игровой графики или изображений на лету». Холст — это прямоугольная область на вашей странице, где с помощью JavaScript можно рисовать что вы пожелаете.

Поддержка <canvas>

iPhone
7.0+ 3.0+ 3.0+ 3.0+ 10.0+ 1.0+ 1.0+

* Internet Explorer поддерживает только с библиотекой explorercanvas. Internet Explorer 9 поддерживает <canvas>.

Как же этот холст выглядит? В действительности, никак. У элемента <canvas> нет собственного контента и рамки.

Невидимый холст

Код выглядит так.

<canvas width="300" height="225"></canvas>

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

Холст с рамкой

Холст с рамкой

У вас может быть несколько элементов <canvas> на одной странице. Каждый холст будет отображаться в DOM и хранить своё собственное состояние. Если вы добавите каждому холсту атрибут id, то можете получить к ним доступ, как и к любому другому элементу.

Расширим наш код, включив атрибут id.

<canvas id="a" width="300" height="225"></canvas>

Теперь легко можно обнаружить элемент <canvas> в DOM.

var a_canvas = document.getElementById("a");

Простые фигуры

iPhone
7.0+ 3.0+ 3.0+ 3.0+ 10.0+ 1.0+ 1.0+

* Internet Explorer поддерживает только с библиотекой explorercanvas. Internet Explorer 9 поддерживает фигуры в <canvas>.

Каждый холст изначально пустой. Это скучно! Давайте что-нибудь нарисуем.

Событие onclick вызывает эту функцию:

function draw_b() {
  var b_canvas = document.getElementById("b");
  var b_context = b_canvas.getContext("2d");
  b_context.fillRect(50, 25, 150, 100);
}

Первая строка функции не делает ничего особенного, она просто находит элемент <canvas> в DOM.

function draw_b() {
  var b_canvas = document.getElementById("b");
  var b_context = b_canvas.getContext("2d");
  b_context.fillRect(50, 25, 150, 100);
}

Каждый холст имеет контекст рисования, в котором и происходят все эти смешные штучки. Как только вы нашли элемент <canvas> в DOM (с помощью document.getElementById() или любым другим способом), вызываете метод getContext(). Необходимо указать строку «2D» в методе getContext().

Спроси профессора Разметкина

В. Есть холст 3D?

О. Пока нет. Отдельные производители экспериментируют с собственным трёхмерным API, но ни один из них не стандартизирован. В спецификации HTML5 отмечено: «в будущих версиях данной спецификации, вероятно, будет определён 3D-контекст».

Итак, у вас есть элемент <canvas> и есть контекст рисования, где определены все методы и свойства рисования. Имеется целая группа свойств и методов посвящённых рисованию прямоугольников.

  • Свойство fillStyle может быть цветом, рисунком или градиентом (подробнее о градиентах чуть ниже). По умолчанию fillStyle заливает сплошным чёрным цветом, но вы можете установить что угодно. Каждый контекст рисунка помнит свои собственные свойства при открытии страницы, пока вы её не обновите.
  • fillRect(x, y, width, height) рисует прямоугольник, заполненный текущим стилем заливки.
  • Свойство strokeStyle как и fillStyle может быть цветом, рисунком или градиентом.
  • strokeRect(x, y, width, height) рисует прямоугольник с текущим стилем линии. strokeRect не заливается внутри, он просто рисует границы.
  • clearRect(x, y, width, height) очищает от пикселей в указанном прямоугольнике.

Спроси профессора Разметкина

В. Можно ли «перезагрузить» холст?

О. Да. Установка ширины или высоты для элемента <canvas> сотрёт его содержимое и сбросит все свойства контекста рисования в значения по умолчанию. Вам даже не нужно менять ширину, вы можете просто установить её в текущее значение, например, так:

var b_canvas = document.getElementById("b");
b_canvas.width = b_canvas.width;

Вернёмся к предыдущему примеру.

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

var b_canvas = document.getElementById("b");
var b_context = b_canvas.getContext("2d");
b_context.fillRect(50, 25, 150, 100);

Вызов метода fillRect() рисует прямоугольник и заполняет его текущим стилем заливки, исходно это чёрный цвет, пока вы его не измените. Прямоугольник задаётся левым верхним углом (50, 25), шириной (150) и высотой (100). Чтобы лучше представить как это работает, давайте посмотрим на систему координат.

Координаты холста

Холст — это двумерная сетка. Координата 0,0 находится в левом верхнем углу холста. Вдоль оси X значения растут к правому краю холста. По оси Y значения растут к нижнему краю холста.

Координаты холста

Координаты холста

Координатная сетка была нарисована с помощью <canvas> и включает в себя:

  • набор серых вертикальных линий;
  • набор серых горизонтальных линий;
  • две чёрные горизонтальные линии;
  • две чёрные вертикальные линии;
  • две маленькие чёрные диагональные линии, которые образуют стрелки;
  • две чёрные вертикальные линии;
  • две маленькие чёрные диагональные линии, которые образуют вторую стрелу;
  • букву «х»;
  • букву «у»;
  • текст «(0, 0)» вблизи левого верхнего угла;
  • текст «(500, 375)» в правом нижнем углу;
  • точку в левом верхнем углу и другую в правом нижнем углу.

Для начала нам необходимо определить сам элемент <canvas>, задать ему ширину и высоту, а также id, чтобы мы могли найти его позже.

<canvas id="c" width="500" height="375"></canvas>

Также нам нужен скрипт для поиска элемента <canvas> в DOM и получить его контекст рисования.

var c_canvas = document.getElementById("c");
var context = c_canvas.getContext("2d");

Теперь мы можем рисовать линии.

Контуры

iPhone
7.0+ 3.0+ 3.0+ 3.0+ 10.0+ 1.0+ 1.0+

* Internet Explorer поддерживает только с библиотекой explorercanvas. Internet Explorer 9 поддерживает <canvas>.

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

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

Чтобы рисовать прямые линии карандашом, можно использовать следующие два метода:

  1. moveTo(х, у) перемещает карандаш к указанной начальной точке.
  2. lineTo(х, у) рисует линии до указанной конечной точки.

Чем чаще вы вызываете moveTo() и lineTo(), тем длиннее получается контур. Это «карандашные» методы — вы можете обращаться к ним так часто, насколько хотите, но вы ничего не увидите на холсте, пока не обратитесь к одному из «чернильных» методов.

Давайте нарисуем серую сетку.

Рисование вертикальных линий

for (var x = 0.5; x < 500; x += 10) {
  context.moveTo(x, 0);
  context.lineTo(x, 375);
}

Рисование горизонтальных линий

for (var y = 0.5; y < 375; y += 10) {
  context.moveTo(0, y);
  context.lineTo(500, y);
}

Все эти методы были «карандашные». На самом деле, на холсте ещё ничего не нарисовано, нам нужны «чернильные» методы, чтобы сделать рисунок видимым.

context.strokeStyle = "#eee";
context.stroke();

stroke() является одним из «чернильных» методов. Он принимает сложный контур, заданный всеми вызовами moveTo() и lineTo() и рисует его на холсте. strokeStyle управляет цветом линии. Вот результат.

Сетка

Спроси профессора Разметкина

В. Почему мы начинаем x и y c 0.5, а не с 0?

О. Представьте каждый пиксель как большой квадрат. Все целочисленные координаты (0, 1, 2, …) являются углами этих квадратов. Если вы рисуете однопиксельную линию между целыми координатами, она будет перекрывать противоположные стороны пиксельного квадрата, в результате будет нарисована ширина два пикселя. Чтобы нарисовать  линию шириной только в один пиксель, необходимо сместить координаты на 0.5 перпендикулярно к направлению линии.

К примеру, если вы попытаетесь нарисовать линию от (1, 0) до (1, 3), браузер будет рисовать линию с перекрытием в полпикселя по обе стороны от x=1. На экране невозможно отобразить половину пикселя, поэтому линия будет расширена для покрытия двух пикселей.

Линия от (1,0) до (1,3) толщиной два пиксела

Если вы попробуете нарисовать линию от (1.5, 0) до (1.5, 3), браузер нарисует линию с перекрытием полпикселя на каждой стороне от x=1.5, что в результате даёт истинную однопиксельную линию.

Линия от (1.5,0) до (1.5,3) толщиной один пиксел

Спасибо Джейсону Джонсону за эти графики.

Теперь нарисуем горизонтальную стрелку. Все линии и кривые на контуре нарисованы тем же цветом (или градиентом — да, мы скоро до него доберемся). Мы хотим нарисовать стрелку другим цветом — чёрным, а не серым, так что мы должны начать новый контур.

Новый контур

context.beginPath();
context.moveTo(0, 40);
context.lineTo(240, 40);
context.moveTo(260, 40);
context.lineTo(500, 40);
context.moveTo(495, 35);
context.lineTo(500, 40);
context.lineTo(495, 45);

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

Не новый контур

context.moveTo(60, 0);
context.lineTo(60, 153);
context.moveTo(60, 173);
context.lineTo(60, 375);
context.moveTo(65, 370);
context.lineTo(60, 375);
context.lineTo(55, 370);

Я сказал, что эти стрелки будут чёрными, но strokeStyle установлен как серый (fillStyle и strokeStyle не сбрасываются, когда вы начинаете новый контур). Это нормально, потому что мы просто запустили серию «карандашных» методов. Но прежде чем нарисовать реально в «чернилах», мы должны установить strokeStyle чёрным. В противном случае эти две стрелки будут серыми и мы вряд ли их заметим. Следующие строки изменяют цвет на чёрный и рисуют линии на холсте.

context.strokeStyle = "#000";
context.stroke();

Вот результат.

Сетка со стрелками

Текст

iPhone
7.0+ 3.0+ 3.0+ 3.0+ 10.0+ 1.0+ 1.0+

* Internet Explorer поддерживает только с библиотекой explorercanvas. Internet Explorer 9 поддерживает текст в <canvas>.

* Mozilla Firefox 3.0 требует костыль для совместимости.

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

Следующие атрибуты шрифта доступны в контексте рисования.

  • font может содержать всё, что вы бы добавили в CSS-свойство font. Включает стиль шрифта, насыщенность, размер, межстрочное расстояние и семейство гарнитур.
  • textAlign управляет выравниванием текста. Похоже на CSS-свойство text-align, но не идентично ему. Возможные значения: start, end, left, right и center.
  • textBaseline говорит, где рисуется текст относительно начальной точки. Возможные значения: top, hanging, middle, alphabetic, ideographic и bottom.

Атрибут textBaseline хитрый, потому что сам текст такой (к тексту на английском это не относится, но вы ведь можете нарисовать любой символ Юникода и сам Юникод хитрый). Спецификация HTML5 объясняет различия между базовыми линиями.

Верх площадки em (top) это примерно верх глифов в шрифте; выносная базовая линия (hanging) там, где привязаны некоторые глифы вроде आ; середина (middle) это половина между верхом и низом площадки em; алфавитная базовая линия (alphabetic) проходит там, где привязаны символы вроде Á, ÿ, f и Ω; идеографическая базовая линия (ideographic) располагается там, где привязаны символы вроде 私 и 達; низ площадки em это примерно низ глифов в шрифте. Верх и низ ограничивающего прямоугольника может быть далеко от базовой линии из-за того, что глифы выходят далеко за пределы прямоугольника em.

Базовые линии

Для простых алфавитов вроде английского вы можете без опасений придерживаться значений top, middle или bottom у свойства textBaseline.

Давайте нарисуем какой-нибудь текст! Текст внутри холста наследует размер шрифта и стиль  самого элемента <canvas>, но вы можете переопределить эти значения, установив свойства шрифта в контексте рисования.

Изменение стиля шрифта

context.font = "bold 12px sans-serif";
context.fillText("x", 248, 43);
context.fillText("y", 58, 165);

Метод fillText() рисует собственно текст.

Рисование текста

context.font = "bold 12px sans-serif";
context.fillText("x", 248, 43);
context.fillText("y", 58, 165);

Спроси профессора Разметкина

В. Могу я использовать относительные размеры шрифтов для рисования текста на холсте?

О. Да. Как и любой другой HTML-элемент на странице, <canvas> сам вычислит размер шрифта на основе правил CSS. Если вы установите свойство context.font на относительный размер шрифта, такой как 1.5em или 150%, ваш браузер умножит его на вычисленный размер шрифта самого элемента <canvas>.

Для текста в левом верхнем углу, скажем, хочу, чтобы верх текста был при y=5. Но я ленивый, не хочу измерять высоту текста и вычислять базовую линию. Вместо этого я установлю textBaseline как top и укажу координаты левого верхнего угла окружающего текст прямоугольника.

context.textBaseline =  "top";
context.fillText("( 0 , 0 )", 8, 5);

Теперь текст в правом нижнем углу. Скажем, я хочу в правом нижнем углу текст, который будет в точке с координатами (492, 370) — это всего несколько пикселей от правого нижнего угла холста — но я не хочу измерять ширину или высоту текста. Я могу установить textAlign как right и textBaseline как bottom, а затем вызвать fillText() с координатами правого нижнего угла прямоугольника ограничивающего текст.

context.textAlign = "right";
context.textBaseline = "bottom";
context.fillText("( 500 , 375 )", 492, 370);

И вот результат:

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

Рисуем две «точки»

context.fillRect(0, 0, 3, 3);
context.fillRect(497, 372, 3, 3);

И это весь написанный текст! Вот финальный результат.

Градиенты

iPhone
Линейный 7.0+ 3.0+ 3.0+ 3.0+ 10.0+ 1.0+ 1.0+
Радиальный 9.0+ 3.0+ 3.0+ 3.0+ 10.0+ 1.0+ 1.0+

* Internet Explorer 7 и 8 поддерживает только с библиотекой explorercanvas. Internet Explorer 9 поддерживает градиенты <canvas>.

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

Градиент

Разметка выглядит так же, как любой другой холст.

<canvas id="d" width="300" height="225"></canvas>

Вначале мы должны найти элемент <canvas> и его контекст рисования.

var d_canvas = document.getElementById("d");
var context = d_canvas.getContext("2d");

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

  1. createLinearGradient(x0, y0, x1, y1) рисует вдоль линии от (x0, y0) до (x1, y1);
  2. createRadialGradient(x0, y0, r0, x1, y1, r1) рисует по конусу между двумя окружностями. Первые три параметра определяют начальную окружность с центром (x0, y0) и радиусом r0. Последние три параметра представляют последнюю окружность с центром (x1, y1) и радиусом r1.

Давайте сделаем линейный градиент. Градиенты могут быть любого размера, но я сделаю этот градиент шириной 300 пикселей, как и холст.

Создание градиентного объекта

var my_gradient = context.createLinearGradient(0, 0, 300, 0);

Поскольку значения у второго и четвёртого параметра равны 0, этот градиент будет заполнен слева направо.

После того как мы получили градиентный объект, мы можем определить цвета градиента. Градиент имеет два или более цвета остановки, которые могут быть в любом месте вдоль градиента. Чтобы добавить цвет остановки, необходимо указать его позицию вдоль градиента, она может быть от 0 до 1.

Давайте определим градиент от чёрного цвета к белому.

my_gradient.addColorStop(0, "black");
my_gradient.addColorStop(1, "white");

Определение градиента не рисует что-либо на холсте, это просто объект, спрятанный где-то в памяти. Чтобы нарисовать градиент, установите fillStyle в градиент и нарисуйте фигуру вроде прямоугольника или линии.

Стиль заполнения градиентом

context.fillStyle = my_gradient;
context.fillRect(0, 0, 300, 225);

И вот результат.

Градиент

Предположим, вы хотите получить градиент сверху вниз. Когда вы создаёте градиентный объект, оставьте значения x (первый и третий параметры) постоянными и сделайте значения y (второй и четвертый параметры) в диапазоне от 0 до высоты холста.

Значения x равны 0, значения y меняются

var my_gradient = context.createLinearGradient(0, 0, 0, 225);
my_gradient.addColorStop(0, "black");
my_gradient.addColorStop(1, "white");
context.fillStyle = my_gradient;
context.fillRect(0, 0, 300, 225);

И вот результат:

Градиент

Вы также можете сделать градиент по диагонали.

Оба значения x и y меняются

var my_gradient = context.createLinearGradient(0, 0, 300, 225);
my_gradient.addColorStop(0, "black");
my_gradient.addColorStop(1, "white");
context.fillStyle = my_gradient;
context.fillRect(0, 0, 300, 225);

Вот результат:

Градиент

Изображения

Поддержка <canvas>

iPhone
7.0+ 3.0+ 3.0+ 3.0+ 10.0+ 1.0+ 1.0+

* Internet Explorer поддерживает только с библиотекой explorercanvas. Internet Explorer 9 поддерживает изображения в <canvas>.

Контекст рисования холста определяет метод drawImage() для вывода изображений. Этот метод может иметь три, пять или девять аргументов.

  • drawImage(image, dx, dy) принимает изображение и выводит его на холсте. Заданные координаты (dx, dy) соответствуют левому верхнему углу изображения, координаты (0, 0) выводят изображения в левом верхнем углу холста.
  • drawImage(image, dx, dy, dw, dh) принимает изображение, масштабирует его до ширины dw и высоты dh и выводит в точке с координатами (dx, dy).
  • drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh) принимает изображение, обрезает его до прямоугольника (sx, sy, sw, sh), масштабирует до размеров (dw, dh) и выводит в точке с координатами (dx, dy).

Спецификация HTML5 поясняет параметры drawImage():

Исходный прямоугольник — это прямоугольник (в пределах исходного изображения), у которого углы это четыре точки (sx, sy), (sx+sw, sy), (sx+sw, sy+sh), (sx, sy+sh).

Прямоугольник назначения это прямоугольник (в холсте), у которого углы это четыре точки (dx, dy), (dx+dw, dy), (dx+dw, dy+dh), (dx, dy+dh).

Чтобы нарисовать изображение на холсте, у вас должно быть изображение. Это может быть существующий элемент <img> или вы можете создать объект Image() через JavaScript. В любом случае вы должны убедиться, что изображение полностью загружено, прежде чем его можно нарисовать на холсте.

Если вы используете существующий элемент <img>, то можете смело нарисовать его на холсте через событие window.onload.

Использование <img>

<img id="cat" src="images/cat.png" alt="Спящий кот" width="177" height="113">
<canvas id="e" width="177" height="113"></canvas>
<script>
  window.onload = function() {
    var canvas = document.getElementById("e");
    var context = canvas.getContext("2d");
    var cat = document.getElementById("cat");
    context.drawImage(cat, 0, 0);
  };
</script>

Если вы создаёте объект полностью на JavaScript, то можете спокойно нарисовать изображение на холсте во время события Image.onload.

Использование объекта Image()

<canvas id="e" width="177" height="113"></canvas>
<script>
  var canvas = document.getElementById("e");
  var context = canvas.getContext("2d");
  var cat = new Image();
  cat.src = "images/cat.png";
  cat.onload = function() {
    context.drawImage(cat, 0, 0);
  };
</script>

Необязательные третий и четвертый параметры в методе drawImage() управляют масштабом изображения. То же самое изображение масштабировано до половины его ширины и высоты и повторяется с разными координатами в пределах одного холста.

«многокошечный» эффек

Вот скрипт который производит «многокошачий» эффект.

cat.onload = function() {
  for (var x = 0, y = 0;
    x < 500 && y < 375;
    x += 50, y += 37) {
    context.drawImage(cat, x, y, 88, 56);
  }
};

Все эти усилия вызывает законный вопрос: почему вы хотите рисовать изображение в первую очередь на холсте? Что дают дополнительные сложности при выводе изображения на холсте по сравнению с элементом <img> или некоторыми правилами CSS? Даже «многокошачий» эффект может быть сделан с десятью перекрывающимися элементами <img>.

Простой ответ в том, что вы также можете нарисовать текст на холсте. График координат включает текст, линии и формы. Более сложные диаграммы легко могут использовать drawImage() для включения иконок, спрайтов или других графических элементов.

Что насчёт IE?

Microsoft Internet Explorer до версии 9.0 не поддерживает Canvas API (IE9 полностью поддерживает Canvas API). Тем не менее, старые версии Internet Explorer поддерживает фирменную технологию Майкрософт, называемую VML, которая может делать многие из тех же вещей, что и элемент <canvas>. Так и родился excanvas.js.

Explorercanvas (excanvas.js) является JavaScript-библиотекой с открытым исходным кодом, которая реализует API Canvas в Internet Explorer. Чтобы её использовать, включите следующий <script> в верхнюю часть страницы.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Dive Into HTML5</title>
    <!--[if IE]>
      <script src="excanvas.js"></script>
    <![endif]-->
  </head>
  <body>
    ...
  </body>
</html>

Фрагмент <!—[if lt IE 9]> и <![endif]—> это условные комментарии. Internet Explorer интерпретирует их следующим образом: «если текущий браузер это Internet Explorer до версии 9 (но не включая её), тогда выполнить этот блок». Любой другой браузер будет рассматривать весь блок как комментарий HTML. Конечным результатом является то, что Internet Explorer скачает скрипт excanvas.js и выполнит его, а другие браузеры будут игнорировать скрипт вообще (не будут его скачивать, выполнять или ещё что-нибудь делать). Это делает ваши страницы загружаемыми быстрее в тех браузерах, которые поддерживают Canvas API изначально.

Как только вы включите excanvas.js в <head> вашей страницы, вам не нужно ничего делать для настройки Internet Explorer. Просто включите элементы <canvas> в разметку или создайте их динамически через JavaScript. Следуйте инструкциям в этой главе, чтобы отобразить контекст  элемента <canvas>, и вы можете рисовать фигуры, текст и картинки.

Ну…, не совсем. Есть несколько ограничений.

  1. Градиенты могут быть только линейными, радиальные градиенты не поддерживаются.
  2. Картинки должны повторяться в обоих направлениях.
  3. Области кадрирования не поддерживаются.
  4. Непропорциональное масштабирование работает некорректно с контурами.
  5. Это медленно. Это не должно вызвать шок у кого-либо, так как анализатор JavaScript в Internet Explorer с самого начала медленнее, чем в других браузерах. Как только вы начинаете рисовать сложные составные фигуры с помощью JavaScript-библиотеки, которая переводит команды в полностью другие технологии, всё начинает увязать в трясине. Вы не заметите снижение производительности на простых примерах вроде рисунка с несколькими линиями и преобразованием изображения, но увидите его сразу, как только начнёте делать анимацию на холсте и другие сумасшедшие штуки.

Существует ещё одно предостережение об использовании excanvas.js и это проблема с которой я столкнулся при создании примеров в этой главе. ExplorerCanvas инициализирует собственный интерфейс лжехолста автоматически, когда вы включаете скрипт excanvas.js в вашу HTML-страницу. Но это не означает, что Internet Explorer готов к использованию сразу же. В определённых ситуациях вы можете получить состояние, когда интерфейс лжехолста готов к использованию, но не совсем. Основным симптомом этого состояния является то, что Internet Explorer будет жаловаться всякий раз, что «объект не поддерживает это свойство или метод», когда вы попытаетесь сделать что-нибудь с элементом <canvas>, подобно получению контекста рисования.

Самое простое решение данной проблемы это отложить все манипуляции с холстом, пока не сработает событие onload. Это может занять какое-то время — если ваша страница содержит много изображений или видео, они приведут к задержке события onload, но это даст ExplorerCanvas время для работы над своей магией.

Заключение, живой пример

Уголки это многовековая настольная игра с множеством разных вариантов. В этом примере я создал версию для одного игрока с девятью фишками и полем 9х9. В начале игры фишки заполняют поле 3х3 в левом нижнем углу доски. Цель игры в том, чтобы переместить все фишки в поле 3х3 в правый верхний угол доски за наименьшее число ходов.

В Уголках существует два типа правильных перемещений.

  • Взять фишку и переместить её на любую соседнюю пустую клетку — это одна из клеток, в которой нет фишек. Соседняя клетка это непосредственно север, юг, восток, запад, северо-запад, северо-восток, юго-запад или юго-восток от текущей позиции фишки. Доска не может поворачиваться. Если фишка находится в самом левом столбце, она не может двигаться на запад, северо-запад или юго-запад. Если фишка находится в самой нижней линии, она не может двигаться на юг, юго-восток или юго-запад.
  • Взять фишку и перепрыгнуть через соседнюю фишку, также возможно повторить. Т. е. вы перепрыгиваете через соседнюю фишку, затем перепрыгиваете через другую ближайшую фишку в новую позицию, что считается одним ходом. Так как целью является сведение к минимуму общего числа ходов, правильная стратегия в Уголках включает в себя продумывание, а затем использование длинных цепочек чередующихся фишек так, чтобы другие фишки могли долго перепрыгивать через них.

Вот сама игра.

Игра Уголки

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

Во время загрузки страницы мы инициализируем игру, установив размеры самого <canvas> и сохраняя указатель на его контекст рисования.

gCanvasElement.width = kPixelWidth;
gCanvasElement.height = kPixelHeight;
gDrawingContext = gCanvasElement.getContext("2d");

Затем мы делаем то, что вы ещё не видели: добавим отслеживание события щелчка для элемента <canvas>.

gCanvasElement.addEventListener("click", halmaOnClick, false);

Функция halmaOnClick() вызывается, когда пользователь щёлкает где-нибудь внутри холста. Его аргумент это объект MouseEvent, который содержит информацию о том, где пользователь щёлкал.

function halmaOnClick(e) {
  var cell = getCursorPosition(e);
  // Остальное это просто логика игры
  for (var i = 0; i < gNumPieces; i++) {
    if ((gPieces[i].row == cell.row) && 
        (gPieces[i].column == cell.column)) {
        clickOnPiece(i);
        return;
    }
  }
  clickOnEmptyCell(cell);
}

Следующий шаг это получить объект MouseEvent и рассчитать, по какой клетке на доске игры только что щёлкнули. Доска Уголков занимает весь холст, поэтому каждый щелчок происходит в пределах доски. Нам просто нужно выяснить, где. Это сложно, потому что события мыши осуществляется по-разному почти во всех браузерах.

function getCursorPosition(e) {
  var x;
  var y;
  if (e.pageX != undefined && e.pageY != undefined) {
    x = e.pageX;
    y = e.pageY;
  }
  else {
    x = e.clientX + document.body.scrollLeft +
    document.documentElement.scrollLeft;
    y = e.clientY + document.body.scrollTop +
    document.documentElement.scrollTop;
  }

На данный момент у нас есть координаты x и y по отношению к документу (т. е., всей HTML-страницы). Это не совсем полезно. Мы хотим координаты относительно холста.

x -= gCanvasElement.offsetLeft;
y -= gCanvasElement.offsetTop;

Теперь у нас есть координаты x и y, которые относятся к холсту. То есть, если в этой точке х это 0 и у это 0, мы знаем, что пользователь просто щёлкнул на левый верхний пиксель холста.

Отсюда мы можем рассчитать, по какой клетке пользователь щёлкнул, а затем действовать соответственно.

  var cell = new Cell(Math.floor(y/kPieceHeight),
                      Math.floor(x/kPieceWidth));
  return cell;
}

Вот так так! События мыши трудны. Но вы можете использовать ту же логику во всех ваших собственных приложениях с холстом. Помните: щелчок мыши → координаты относительно документа → координаты относительно холста → код конкретного приложения.

Хорошо, давайте посмотрим на основные типовые задачи рисования. Потому что графика это так просто, что я решил очищать и перерисовывать доску в полном объеме каждый раз, когда что-нибудь изменяется в игре. Это не является строго обязательным. Контекст рисования холста будет сохранять всё, что вы ранее нарисовали на нём, даже если пользователь прокручивает холст за пределы видимости или выбирает другую вкладку, а затем возвращается позже назад. Если вы разрабатываете приложение с более сложной графикой (например, аркадные игры), вы можете оптимизировать производительность путем отслеживания тех регионов холста, которые «загрязнились» и перерисовывать только их. Но это выходит за рамки данной книги.

gDrawingContext.beginPath();
  /* вертикальные линии */
  for (var x = 0; x <= kPixelWidth; x += kPieceWidth) {
    gDrawingContext.moveTo(0.5 + x, 0);
    gDrawingContext.lineTo(0.5 + x, kPixelHeight);
  }

  /* горизонтальные линии */
  for (var y = 0; y <= kPixelHeight; y += kPieceHeight) {
    gDrawingContext.moveTo(0, 0.5 + y);
    gDrawingContext.lineTo(kPixelWidth, 0.5 +  y);
  }
  /* рисуем их! */
  gDrawingContext.strokeStyle = "#ccc";
  gDrawingContext.stroke();

Самое интересное начинается тогда, когда мы идём рисовать каждую фишку отдельно. Фишка представляет собой окружность, которую мы прежде не рисовали. Кроме того, если пользователь выберет фишку в ожидании перемещения, мы хотим нарисовать фишку как заполненную окружность. Здесь аргумент p соответствует фишке, которая имеет свойства строки и столбца, обозначающих текущее местоположение фишки на доске. Мы используем некоторые игровые константы (столбец, строка) и переводим их в относительные координаты холста (х, у), затем рисуем окружность, а затем (если фишка выбрана) заполняем окружность цветом.

function drawPiece(p, selected) {
  var column = p.column;
  var row = p.row;
  var x = (column * kPieceWidth) + (kPieceWidth/2);
  var y = (row * kPieceHeight) + (kPieceHeight/2);
  var radius = (kPieceWidth/2) - (kPieceWidth/10);

Вот и вся специфичная игровая логика. Теперь у нас есть координаты (х, у) относительно холста для получения центра окружности, которую мы хотим нарисовать. В API Canvas нет метода circle(), но есть метод arc(). И действительно, что есть окружность, как не замкнутая дуга? Помните основы геометрии? Метод arc() задаёт центральную точку (х, у), радиус, начальный и конечный угол (в радианах) и флаг направления (false по часовой стрелке, true против часовой стрелки). Вы можете использовать модуль Math встроенный в JavaScript для расчёта радиан.

gDrawingContext.beginPath();
gDrawingContext.arc(x, y, radius, 0, Math.PI * 2, false);
gDrawingContext.closePath();

Но подождите! Ничего ещё не нарисовано. Метод arc() подобен moveTo() и lineTo() и относится к «карандашным» методам. Чтобы действительно нарисовать окружность, мы должны установить strokeStyle и вызвать метод stroke() для обводки «чернилами».

gDrawingContext.strokeStyle = "#000";
gDrawingContext.stroke();

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

if (selected) {
  gDrawingContext.strokeStyle = "#000";
  gDrawingContext.fill();
}

Вот теперь всё значительно лучше. Остальная часть программы это игровая логика — различия между правильными и неверными движениями, отслеживание количества ходов, определение, закончилась ли игра. С девятью окружностями, несколькими линиями и одним обработчиком onclick мы создали всю игру на <canvas>. Ура!

Дальнейшее чтение

  • Руководство по Canvas в Mozilla Developer Center
  • HTML5 canvas — the basics
  • The canvas element в черновике стандарта HTML5
  • Internet Explorer 9 Guide for Developers: HTML5 canvas element

Последнее изменение: 13.09.2022

Элемент HTML5 canvas можно использовать для рисования графики на веб-странице с помощью JavaScript. Холст (canvas) был изначально представлен Apple для виджетов панели управления Mac OS и для обеспечения графики в веб-браузере Safari. Позже его стали использовать Firefox, Google Chrome и Opera. Теперь canvas является частью новой спецификации HTML5 для веб-технологий следующего поколения.

По умолчанию элемент <canvas> имеет ширину 300 пикселей и высоту 150 пикселей без границ и содержимого. Однако пользовательские ширина и высота могут быть определены с помощью атрибутов height и width, а границы с помощью CSS-свойства border.

Canvas представляет собой двухмерную прямоугольную область. Координаты начинаются от верхнего левого угла холста (0, 0), который называют источник (origin) и заканчиваются нижним правым углом (canvas width, canvas height).

Элемент <canvas> поддерживается во всех основных веб-браузерах, таких как Chrome, Firefox, Safari, Opera, IE 9 и выше.

Рисование контура и фигур на Canvas

В этом разделе мы познакомимся с тем, как рисовать основные контуры и фигуры, используя недавно представленный элемент canvas и JavaScript.

Вот базовый шаблон для рисования контуров и фигур на 2D-холсте HTML5.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Drawing on Canvas</title>
<script>
    window.onload = function() {
        var canvas = document.getElementById("myCanvas");
        var context = canvas.getContext("2d");
        // draw stuff here
    };
</script>
</head>
<body>
    <canvas id="myCanvas" width="300" height="200"></canvas>
</body>
</html>

Анонимная функция, прикрепленная к событию window.onload, будет выполняться при загрузке страницы. После загрузки страницы мы можем получить доступ к элементу canvas с помощью метода document.getElementById(). Позже мы определили 2D-контекст холста, передав 2d в метод getContext() объекта canvas.

Рисование линии

Самый простой элемент, который вы можете нарисовать на canvas — это прямая линия. Наиболее важные методы, используемые для этого: moveTo(), lineTo() и stroke().

Метод moveTo() определяет позицию рисования курсора на холсте, а метод lineTo() используется для определения координат конечной точки, и, наконец, метод stroke() используется для отображения линии. Посмотрим пример:

<script>
    window.onload = function() {
        var canvas = document.getElementById("myCanvas");
        var context = canvas.getContext("2d");
        context.moveTo(50, 150);
        context.lineTo(250, 50);
        context.stroke();
    };
</script>

Рисование дуги

Вы можете создавать дуги, используя метод arc(). Синтаксис этого метода следующий:

context.arc(centerX, centerY, radius, startingAngle, endingAngle, counterclockwise);

Код JavaScript в следующем примере нарисует дугу на холсте.

<script>
    window.onload = function() {
        var canvas = document.getElementById("myCanvas");
        var context = canvas.getContext("2d");
        context.arc(150, 150, 80, 1.2 * Math.PI, 1.8 * Math.PI, false);
        context.stroke();
    };
</script>

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

Вы можете создавать прямоугольные и квадратные формы, используя метод rect(). Этот метод требует четырех параметров: координат x, y, ширину и высоту.

Основной синтаксис метода rect() может быть задан с помощью:

context.rect(x, y, width, height);

Следующий код JavaScript нарисует прямоугольную форму с центром на холсте.

<script>
	window.onload = function() {
        var canvas = document.getElementById("myCanvas");
        var context = canvas.getContext("2d");
        context.rect(50, 50, 200, 100); 
        context.stroke();
    };
</script>

Рисование круга

Не существует специального метода для создания круга. Однако вы можете создать полностью закрытую дугу используя метод arc().

Синтаксис для рисования полного круга с использованием метода arc() можно задать с помощью:

context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);

В следующем примере будет нарисован полный круг с центром на холсте.

<script>
	window.onload = function() {
        var canvas = document.getElementById("myCanvas");
        var context = canvas.getContext("2d");
        context.arc(150, 100, 70, 0, 2 * Math.PI, false);
        context.stroke();
    };
</script>

Применение стилей и цветов для линий

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

В следующем примере будет нарисована оранжевая цветная линия шириной 5 пикселей.

<script>
	window.onload = function() {
        var canvas = document.getElementById("myCanvas");
        var context = canvas.getContext("2d");
        context.lineWidth = 5;
        context.strokeStyle = "orange";
        context.moveTo(50, 150);
        context.lineTo(250, 50);
        context.stroke();
    };
</script>

Вы также можете установить стиль ограничения для линий, используя свойство lineCap. Есть три стиля, доступных для линии — butt, round, и square. Вот пример:

<script>
	window.onload = function() {
        var canvas = document.getElementById("myCanvas");
        var context = canvas.getContext("2d");
        context.lineWidth = 10;
        context.strokeStyle = "orange";
        context.lineCap = "round";
        context.arc(150, 150, 80, 1.2 * Math.PI, 1.8 * Math.PI, false);
        context.stroke();
    };
</script>

Заполнение цветом внутри форм Canvas

Вы можете заполнить цветом форму canvas, используя метод fillStyle().

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

<script>
	window.onload = function() {
        var canvas = document.getElementById("myCanvas");
        var context = canvas.getContext("2d");
        context.rect(50, 50, 200, 100); 
        context.fillStyle = "#FB8B89";
        context.fill();
        context.lineWidth = 5;
        context.strokeStyle = "black";
        context.stroke();
    };
</script>

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

Точно так же вы можете использовать метод fillStyle(), чтобы залить сплошным цветом круг.

<script>
	window.onload = function() {
        var canvas = document.getElementById("myCanvas");
        var context = canvas.getContext("2d");
        context.arc(150, 100, 70, 0, 2 * Math.PI, false);
        context.fillStyle = "#FB8B89";
        context.fill();
        context.lineWidth = 5;
        context.strokeStyle = "black";
        context.stroke();
    };
</script>

Заполнение градиентным цветом форм Canvas

Вы также можете заполнить градиентным цветом форму canvas. Градиент — это просто плавный визуальный переход от одного цвета к другому. Существует два типа градиента — линейный и радиальный.

Основной синтаксис для создания линейного градиента может быть задан с помощью:

var grd = context.createLinearGradient(startX, startY, endX, endY);

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

<script>
	window.onload = function() {
        var canvas = document.getElementById("myCanvas");
        var context = canvas.getContext("2d");
        context.rect(50, 50, 200, 100); 
        var grd = context.createLinearGradient(0, 0, canvas.width, canvas.height);
        grd.addColorStop(0, '#8ED6FF');   
        grd.addColorStop(1, '#004CB3');
        context.fillStyle = grd;
        context.fill();
        context.stroke();
    };
</script>

Точно так же вы можете заполнить формы радиальным градиентом, используя метод createRadialGradient(). Основной синтаксис для создания радиального градиента может быть задан с помощью:

var grd = context.createRadialGradient(startX, startY, startRadius, endX, endY, endRadius);

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

<script>
	window.onload = function() {
        var canvas = document.getElementById("myCanvas");
        var context = canvas.getContext("2d");
        context.arc(150, 100, 70, 0, 2 * Math.PI, false);
        var grd = context.createRadialGradient(150, 100, 10, 160, 110, 100);
        grd.addColorStop(0, '#8ED6FF');   
        grd.addColorStop(1, '#004CB3');
        context.fillStyle = grd;
        context.fill();
        context.stroke();
    };
</script>

Рисование текста на Canvas

Вы также можете нарисовать текст на canvas. Текст может содержать любые символы Юникода. В следующем примере будет нарисовано простое приветственное сообщение «Hello World!».

<script>
	window.onload = function() {
        var canvas = document.getElementById("myCanvas");
        var context = canvas.getContext("2d");
        context.font = "bold 32px Arial";
        context.fillText("Hello World!", 50, 100);
    };
</script>

Дополнительно вы можете установить цвет и выравнивание текста на холсте, например так:

<script>
	window.onload = function() {
        var canvas = document.getElementById("myCanvas");
        var context = canvas.getContext("2d");
        context.font = "bold 32px Arial";
        context.textAlign = "center";
        context.textBaseline = "middle";
        context.fillStyle = "orange";
        context.fillText("Hello World!", 150, 100);
    };
</script>

Вы также можете применить обводку к тексту, используя метод strokeText(). Этот метод будет окрашивать периметр текста, а не заполнять его. Однако если вы хотите установить как заливку, так и обводку текста, вы можете использовать оба метода fillText() и strokeText().

<script>
	window.onload = function() {
        var canvas = document.getElementById("myCanvas");
        var context = canvas.getContext("2d");
        context.font = "bold 32px Arial";
        context.textAlign = "center";
        context.textBaseline = "middle";
        context.strokeStyle = "orange";
        context.strokeText("Hello World!", 150, 100);
    };
</script>

При оформлении текста на холсте рекомендуется использовать метод fillText() перед методом strokeText(), чтобы правильно отобразить обводку.

Как в канве сделать тень от объекта

Completing the CAPTCHA proves you are a human and gives you temporary access to the web property.

What can I do to prevent this in the future?

If you are on a personal connection, like at home, you can run an anti-virus scan on your device to make sure it is not infected with malware.

If you are at an office or shared network, you can ask the network administrator to run a scan across the network looking for misconfigured or infected devices.

Another way to prevent getting this page in the future is to use Privacy Pass. You may need to download version 2.0 now from the Chrome Web Store.

Cloudflare Ray ID: 71adcbc069d29a35 • Your IP : 82.102.23.104 • Performance & security by Cloudflare

Еще одно Canvas руководство [2]: Стилизация, градиенты, тени

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

Сделаем наш холст разноцветным


Как вы уже заметили в canvas есть два типа операции отрисовки fill и rect и у каждого есть свои настройки стилей. Для их изменения нужно менять свойства контекста fillStyle и strokeStyle, эти свойства в качестве значения могут принимать не только цвета, но и другие значения которые мы рассмотрим позже. А сейчас мы рассмотрим как поменять цвет. Для этого нужно просто присвоить свойствам fillStyle и strokeStyle новый значения, в случае с цветами это будут строки, при этом canvas поддерживает следующие схемы описания цветов: orange, #FFA500, rgb(255,165,0), rgba(255,165,0,1).
Для примера нарисуем разноцветный круг, оставим в нашем скрипте только получение контекста, а затем добавим следующий код:

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

Поработаем с линиями

Мы также можем изменить некоторые параметры у линий для этого существует несколько свойств, давайте рассмотрим по порядку каждое из них.

Изменяем ширину линии

Значение ширины линии хранится в свойстве lineWidth контекста canvas и одна единица соответствует одному пикселю. Значение по умолчанию естественно 1.0

Стиль верхушки линий


Стиль верхушки линии хранится в свойстве lineCap и для него существует три возможных значение: butt, round, sqare, стилем по умолчанию является butt.

Стиль соединения линий


Стиль соединения линий хранится в свойстве lineJoin и может принимать три возможных значение: miter, round, bevel, стилем по умолчанию является miter.

Еще немного о miter

Мы можем ограничить длину огромного хвоста miter с помощью свойства miteLimit которое по умолчанию принимает значение 10.

Отбросим тени


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

Для примера отбросим две тени на друг друга в ограниченной области рисования и посмотрим что произойдет:

Используем градиенты

Линейные градиенты

Создание объекта градиента

— создаст объект линейного градиента проходящего из точки (x1;y1) в точку (x2;y2), добавим в наш код строку:

Добавляем цвета в градиент

— добавит в наш градиент цвет color с отступом offset который принимает значения от 0 до 1.
Добавим в наш скрипт строки:

Применим градиент как стиль заливки

Свойство fillStyle контекста canvas может принимать в качестве значения не только цвет, но и градиент, добавим в скрипт строку:

Финальный шаг, рисуем залитый прямоугольник

Добавим в наш скрипт последнюю строку:

Радиальные градиенты


При работе с радиальными градиентами отличие от линейных заключается только в создании.
— создаст радиальный градиент с плавным переходом цвета из окружности с центром в точке (x1;y1) и радиусом r1 в окружность с центром точке (x2;y2) и радиусом r2. Для примера нарисуем шарик и сделаем псевдо-освещение:

Создание теней

shadowBlur — Устанавливает степень размытия теней. Нулевое значение этого свойства определяет четкую, резкую тень, выглядящую как силуэт исходного изображения. А значение 20 дает тень в виде размытой дымки, и можно установить еще большее значение. Значение shadowBlur около 3 считается достаточном для ненавязчивого визуального эффекта

shadowOffsetX и shadowOffsetY — Определяют положение тени относительно содержимого, которому она принадлежит. Например, если присвоить каждому свойству значение 5, тень будет расположена на 5 px вправо и 5px вниз от исходного содержимого. Отрицательные значения сдвигают тень в противоположном направлении — влево и вверх.

Ниже показан пример использования теней:

Заполнение фигур изображениями

Нарисованные на холсте фигуры можно заполнять не только сплошными или полупрозрачными цветами, но также градиентными цветами или узорами. Такого рода оформление выполняется в два этапа: сначала создается заполнение, которое потом связывается со свойством fillStyle (или иногда со свойством strokeStyle).

Заполнение узором осуществляется путем множественной вставки копий одного исходного изображения вплотную друг к другу. Изображение, используемое в качестве исходной плитки, нужно загрузить в объект изображения. Имея объект изображения, можно создать объект шаблона, используя метод контекста createPattern(). На этом этапе указывается направление копирования плитки — горизонтально (repeat-x), вертикально (repeat-y) или в обоих направлениях (repeat). Последний шаг — присвоить созданный объект шаблона свойству контекста fillStyle или strokeStyle.

Ниже показан пример:

Этот код создает прямоугольник, который заполняет наш холст исходным изображением в виде паттерна:

Градиенты в Canvas

В Сanvas существуют линейные и радиальные градиенты. Первым шагом в создании градиентной заливки будет создание правильного типа объекта градиента. Для решения этой задачи контекст рисования предоставляет два метода: createLinearGradient() и createRadialGradient(). Они содержат список цветов, которые задействуются в разных точках.

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

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

Рассмотрим, например, линейный градиент, переходящий из светло-розового цвета в желтый. Этот переход можно выполнить в полосе шириной в несколько пикселов или же по всей ширине холста. Кроме этого, направление перехода может быть слева направо, сверху вниз или же с любым наклоном между этими двумя линиями. Все эти аспекты определяются линией градиента.

В данном примере линия градиента берет начало в точке (10, 0) и оканчивается в точке (100, 0). Эти точки предоставляют нам следующую важную информацию о данном градиенте:

  • Градиент горизонтальный. Это означает, что переход цветов происходит слева направо. Мы извлекаем эту информацию из того факта, что обе точки имеют одинаковую ординату. Если бы мы хотели выполнить переход сверху вниз, то можно было использовать, например, точки (0, 10) и (0, 100). А для перехода по диагонали сверху вниз слева направо можно было бы использовать, например, точки (10, 10) и (100, 100).
  • Собственно переход охватывает всего лишь 90 пикселов (начиная со значения абсциссы, равного 10, и заканчивая, когда это значение равно 100). В данном примере горизонтальный размер сердцевидной фигуры слегка меньше, чем размеры градиента, вследствие чего в фигуре видно большую часть градиента.
  • Цвета за пределами этого градиента становятся сплошными. Поэтому, если сделать фигуру шире, ее левый край будет окрашен чистым светло-розовым цветом, а правый — чистым желтым.

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

Остановка цветов градиента осуществляется вызовами метода градиента addColorStop(). При каждом вызове метода ему передается значение смещения от 0 до 1, которое определяет местонахождение цвета в переходе. Значение 0 означает, что цвет находится в самом начале градиента, а значение 1 размещает цвет в конце. Изменив эти числа (например, на 0.2 и 0.8), мы можем сжать градиент, показывая большую область сплошного цвета на каждом конце.

Для двухцветного градиента наиболее логичными значениями смещения являются 0 и 1. Но для градиентов с большим количеством цветов можно устанавливать разные смещения, чтобы сжать одни цветовые полосы и растянуть другие.

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

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

В правой верхней фигуре примера радиального градиента цветовой переход распространяется от центральной точки фигуры с координатами (180, 100). Внутренний цвет ограничен кругом радиусом 10 px, а внешний — кругом радиусом 50 px. Опять же, если выйти за эти пределы, мы получим сплошные цвета — светло-розовый в центре и желтый по внешней окружности.

Знакомство с новым элементом
Первый пример
Настройки цвета и размера
Прямоугольники
Линии и дуги
Окружности
Закруглённые углы
Кривые Безье
Функция clip() — ограничиваем область рисования
Тени
Градиенты
Прозрачность
Используем шаблоны
Треугольник Серпинского
Рисование изображений
Рисование текста
Комбинирование наложений

Знакомство с новым элементом

Canvas — это новый элемент HTML5, который предназначен для создания растрового изображения при помощи JavaScript. Само слово canvas переводится как холст или канва. Текст внутри тега будет проигнорирован браузером с поддержкой canvas и показан в браузере без поддержки canvas.


<canvas id="test" width="500" height="500">
    Здесь можно указать текст для тех,
    у кого не поддерживается тег canvas
</canvas>

У тега есть два атрибута — width (ширина) и height (высота). Если размеры не указать, то по умолчанию размер холста будет равен 300х150 пикселей. Canvas создаёт область фиксированного размера, содержимым которого управляют контексты. Атрибуты не имеют отношения к CSS, они обозначают ширину и высоту canvas в пикселях не на экране, а на координатной плоскости холста.

Не рекомендуется использовать CSS для установки высоты и ширины холста, так как в этом случае canvas подвергнется масштабированию. Задавайте размеры в элементе.

Требуется установить обязательный идентификатор для обращению к элементу в JavaScript.

Также можно применить стиль, например, сделаем рамку вокруг холста и не будем устанавливать размеры, чтобы увидеть ширину и высоту по умолчанию.

Canvas


<canvas id="border" style = "border:2px solid black">Canvas</canvas>

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


var canvas = document.getElementById('my_canvas');
if (canvas.getContext){
    var context = canvas.getContext('2d');
}else{
    //  Сделать  что-то для  вывода  скрытого  содержимого 
    //  или  позволить  браузеру  вывести  текст элемента canvas
}

Мы находим элемент canvas по идентификатору, а затем вызываем метод getContext() с единственным параметром — строкой 2d. Если getContext() возвращает ответ, мы получаем 2D-контекст холста для добавления объектов.

Размер холста можно вычислить программно через свойства canvas.width и canvas.height.

Первый пример


  <canvas height='320' width='480' id='first_example'>Пример</canvas>
  <script>
    var canvas = document.getElementById("first_example");
    var context = canvas.getContext('2d');
    context.fillRect(0, 0, canvas.width, canvas.height);
  </script>

Пример

Если открыть созданный пример браузером, то увидим область с чёрным прямоугольником. Это и есть тот самый холст, на котором нарисован прямоугольник, размеры которого равны размерам элемента canvas. Если бы мы не рисовали чёрный прямоугольник, то у нас был бы прозрачный холст. Размеры задаются в пикселях, а отсчёт идёт от верхнего левого угла. На холсте можно рисовать различные фигуры. Можно указать отрицательные значения для координат, ошибки не произойдёт, но смысла в этом нет — фигуры не будут видны на экране.

Настройки цвета и размера

Стили для заливки и обводки имеют глобальный параметр. Если вы задали какое-то свойство, то оно применится для всех элементов, если не был после этого изменен. Например, мы сначала задали зелёный цвет для заливки и синий для обводки. Если после этого мы нарисуем несколько фигур, то они все будут иметь зелёный фон и синюю обводку.

За заливку отвечает свойство fillStyle. По умолчанию для заливки используется чёрный цвет. За цвет и стиль обводки отвечает свойство strokeStyle.

Цвет задается точно так же как и в CSS (четыре способа)


// все четыре строки задают оранжевый цвет заливки
context.fillStyle = "orange";
context.fillStyle = "#FFA500";
context.fillStyle = "rgb(255,165,0)";
context.fillStyle = "rgba(255,165,0,1)"

Есть ещё редко используемый способ через HSL — hsl(219, 58%, 93%).

Установим желаемые настройки — укажем, что мы хотим красный цвет (#FF0000) и толщину в 3 пиксела для обводки и зеленый цвет (#00FF00) для заливки:


context.strokeStyle = '#FF0000'; // Цвет обводки
context.lineWidth = 3; // Ширина линии
context.fillStyle = '#00FF00'; // Цвет заливки

Прямоугольники

Начнем с прямоугольника. В canvas есть два вида прямоугольников — залитые и незалитые (обводка). Предусмотрены три функции для рисования прямоугольников.

  • strokeRect(x, y, ширина, высота) — рисует границы прямоугольника
  • fillRect(x, y, ширина, высота) — рисует закрашенный прямоугольник
  • clearRect(x, y, ширина, высота) — Очищает область на холсте размер с прямоугольника заданного размера в указанной позиции

Функция clearRect() как бы вырезает кусок фигуры, за которым можно увидеть холст.


context.clearRect(10, 10, 200, 200); // Очистка области указанного размера и положения
context.clearRect(0, 0, canvas.width, canvas.height); // Очистка всего холста 

Нарисуем два вида прямоугольников.

Пример


var canvas = document.getElementById("rectangles");
var context = canvas.getContext('2d');

context.strokeStyle = '#FF0000'; // Цвет обводки
context.lineWidth = 3; // Ширина линии
context.fillStyle = '#00FF00'; // Цвет заливки

context.fillRect(10, 10, 390, 100);
context.strokeRect(40, 130, 200, 150);

Попробуйте нарисовать ещё один закрашенный прямоугольник и вырезать из него прямоугольник меньшего размера.

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

Наложение прямоугольников


<canvas id='rects'>Наложение прямоугольников</canvas>

<script>
    var canvas = document.getElementById("rects");
    var context = canvas.getContext('2d');
    canvas.height = 200;
    canvas.width = 300;
    
    context.fillStyle = "rgb(200, 0, 0)";
    context.fillRect(15, 15, 100, 100); 
    context.fillStyle = "rgb(0, 200, 0)";
    context.fillRect(30, 30, 100, 100);
    context.fillStyle = "rgb(0, 0, 200)";
    context.fillRect(45, 45, 100, 100);
</script>

Рисуем шахматную доску


<canvas id='chessboard'>Шахматная доска</canvas>

<script>
    var canvas = document.getElementById("chessboard");
    var context = canvas.getContext('2d');
    // Размеры холста
    canvas.width  = 300;
    canvas.height = 300;
    // Внешняя рамка для доски
    context.strokeRect(15, 15, 266, 266);
    // Внутренняя рамка для доски
    context.strokeRect(18, 18, 260, 260);
    // Закрашиваем внутреннюю область черным цветом
    context.fillRect(20, 20, 256, 256);
    for (i = 0; i < 8; i += 2)
      for (j = 0; j < 8; j += 2) {
        context.clearRect(20 + i * 32, 20 + j * 32, 32, 32);
        context.clearRect(20 + (i + 1) * 32, 20 + (j + 1) * 32, 32, 32);
      }
</script>

Шахматная доска

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

Раскрашиваем шахматную доску

Цветная шахматная доска


<canvas id='color_chessboard'>Цветная шахматная доска</canvas>

<script>
  var canvas = document.getElementById("color_chessboard");
  var context = canvas.getContext('2d');
  canvas.width  = 300;
  canvas.height = 300;
  context.strokeStyle = '#B70A02'; // меняем цвет рамки
  context.strokeRect(15, 15, 266, 266);
  context.strokeRect(18, 18, 260, 260);
  context.fillStyle = '#AF5200'; // меняем цвет клеток
  context.fillRect(20, 20, 256, 256);
  for (i = 0; i < 8; i += 2)
    for (j = 0; j < 8; j += 2) {
      context.clearRect(20 + i * 32, 20 + j * 32, 32, 32);
      context.clearRect(20 + (i + 1) * 32, 20 + (j + 1) * 32, 32, 32);
    }
</script>

Линии и дуги

Мы можем рисовать прямые и изогнутые линии, окружности и другие фигуры. Замкнутые линии можно заливать цветом. В отличии от рисования прямоугольников, рисование линий это не одна команда, а их последовательность. Так, сначала надо объявить начало новой линии с помощью beginPath(), а в конце сказать от том, что рисование линии заканчивается с помощью closePath(). У каждого отрезка линии есть начало и конец.

beginPath используется что бы «начать» серию действий описывающих отрисовку фигуры. Каждый новый вызов этого метода сбрасывает все действия предыдущего и начинает «рисовать» снова.

closePath является не обязательным действием и по сути оно пытается завершить рисование проведя линию от текущей позиции к позиции с которой начали рисовать.

Завершающий шаг — это вызов методов stroke или fill. stroke обводит фигуру линиями, а fill заливает фигуру сплошным цветом.

Также существуют такие методы как,

  • moveTo(x, y) — перемещает «курсор» в позицию x, y и делает её текущей
  • lineTo(x, y) — ведёт линию из текущей позиции в указанную, и делает в последствии указанную текущей
  • arc(x, y, radius, startAngle, endAngle, anticlockwise) — рисование дуги, где x и y центр окружности, далее начальный и конечный угол, последний параметр указывает направление

Давайте нарисуем ломаную, состоящую из двух отрезков:


context.beginPath();
context.moveTo(10, 10); // Начало линии 
context.lineTo(100, 100); // Узел линии  
context.lineTo(150, 100); // Конец линии 
context.closePath();

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


context.beginPath();  
context.moveTo(50, 50);  
context.lineTo(50, 250);  
context.lineTo(250, 250);  
context.closePath();  
context.fill();

Изменяем ширину линии

Значение ширины линии хранится в свойстве lineWidth контекста canvas и одна единица соответствует одному пикселю. Значение по умолчанию естественно 1.0

Стиль верхушки линий

Стиль верхушки линии хранится в свойстве lineCap и для него существуют три возможных значения:

  • butt (по умолчанию)
  • round
  • sqare

,

Стиль соединения линий

Стиль соединения линий хранится в свойстве lineJoin и может принимать три возможных значения:

  • miter (по умолчанию)
  • round
  • bevel

Мы можем ограничить длину огромного хвоста miter с помощью свойства miteLimit, которое по умолчанию принимает значение 10.

Рисуем корону

Корона


<canvas id='crown'>Корона</canvas>

<script>
    var canvas = document.getElementById("crown");
    var context = canvas.getcanvas('2d');
    canvas.height = 200;
    canvas.width = 200;
    context.beginPath();
    context.arc(80, 100, 56, 3/4 * Math.PI, 1/4 * Math.PI, true);
	//Заливаем дугу
    context.fill();
    context.moveTo(40, 140);
    context.lineTo(20, 40);
    context.lineTo(60, 100);
    context.lineTo(80, 20);
    context.lineTo(100, 100);
    context.lineTo(140, 40);
    context.lineTo(120, 140);
	// Обводим контур короны
    context.stroke();
</script>

Окружности

Окружности рисуются с помощью команды arc(ox, oy, radius, startAngle, endAngle, antiClockWise), где ox и oy — координаты центра, radius — радиус окружности, startAngle и endAngle — начальный и конечный углы (в радианах) для отрисовки окружности, а antiClockWise — направление движения при отрисовке (true для против часовой стрелке, false — против). С помощью arc() можно рисовать как круги и окружности, так и дуги и части окружности.

Окружность с радиусом в 100 пикселей:


context.beginPath();  
context.arc(250, 250, 100, 0, Math.PI * 2, false);  
context.closePath();
context.fill(); // Заливка окружности

Нарисуем разноцветный круг:

Код нарисует круг, состоящий из 6 сегментов с произвольными цветами, которые будут меняться при обновлении страницы


<canvas id="color_circle" width="300" height="200"></canvas>
 
<script>
    canvas = document.getElementById("color_circle");
    context = canvas.getContext("2d");
    
    for(var i = 0; i < 6;i++){
        context.fillStyle = 'rgb(' + Math.round(Math.random()*255) + ',' + Math.round(Math.random() * 255) + ',' + Math.round(Math.random()*255) +')'
    context.beginPath();
    context.arc(100, 100, 70, Math.PI/3 * i, Math.PI/3 * (i + 1), false)
    context.lineTo(100, 100);
    context.fill();
}
</script>

Нарисуем дольки апельсина или арбуза, а также другие варианты с использованием собственной процедуры.

Дольки


<canvas id='arc_demo'>Дольки</canvas>

<script>
  var canvas = document.getElementById("arc_demo");
  var context = canvas.getContext('2d');
  canvas.height = 200;
  canvas.width = 500;
  
  function drawArc(xPos, yPos, radius, startAngle, endAngle, anticlockwise, lineColor, fillColor)
  {
    var startAngle = startAngle * (Math.PI/180);
    var endAngle = endAngle * (Math.PI/180);
    var radius = radius;
    context.strokeStyle = lineColor;
    context.fillStyle = fillColor;
    context.lineWidth = 8;
    context.beginPath();
    context.arc(xPos, yPos, radius, startAngle, endAngle, anticlockwise);
    context.fill();
    context.stroke();
  }
  
  drawArc(50, 15, 40, 0, 180, false, "aqua", "yellow");
  drawArc(150, 15, 50, 350, 170, false, "green", "pink");
  drawArc(270, 70, 60, 0, 100, true, "red", "white");
  drawArc(400, 60, 50, 350, 20, true, "blue", "purple");
</script>

Теперь нарисуем круги из этих же фигур.

Дольки


<canvas id='circles_demo'>Дольки</canvas>

<script>
  var canvas = document.getElementById("circles_demo");
  var context = canvas.getContext('2d');
  canvas.height = 200;
  canvas.width = 500;
  
  function drawCircle(xPos, yPos, radius, lineColor, fillColor)
  {
    var startAngle = 0 * (Math.PI/180);
    var endAngle = 360 * (Math.PI/180);
    var radius = radius;
    context.strokeStyle = lineColor;
    context.fillStyle = fillColor;
    context.lineWidth = 8;
    context.beginPath();
    context.arc(xPos, yPos, radius, startAngle, endAngle, false);
    context.fill();
    context.stroke();
  }
  
  drawCircle(50, 45, 40, "aqua", "yellow");
  drawCircle(150, 55, 50, "green", "pink");
  drawCircle(270, 70, 60, "red", "white");
  drawCircle(400, 65, 50, "blue", "purple");
</script>

Частичная заливка окружности

Нарисуем частично залитую окружность.

Частично залитая окружность


<canvas id='part_circle'>Частично залитая окружность</canvas>

<script>
  var canvas = document.getElementById("part_circle");
  var context = canvas.getContext('2d');
  canvas.height = 400;
  canvas.width = 400;
  context.beginPath();
  context.arc(200, 200, 100, 0, Math.PI * 0.85, false)
  context.stroke();

  context.beginPath();
  context.arc(200, 200, 100, 0, Math.PI * 0.85, true);
  context.fill();
</script>

Много кругов

Нарисуем круги в случайном порядке.

круги в случайном порядке


<canvas id='random_circle'>круги в случайном порядке</canvas>

<script>
  var canvas = document.getElementById("random_circle");
  var context = canvas.getContext('2d');
  canvas.height = 400;
  canvas.width = 400;
  
  var numCircles = 500;
  var maxRadius = 20;
  var minRadius = 3;
  var colors =
      ["aqua", "black", "blue", "fuchsia", "green", "cyan", "lime", "maroon",
      "navy", "olive", "purple", "red", "silver", "teal", "yellow", "azure",
      "gold", "bisque", "pink", "orange"];
  var numColors = colors.length;
  
  // в цикле создаём круги
  for(var n = 0; n < numCircles; n++)
  {
    // в случайном порядке установим характеристики
    var xPos = Math.random() * canvas.width;
    var yPos = Math.random() * canvas.height;
    var radius = minRadius + (Math.random() * (maxRadius-minRadius));
    var colorIndex = Math.random() * (numColors - 1);
    colorIndex = Math.round(colorIndex);
    var color = colors[colorIndex];
    drawCircle(context, xPos, yPos, radius, color);
  }
  
  // функция для рисования круга
  function drawCircle(context, xPos, yPos, radius, color)
  {
    var startAngle = (Math.PI / 180) * 0;
    var endAngle = (Math.PI / 180) * 360;
    context.shadowColor = "gray";
    context.shadowOffsetX = 1;
    context.shadowOffsetY = 1;
    context.shadowBlur = 5;
    context.beginPath();
    context.arc(xPos, yPos, radius, startAngle, endAngle, false);
    context.fillStyle = color;
    context.fill();
  }
</script>

Clock

Закруглённые углы

Закруглённые углы рисуются при помощи функции arcto(), который содержит пять параметров.

  • xBeginning — координата X начала дуги
  • yBeginning — координата Y начала дуги
  • xEnd — координата X конца дуги
  • yEnd — координата Y конца дуги
  • Radius — радиус дуги

Закруглённые углы


<canvas id='arcto'>Закруглённые углы</canvas>

<script>
  var canvas = document.getElementById("arcto");
  var context = canvas.getContext('2d');
  canvas.height = 150;
  canvas.width = 400;
  
  var xPos = 25; 
  var yPos = 25; 
  var width = 150;
  var height = 75; 
  var radius = 30;
  
  context.strokeStyle = "blue"; 
  context.lineWidth = 20;
  context.lineCap = "square"; 
  context.shadowOffsetX = 3;
  context.shadowOffsetY = 3; 
  context.shadowBlur = 5;
  context.shadowColor = "gray";
  context.beginPath();
  context.moveTo(xPos, yPos);  
  context.lineTo(xPos + width - radius, yPos);
  context.arcTo(xPos + width, yPos, xPos + width, yPos + radius, radius);
  context.lineTo(xPos + width, yPos + height);
  context.stroke();
</script>

Кривые Безье

Имеются две функции, для построения кубической и квадратичной кривой Безье:

quadraticCurveTo(Px, Py, x, y)
bezierCurveTo(P1x, P1y, P2x, P2y, x, y)

x и y — это точки в которые необходимо перейти, а координаты P(Px, Py) в квадратичной кривой это дополнительные точки, которые используются для построения кривой. В кубической кривой соответственно две дополнительные точки.

Рисуем кривые Безье

Кривая Безье


<canvas id='bezier_demo'>Кривая Безье</canvas>

<script>
    var canvas = document.getElementById("bezier_demo");
    var context = canvas.getContext('2d');
    canvas.height = 200;
    canvas.width = 260;
    context.beginPath();
    context.moveTo(10, 15);
    context.bezierCurveTo(75, 55, 175, 20, 250, 15);
    context.moveTo(10, 15);
    context.quadraticCurveTo(100, 100, 250, 15);
    context.stroke();
</script>

Раскрашиваем кривые Безье

Раскрашиваем кривые Безье


<canvas id='color_bezier'>Раскрашиваем кривые Безье</canvas>

<script>
  var canvas = document.getElementById("color_bezier");
  var context = canvas.getContext('2d');
  canvas.height = 100;
  canvas.width = 260;
  context.strokeStyle = '#f00';
  context.beginPath();
  context.moveTo(10, 15);
  context.bezierCurveTo(75, 55, 175, 20, 250, 15);
  context.stroke();
  context.strokeStyle = '#0f0';
  context.beginPath();
  context.moveTo(10, 15);
  context.quadraticCurveTo(100, 100, 250, 15);
  context.stroke();
</script>

Это точка на фигуре?

Функция isPointInPath(float x, float y) вернёт значение true, если точка с переданными координатами находится внутри пути. Создадим путь в виде прямоугольника и проверим:

Пример 8

Данный скрипт должен вывести в отладочную консоль сначала true, а затем false.


<p><canvas id='example8'>Пример 8</canvas></p>

<script type="text/javascript">
  var example = document.getElementById("example8");
  var ctx = example.getContext('2d');
  example.height = 400;
  example.width = 400;
  ctx.beginPath();
  ctx.rect(200, 200, 100, 200);
  ctx.stroke();
  console.log(ctx.isPointInPath(250, 250));
  console.log(ctx.isPointInPath(100, 100));
</script>

Функция clip() — ограничиваем область рисования

Функция clip() ничего не рисует. После её вызова любой объект будет рисоваться только в том случае, когда он находится в области на которой определён путь. Нарисуем круг и ограничим область рисования этим кругом. Затем нарисуем две линии, которые будут видны только внутри круга:

Clip

Если закомментировать вызов функции clip(), то увидим, как на самом деле рисуются линии.

No clip


<canvas id='clip_demo'>Clip</canvas>

<script>
  var canvas = document.getElementById("clip_demo");
  var context = canvas.getContext('2d');
  canvas.height = 400;
  canvas.width = 600;
  context.beginPath();
  context.arc(200, 200, 150, 0, Math.PI * 2, true);
  context.stroke();  //Нарисуем круг по которому определим область пути
  context.clip();       //Ограничим область для рисования областью пути

  context.beginPath();
  context.moveTo(100, 320);
  context.lineTo(500, 120);
  context.lineTo(50, 250);
  context.stroke() //Нарисуем линии, которые будут видны только внутри круга
</script>

Тени

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

  • shadowOffsetX = 0.0
  • shadowOffsetY = 0.0
  • shadowBlur = 0.0
  • shadowColor = «transparent black»

Возьмем предыдущий пример и посмотрим на тени

Shadow


<canvas id='clip_shadow'>Shadow</canvas>

<script>
  var canvas = document.getElementById("clip_shadow");
  var context = canvas.getContext('2d');
  canvas.height = 400;
  canvas.width = 600;
  context.beginPath();
  context.arc(200, 200, 150, 0, Math.PI * 2, true);
  context.stroke();  //Нарисуем круг по которому определим область пути
  context.clip();       //Ограничим область для рисования областью пути
    
  context.shadowOffsetX = -10;
  context.shadowOffsetY = -10;
  context.shadowBlur = 2;
  context.shadowColor = 'black';

  context.beginPath();
  context.moveTo(100, 320);
  context.lineTo(500, 120);
  context.lineTo(50, 250);
  context.stroke() //Нарисуем линии, которые будут видны только внутри круга
</script>

Пример с прямоугольниками.

Shadow


<canvas id='rect_shadow'>Shadow</canvas>

<script>
  var canvas = document.getElementById("rect_shadow");
  var context = canvas.getContext('2d');
  canvas.height = 100;
  canvas.width = 600;
  
  var x1Pos = 25;
  var x2Pos = 200;
  var yPos = 10;
  var length = 150; var height = 50;
  
  // первый прямоугольник с тенью
  context.shadowOffsetX = 4;
  context.shadowOffsetY = 4;
  context.shadowBlur = 3;
  context.fillStyle = "deeppink";
  context.shadowColor = "gray";
  context.fillRect (x1Pos, yPos, length, height);
  
  // второй прямоугольник с тенью
  context.shadowOffsetX = 12;
  context.shadowOffsetY = 12;
  context.shadowBlur = 4;
  context.strokeStyle = "aqua";
  context.shadowColor = "lightgreen";
  context.lineWidth = 8;
  context.strokeRect (x2Pos, yPos, length, height);
</script>

Градиенты

Линейные градиенты

Сначала создаётся объект градиента при помощи функции createLinearGradient(float x1, float y1, float x2, float y2) из точки (x1; y1) в точку (x2; y2). Затем добавляются цвета при помощи функции addColorStop(float offset, string color), где offset — отступ со значениями от 0 до 1, а color — нужный цвет. Далее созданный градиент применяется как стиль заливки в свойстве fillStyle.


<canvas id="lineargradient" width="160" height="160"></canvas>
    
<script>
    var canvas = document.getElementById("lineargradient");
    var context = canvas.getContext("2d");
    var gradient = context.createLinearGradient(0, 0, 150, 150);
    gradient.addColorStop(0.0, 'blue');
    gradient.addColorStop(0.5, 'red');
    gradient.addColorStop(1.0, 'green');
    context.fillStyle = gradient;
    
    // рисуем залитый прямоугольник
    context.fillRect(0, 0, 150, 150);
        
</script>

Радиальные градиенты

Радиальный градиент создаётся с помощью функции createRadialGradient(float x1, float y1, float r1, float x2, float y2, float r2) — плавный переход цвета из окружности с центром в точке (x1; y1) и радиусом r1 в окружность с центром точке (x2; y2) и радиусом r2.

Нарисуем шар с псевдо-освещением


<canvas id="radialgradient" width="500" height="170"></canvas>
    
<script>
    var canvas = document.getElementById("radialgradient");
    var context = canvas.getContext("2d");
    
    context.shadowOffsetX = 10;
    context.shadowOffsetY = 15;
    context.shadowBlur = 10;
    context.shadowColor = '#0F0';
    
    var gradient = context.createRadialGradient(60, 60, 15, 75, 75, 75);
    gradient.addColorStop(0.0, '#0F0');
    gradient.addColorStop(1.0, '#0DA805');

    context.fillStyle = gradient;

    context.beginPath();
    context.arc(75, 75, 75, 0, Math.PI * 2, false);
    context.fill();
        
</script>

Прозрачность

Прозрачность задаётся через атрибут globalAlpha. Значения находятся в диапазоне от 0 до 1, где 0 — полная прозрачность, 1 — сплошной цвет.


<canvas id="transparent_demo" width="500" height="100"></canvas>
    
<script>
    var canvas = document.getElementById("transparent_demo");
    var context = canvas.getContext("2d");
    
    // первый объект
    var xPos = 20;
    var yPos = 20;
    var gap = -20;
    var width = 80; var height = 80;
    
    // тень
    context.shadowOffsetX = 4;
    context.shadowOffsetY = 4;
    context.shadowBlur = 3;
    context.shadowColor = "gray";
    
    // прозрачность
    context.globalAlpha = 1;
    context.fillStyle = "orange";
    context.fillRect (xPos + (0 * width) + (0 * gap), yPos, width, height);
    context.globalAlpha = .5;
    context.fillStyle = "blue";
    context.fillRect (xPos + (1 * width) + (1 * gap), yPos, width, height);
    context.globalAlpha = .25;
    context.fillStyle = "red";
    context.fillRect (xPos + (2 * width) + (2 * gap), yPos, width, height);
    context.globalAlpha = .25;
    context.fillStyle = "limegreen";
    context.fillRect (xPos + (3 * width) + (3 * gap), yPos, width, height);
    context.globalAlpha = .4;
    context.fillStyle = "magenta";
    context.fillRect (xPos + (4 * width)+(4 * gap), yPos, width, height);
    context.globalAlpha = .25;
    context.fillStyle = "gold";
    context.fillRect (xPos + (5 * width) + (5 * gap), yPos, width, height);
    context.globalAlpha = .4;
    context.fillStyle = "turquoise";
    context.fillRect (xPos + (6 * width) + (6 * gap), yPos, width, height);

Также прозрачность можно задать в атрибутах цвета:


context.fillStyle = "rgb(0, 0, 255, .5)";

Используем шаблоны

Кроме цветов и градиентов fillStyle и strokeStyle в качестве значения могут принимать и так называемые шаблоны. Шаблоны можно создать из того же самого canvas элемента, изображения или видео. Для примера будем использовать изображение. Шаблон создается методом createPattern(object any, string repeat), где repeat может принимать следующие значения:«repeat» (по умолчанию),«repeat-x»,«repeat-y»,«no-repeat».

Треугольник Серпинского


<canvas id="pascalCanvas" width="800" height="800"></canvas>
 
<script>
 
    function drawPixel(x, y, context) {
        context.fillRect(x, y, 1, 1);
    }
 
    var canvas = document.getElementById("pascalCanvas");
    var context = canvas.getContext("2d");
 
    // gradient style
    var gradient = context.createLinearGradient(0, 0, 0, canvas.height);
    gradient.addColorStop(0, "#00f");
    gradient.addColorStop(1, "#f30");
    context.fillStyle = gradient;
    //context.fillStyle = "#000";
 
    //Pascal's triangle
    var tr = new Array(canvas.height);
    for (i = 0; i < canvas.height; i++) {
        tr[i] = new Array(canvas.width);
        for (k = 0; k < canvas.width; k++) {
            if (k == 0)
                tr[i][k] = 1;
            else
                tr[i][k] = 0;
        }
    }
 
    for (i = 1; i < canvas.height; i++) {
        for (k = 1; k < canvas.width; k++) {
            tr[i][k] = (tr[i-1][k-1] + tr[i-1][k]) % 2;
        }
    }
 
    //draw
    for (i = 0; i < canvas.height; i++) {
        for (k = 0; k < canvas.width; k++) {
            if (tr[i][k] != 0)
            drawPixel(k, i, context);
        }
    }
</script>

Отсюда

Рисование изображений

Чтобы нарисовать изображение, нужно создать его объект с помощью конструктора Image, затем установить путь к изображению через свойство src полученного объекта.

Прежде чем рисовать изображение, его стоит загрузить. Для этого добавим обработчик события load для объекта img, добавим его после создания объекта.

Далее можно нарисовать изображение исходного размера с помощью функции drawImage(object img, float x, float y), где указывается его верхний левый угол в точке (x;y).

Для масштабирования используется другая версия функции — drawImage(object img, float x, float y, float w, float h) — в последних двух параметрах указывается ширина и высота.

Также можно обрезать картинку через ещё одну версию функции drawImage(object img, float sx, float sy, float sw, float sh, float cx, float cy, float cw, float ch) — нарисует часть изображения шириной sw и высотой sh расположенную в точке (sx,sy) в исходном изображении на canvas с шириной cw и высотой ch в точке (cx,cy).


var img = new Image()
img.onload =  function(){
    //Тут ваш код для работы с контекстом
}
img.src = 'path.png'

Выведем изображения с разными размерами.


<canvas id="images_demo" width="500" height="150" style = "border:2px solid black"></canvas>
    
<script>
    var canvas = document.getElementById("images_demo");
    var context = canvas.getContext("2d");
    
    var smallImageXPos = 40;
    var smallImageYPos = 55;
    var smallImageWidth = 75;
    var smallImageHeight = 75;
    var largeImageXPos = 225;
    var largeImageYPos = 10;
    var sourceCropX = 25;
    var sourceCropY = 25;
    var sourceCropWidthX = 50;
    var sourceCropWidthY = 50;
    var imageWidth = 80;
    var imageHeight = 80;
    
    var smallImage = new Image();
    var largeImage = new Image();
    
    smallImage.onload = function()
    {
        context.drawImage(smallImage, smallImageXPos, smallImageYPos);
        context.drawImage(smallImage, smallImageXPos + 80, smallImageYPos - 25,
        smallImageWidth, smallImageHeight);
    }
    
    largeImage.onload = function()
    {
        context.drawImage(largeImage, largeImageXPos, largeImageYPos);
         context.drawImage (largeImage, sourceCropX, sourceCropY,
        sourceCropWidthX, sourceCropWidthY,
        largeImageXPos + 140, largeImageYPos + 10,
        imageWidth, imageHeight);
    }
    
    smallImage.src = "../images/star.jpg";
    largeImage.src = "../images/star.jpg";

    context.shadowOffsetX = -3;
    context.shadowOffsetY = 3;
    context.shadowBlur = 8;
    context.shadowColor = "gray";
</script>

Нельзя вызывать метод drawImage(), если картинка не загружена в браузер. В примере я заранее вывел картинку при помощи тега img. Обычно, в подобных случаях используют вызов window.onload() или document.getElementById(«imageID»).onload.

Ваш браузер не поддерживает canvas


<canvas id="otherImage" width="250" height="300" style="border:1px solid #d3d3d3;">
    Ваш браузер не поддерживает canvas
</canvas>

<script>
window.onload = function() {
    var canvas = document.getElementById('otherImage');
    var context = canvas.getContext('2d');
    var image = new Image();

    image.onload = function() {
       context.drawImage(image, 30, 30);
    };
      
    image.src = 'http://developer.alexanderklimov.ru/android/images/android_cat.jpg';
}
</script>

Для сохранения изображений существует три метода (getAsFile,getBlob,toDataURL), самый удобный — toDataURL поскольку именно он наиболее хорошо поддерживается браузерами. Стоит заметить что метод применяется не к контексту, а к canvas элементу, впрочем его можно получить как свойство ‘canvas’ контекста, также этот метод принимает как аргумент тип изображения (по умолчанию ‘png’). Этот метод вернет изображение в формате base64.

Рисование текста

Существуют функции рисование текста. Залитый текст рисуется через функцию context.fillText(string text, float x, float y) в точке (x;y)

Функция fillText() имеет необязательный аргумент maxWidth, который не совсем корректно работает в некоторых браузерах.

Свойство контекста font управляет стилем текста и имеет синтаксис схожий с css:


// формат
// context.font = "style weight size face";

Не все атрибуты свойства font обязательно указывать. Если какой-то атрибут пропущен, то будет использоваться значение по умолчанию.

Для стилей используются следующие значения

  • normal(the default)
  • italic
  • oblique(similar to italic, usually associated with sans-serif faces)
  • inherit (style comes from the parent element)

Для веса используются значения:

  • normal(the default)
  • bold | bolder
  • lighter
  • 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900
  • inherit(weight comes from the parent element)

Для размеров:

  • px — pixels
  • pt — points
  • em

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

  • Sans-serif: Arial, Verdana
  • Serif: Georgia, Times New Roman, Times
  • Monospace: Courier New, Courier
    
context.font = "bold italic 30px sans-serif";
context.fillText("Hello Kitty", 300, 300);

Управлять цветом мы можем через свойства fillStyle и strokeStyle.

Для рисования контуров текста применяется функции strokeText() вместо fillText().

Для выравнивания текста существует свойство textAlign, оно может принимать пять возможных значений:

  • left — текст выравнивается слева
  • right — текст выравнивается справа
  • center — текст выравнивается по центру
  • start — (значение по умолчанию) текст выравнивается от начала линии слева для письма слева на право и выравнивается справа для письма справа налево
  • end — текст выравнивается от начала линии справа для письма слева на право и выравнивается слева для письма справа налево

<canvas id="textalign_demo" width="500" height="170" style = "border:2px solid black"></canvas>
    
<script>
    var canvas = document.getElementById("textalign_demo");
    var context = canvas.getContext("2d");
    var xPos = canvas.width/2;
    var yPos = 30;
    
    context.font = "15pt Arial";
    context.fillStyle = "blue";
    context.strokeStyle = "hotpink";
    context.lineWidth = 1;
    context.beginPath();
    context.moveTo(xPos, 0);
    context.lineTo(xPos, canvas.height);
    context.stroke();
    context.textAlign = "right";
    context.fillText("right", xPos, yPos * 1);
    context.textAlign = "end";
    context.fillText("end", xPos, yPos * 2);
    context.textAlign = "center";
    context.fillText("center", xPos, yPos * 3);
    context.textAlign = "left";
    context.fillText("left", xPos, yPos * 4);
    context.textAlign = "start";
    context.fillText("start", xPos, yPos * 5);
</script>

Для управления линией основания текста существует свойство textBaseline, оно может принимать следующие значения:

  • top
  • hanging
  • middle
  • alphabetic
  • ideographic
  • bottom

Измерить ширину текста можно через measureText(string text). Она вернет специальный объект TextMetrics, который обладает свойством width — ширина текста в пикселях.


<canvas id="drawtext_demo" width="500" height="170"></canvas>
    
<script>
    var canvas = document.getElementById("drawtext_demo");
    var context = canvas.getContext("2d");
    
    // центрируем текст
    var mText = "Hello Kitty!";
    var xPos = canvas.width/2;
    var yPos = canvas.height/2;

    context.font = "60pt Comic Sans MS";
    context.fillStyle = "lime";
    context.textAlign = "center";
    context.textBaseline = "middle";
    context.fillText(mText, xPos, yPos);
        
</script>

Комбинирование наложений

Наложение двух фигур можно осуществить при помощи свойства globalCompositeOperation, которое может принимать одно из значений.

  • source-over
  • source-in
  • source-out
  • source-atop
  • destination-over
  • destination-in
  • destination-out
  • destination-atop
  • lighter
  • copy
  • xor

Выведем все способы в таблице.


source-over

source-in

source-out

source-atop

destination-over

destination-in

destination-out

destination-atop

lighter

copy

xor

<table border="1" align="center">
  <tr>
    <td>
      <canvas id="source-over" width="120" height="110"></canvas><br/><l>source-over</l>
    </td>
    <td>
        <canvas id="source-in" width="120" height="110"></canvas><br/><l>source-in</l>
    </td>
    <td>
        <canvas id="source-out" width="120" height="110"></canvas><br/><l>source-out</l>
    </td>
    <td>
        <canvas id="source-atop" width="120" height="110"></canvas><br/><l>source-atop</l>
    </td>
  </tr>
  <tr>
    <td>
        <canvas id="destination-over" width="120" height="110"></canvas><br/><l>destination-over</l>
    </td>
    <td>
        <canvas id="destination-in" width="120" height="110"></canvas><br/><l>destination-in</l>
    </td>
    <td>
        <canvas id="destination-out" width="120" height="110"></canvas><br/><l>destination-out</l>
    </td>
    <td>
        <canvas id="destination-atop" width="120" height="110"></canvas><br/><l>destination-atop</l>
    </td>
  </tr>
  <tr>
      <td>
        <canvas id="lighter" width="120" height="110"></canvas><br/><l>lighter</l>
      </td>
      <td>
        <canvas id="copy" width="120" height="110"></canvas><br/><l>copy</l>
      </td>
      <td>
        <canvas id="xor" width="120" height="110"></canvas><br/><l>xor</l>
      </td>
    </tr>
</table>

<script>
    function drawShapes(type)
    {
        canvas = document.getElementById(type);
        context = canvas.getContext("2d");
        var squareOffset = 15;
        var squareSide = 70;
        var circleOffset = 73;
        var circleRadius = 35;

        context.fillStyle = "blue";
        context.fillRect(squareOffset, squareOffset, squareSide, squareSide);

        context.globalCompositeOperation = type;

        context.fillStyle = "red";
        context.beginPath();
        context.arc(circleOffset, circleOffset, circleRadius, 0, Math.PI * 2, true);
        context.fill();
    }
    
    drawShapes("source-over");
    drawShapes("source-in");
    drawShapes("source-out");
    drawShapes("source-atop");
    drawShapes("destination-over");
    drawShapes("destination-in");
    drawShapes("destination-out");
    drawShapes("destination-atop");
    drawShapes("lighter");
    drawShapes("copy");
    drawShapes("xor");
</script>
Реклама

Как в канве сделать тень от объекта

Completing the CAPTCHA proves you are a human and gives you temporary access to the web property.

What can I do to prevent this in the future?

If you are on a personal connection, like at home, you can run an anti-virus scan on your device to make sure it is not infected with malware.

If you are at an office or shared network, you can ask the network administrator to run a scan across the network looking for misconfigured or infected devices.

Another way to prevent getting this page in the future is to use Privacy Pass. You may need to download version 2.0 now from the Chrome Web Store.

Cloudflare Ray ID: 71adcbc069d29a35 • Your IP : 82.102.23.104 • Performance & security by Cloudflare

Еще одно Canvas руководство [2]: Стилизация, градиенты, тени

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

Сделаем наш холст разноцветным


Как вы уже заметили в canvas есть два типа операции отрисовки fill и rect и у каждого есть свои настройки стилей. Для их изменения нужно менять свойства контекста fillStyle и strokeStyle, эти свойства в качестве значения могут принимать не только цвета, но и другие значения которые мы рассмотрим позже. А сейчас мы рассмотрим как поменять цвет. Для этого нужно просто присвоить свойствам fillStyle и strokeStyle новый значения, в случае с цветами это будут строки, при этом canvas поддерживает следующие схемы описания цветов: orange, #FFA500, rgb(255,165,0), rgba(255,165,0,1).
Для примера нарисуем разноцветный круг, оставим в нашем скрипте только получение контекста, а затем добавим следующий код:

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

Поработаем с линиями

Мы также можем изменить некоторые параметры у линий для этого существует несколько свойств, давайте рассмотрим по порядку каждое из них.

Изменяем ширину линии

Значение ширины линии хранится в свойстве lineWidth контекста canvas и одна единица соответствует одному пикселю. Значение по умолчанию естественно 1.0

Стиль верхушки линий


Стиль верхушки линии хранится в свойстве lineCap и для него существует три возможных значение: butt, round, sqare, стилем по умолчанию является butt.

Стиль соединения линий


Стиль соединения линий хранится в свойстве lineJoin и может принимать три возможных значение: miter, round, bevel, стилем по умолчанию является miter.

Еще немного о miter

Мы можем ограничить длину огромного хвоста miter с помощью свойства miteLimit которое по умолчанию принимает значение 10.

Отбросим тени


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

Для примера отбросим две тени на друг друга в ограниченной области рисования и посмотрим что произойдет:

Используем градиенты

Линейные градиенты

Создание объекта градиента

— создаст объект линейного градиента проходящего из точки (x1;y1) в точку (x2;y2), добавим в наш код строку:

Добавляем цвета в градиент

— добавит в наш градиент цвет color с отступом offset который принимает значения от 0 до 1.
Добавим в наш скрипт строки:

Применим градиент как стиль заливки

Свойство fillStyle контекста canvas может принимать в качестве значения не только цвет, но и градиент, добавим в скрипт строку:

Финальный шаг, рисуем залитый прямоугольник

Добавим в наш скрипт последнюю строку:

Радиальные градиенты


При работе с радиальными градиентами отличие от линейных заключается только в создании.
— создаст радиальный градиент с плавным переходом цвета из окружности с центром в точке (x1;y1) и радиусом r1 в окружность с центром точке (x2;y2) и радиусом r2. Для примера нарисуем шарик и сделаем псевдо-освещение:

Создание теней

shadowBlur — Устанавливает степень размытия теней. Нулевое значение этого свойства определяет четкую, резкую тень, выглядящую как силуэт исходного изображения. А значение 20 дает тень в виде размытой дымки, и можно установить еще большее значение. Значение shadowBlur около 3 считается достаточном для ненавязчивого визуального эффекта

shadowOffsetX и shadowOffsetY — Определяют положение тени относительно содержимого, которому она принадлежит. Например, если присвоить каждому свойству значение 5, тень будет расположена на 5 px вправо и 5px вниз от исходного содержимого. Отрицательные значения сдвигают тень в противоположном направлении — влево и вверх.

Ниже показан пример использования теней:

Заполнение фигур изображениями

Нарисованные на холсте фигуры можно заполнять не только сплошными или полупрозрачными цветами, но также градиентными цветами или узорами. Такого рода оформление выполняется в два этапа: сначала создается заполнение, которое потом связывается со свойством fillStyle (или иногда со свойством strokeStyle).

Заполнение узором осуществляется путем множественной вставки копий одного исходного изображения вплотную друг к другу. Изображение, используемое в качестве исходной плитки, нужно загрузить в объект изображения. Имея объект изображения, можно создать объект шаблона, используя метод контекста createPattern(). На этом этапе указывается направление копирования плитки — горизонтально (repeat-x), вертикально (repeat-y) или в обоих направлениях (repeat). Последний шаг — присвоить созданный объект шаблона свойству контекста fillStyle или strokeStyle.

Ниже показан пример:

Этот код создает прямоугольник, который заполняет наш холст исходным изображением в виде паттерна:

Градиенты в Canvas

В Сanvas существуют линейные и радиальные градиенты. Первым шагом в создании градиентной заливки будет создание правильного типа объекта градиента. Для решения этой задачи контекст рисования предоставляет два метода: createLinearGradient() и createRadialGradient(). Они содержат список цветов, которые задействуются в разных точках.

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

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

Рассмотрим, например, линейный градиент, переходящий из светло-розового цвета в желтый. Этот переход можно выполнить в полосе шириной в несколько пикселов или же по всей ширине холста. Кроме этого, направление перехода может быть слева направо, сверху вниз или же с любым наклоном между этими двумя линиями. Все эти аспекты определяются линией градиента.

В данном примере линия градиента берет начало в точке (10, 0) и оканчивается в точке (100, 0). Эти точки предоставляют нам следующую важную информацию о данном градиенте:

  • Градиент горизонтальный. Это означает, что переход цветов происходит слева направо. Мы извлекаем эту информацию из того факта, что обе точки имеют одинаковую ординату. Если бы мы хотели выполнить переход сверху вниз, то можно было использовать, например, точки (0, 10) и (0, 100). А для перехода по диагонали сверху вниз слева направо можно было бы использовать, например, точки (10, 10) и (100, 100).
  • Собственно переход охватывает всего лишь 90 пикселов (начиная со значения абсциссы, равного 10, и заканчивая, когда это значение равно 100). В данном примере горизонтальный размер сердцевидной фигуры слегка меньше, чем размеры градиента, вследствие чего в фигуре видно большую часть градиента.
  • Цвета за пределами этого градиента становятся сплошными. Поэтому, если сделать фигуру шире, ее левый край будет окрашен чистым светло-розовым цветом, а правый — чистым желтым.

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

Остановка цветов градиента осуществляется вызовами метода градиента addColorStop(). При каждом вызове метода ему передается значение смещения от 0 до 1, которое определяет местонахождение цвета в переходе. Значение 0 означает, что цвет находится в самом начале градиента, а значение 1 размещает цвет в конце. Изменив эти числа (например, на 0.2 и 0.8), мы можем сжать градиент, показывая большую область сплошного цвета на каждом конце.

Для двухцветного градиента наиболее логичными значениями смещения являются 0 и 1. Но для градиентов с большим количеством цветов можно устанавливать разные смещения, чтобы сжать одни цветовые полосы и растянуть другие.

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

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

В правой верхней фигуре примера радиального градиента цветовой переход распространяется от центральной точки фигуры с координатами (180, 100). Внутренний цвет ограничен кругом радиусом 10 px, а внешний — кругом радиусом 50 px. Опять же, если выйти за эти пределы, мы получим сплошные цвета — светло-розовый в центре и желтый по внешней окружности.

Понравилась статья? Поделить с друзьями:
  • Honor band 4 running aw70 инструкция
  • Руководство умвд новосибирска
  • Мануал на brp xmr 1000
  • Бесплатно скачать руководства по ремонту мерседес
  • Pfaff stretch jeans 6091 инструкция на русском