Делаем мир canvas ярче. Применение стилей, цветов и теней


Раньше я рассказывал про то, как рисовать на canvas’e графические примитивы. При их отрисовке использовались установленные по умолчанию цвета и стили. Можно сделать ваши творения немного ярче и привлекательней, если использовать некоторые свойства контекста отрисовки на canvas’е.

Свойства strokeStyle и fillStyle

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

  • ‘coral’
  • ‘#FF7F50’
  • ‘rgb(255, 127, 80)’
  • ‘rgba(255, 127, 80, 1)’

Все эти строки описывают один и тот же цвет — коралловый.

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

Нарисуем что-нибудь, используя эти свойства.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var canv = document.getElementById('canv'),
  g = canv.getContext('2d');
 
g.fillStyle = 'orange';
g.fillRect(50, 50, 90, 380);
 
g.strokeStyle = 'red';
g.strokeRect(180, 50, 90, 380);
 
g.fillStyle = 'green';
g.fillRect(320, 50, 90, 380);
 
g.strokeStyle = 'blue';
g.strokeRect(460, 50, 90, 380);

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

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

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

1
2
3
function intRand(min, max) {
  return Math.round(min + (max - min) * Math.random());
}

Эта функция будет возвращать случайное число на отрезке от min до max.

Теперь приступим к рисованию самих фигур

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
var canv = document.getElementById('canv'),
  g = canv.getContext('2d'),
 
/* Определяем квадрат, внутри которого могут располагаться
   верхние левые углы случайных фигур.
   Для окружности (круга) это верхний левый угол описанного
   около неё (него) квадрата.
*/
  maxX = 560, 
  maxY = 400,
  minX = 80,
  minY = 80,
 
/* Определяем диапазон, внутри которого будет колебаться
   сторона квадрата. Для окружности (круга) квадрата около неё (него)
   описанного.
*/
  minWH = 40,
  maxWH = 80,
 
/* Объявляем переменные для хранения случайных 
   координат верхнего левого угла фигуры, цвета и числа,
   которое будет определять тип фигуры.
*/
  rndX, rndY, color, rnd;
 
// Фигур будет десять 
for(var i = 0; i < 10; ++i) {
 
  //Определяем случайные координаты
  rndX = intRand(minX, maxX);
  rndY = intRand(minY, maxY);
 
  // ,сторону квадрата
  rndWH = intRand(minWH, maxWH);
 
  // ,цвет
  color = 'rgb(' + intRand(0, 255) + ', ' + intRand(0, 255) + ', ' + intRand(0, 255) + ')';
 
  // и число, определяющее тип фигуры
  rnd = intRand(0, 3);
 
  // Если число чётное (0 или 2), то фигура будет не заполнена
  if(rnd % 2 == 0) {
    g.strokeStyle = color;
  // в противном случае заполнена
  } else {
    g.fillStyle = color;
  }
 
  g.beginPath();
  switch(rnd) {
    case 0 :
      g.fillRect(rndX, rndY, rndWH, rndWH);
      break;
    case 1 :
      g.strokeRect(rndX, rndY, rndWH, rndWH);
      break;
    case 2:
      g.arc(rndX - rndWH / 2, rndY - rndWH / 2, rndWH / 2, 0, Math.PI * 2, true);
      g.stroke();
      break;
    case 3:
      g.arc(rndX - rndWH / 2, rndY - rndWH / 2, rndWH / 2, 0, Math.PI * 2, true);
      g.fill();
  }
}

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

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

Значение прозрачности можно задавать, используя свойство globalAlpha. Оно принимает значения от 0.0 (полностью прозрачный) до 1.0 (полностью непрозрачный). По-умолчанию оно равно 1.0. После того, как вы установили это свойство, все нарисованные фигуры будут иметь заданную прозрачность. Если вы хотите нарисовать несколько фигур с разной прозрачностью, вам придётся менять это свойство перед отрисовкой каждой фигуры.

Нарисуем три пересекающихся полупрозрачных круга.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var canv = document.getElementById('canv'),
          g = canv.getContext('2d'),
          deg360 = Math.PI * 2;
 
g.globalAlpha = 0.333;
 
g.fillStyle = 'red';
g.beginPath();        
g.arc(320, 200, 100, 0, deg360, true);
g.fill();
 
g.fillStyle = 'green';
g.beginPath();        
g.arc(270, 290, 100, 0, deg360, true);
g.fill();
 
g.fillStyle = 'blue';
g.beginPath();        
g.arc(370, 290, 100, 0, deg360, true);
g.fill();

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

Свойство globalAlpha удобно использовать, если вы хотите нарисовать много фигур с одинаковой прозрачностью, но если вы хотите, чтобы у фигур была разная прозрачность, то имеет смысл использовать формат свойства strokeStyle и fillStyle, которым присваивать строку в формате rgba. Этот подход более гибок, так как позволяет задать прозрачность отдельно для заливки и обводки.

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

1
2
3
4
5
6
7
var canv = document.getElementById('canv'),
  g = canv.getContext('2d');
 
for(var i = 0; i < 5; ++i) {
  g.fillStyle = 'rgba(255, 0, 0, ' + 0.2 * (i + 1) + ')';
  g.fillRect(80 + i * 100, 80, 80, 320);
}

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

Градиенты

Свойства fillStyle и strokeStyle, кроме строк, описывающих цвет, могут так же принимать в качестве значения объекты CanvasGradient. Для создания этих объектов используются два метода: createLinearGradient и createRadialGradient. Первый метод создает линейный градиент, а второй — радиальный. Для создания линейного градиента указываются координаты начальной и конечной точек, через которые он проходит. Строка кода

var grad = g.createLinearGradient(x0, y0, x, y);

создаст градиент идущий от точки с координатами x0 и y0 в точку с координатами x и y.
Для добавления в градиент цвета используется метод addColorStop(offset, color). Здесь оffset – позиция цвета в градиенте (допустимые значения от 0.0 до 1.0), color – строка описывающая добавляемый цвет.

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var canv = document.getElementById('canv'),
  g = canv.getContext('2d'),
 
//Координаты верхнего левого угла пряиоугольника
x0 = 80,
y0 = 80,
 
//Высота и ширина прямоугольника
w = 480,
h = 320;
 
//Нижний левый угол прямоугольника будет иметь координаты x0 + w и y0 + h
grad = g.createLinearGradient(x0, y0, x0 + w, y0 + h);
 
grad.addColorStop(0, 'black');
grad.addColorStop(0.5, 'white');
grad.addColorStop(1, 'red');
 
g.fillStyle = grad;
 
g.fillRect(x0, y0, w, h);

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

Работа с радиальными градиентами отличается только способом их создания. Код

var grad = createRadialGradient(x1, y1, r1, x2, y2, r2)

создаст градиент, переходящий из окружности с центром в точке с координатами x1, y1 и радиусом r1 в окружность с центром в точке с координатами x2, y2 и радиусом r2.

Нарисуем шарик

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var canv = document.getElementById('canv'),
g = canv.getContext('2d'),
 
//Координаты цента большей окружности
x0 = 320,
y0 = 240,
 
//и её радиус
r = 200,
 
grad = g.createRadialGradient(x0, y0, r, 220, 140, 2);
 
grad.addColorStop(0, 'black'); 
grad.addColorStop(1, 'yellow');
 
g.fillStyle = grad;
 
g.arc(x0, y0, r, 0, Math.PI * 2, true);  
 
g.fill();

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

Толщина линий и стиль их верхушки

Ранее я уже рассказывал, как рисовать линии на canvas’е. Их ширина хранится в свойстве lineWidth, измеряется в пикселях и по-умолчанию равна 1.

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
var canv = document.getElementById('canv'),
  g = canv.getContext('2d'),
 
//у - координата красной линни
y = 22;
 
//Красная линия
g.strokeStyle = 'red';
g.lineWidth = 6;
g.moveTo(6, y);
g.lineTo(150, y);
g.stroke();
 
g.strokeStyle = 'black';
g.lineWidth = 30;
 
//butt
g.beginPath();
g.moveTo(24, 170);
g.lineTo(24, y);
g.stroke();
 
//round
g.beginPath();
g.lineCap = 'round'
g.moveTo(78, 170);
g.lineTo(78, y);
g.stroke();
 
//square
g.beginPath();
g.lineCap = 'square'
g.moveTo(132, 170);
g.lineTo(132, y);
g.stroke();

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

Внимательно посмотрим на то, как концы линий расположены относительно тонкой красной линии. Линии со стилем верхушки butt заканчивается ровно по середине красной черты, у линии со стилем round закругление начинается когда она уже пересекла красну черту, ну а линия со стилем squere вылазит за красную черту на свою ширину.

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

Стиль соединения линий хранится в свойстве lineJoin, по умолчанию равном ‘miter‘. Для этого свойства существует ещё два возможных значения ‘round‘ и ‘bevel‘. Чтобы понять, в чём отличие этих стилей, давайте нарисуем три изгибающиеся линии с разными стилями соединения. Место их изгиба опять же обозначим более тонкой красной линией.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
var canv = document.getElementById('canv'),
  g = canv.getContext('2d'),
 
//у - координата красной линни
y = 40;
 
g.strokeStyle = 'black';
g.lineWidth = 30;
 
//miter
g.beginPath();
g.moveTo(25, 170);
g.lineTo(25, y);
g.lineTo(100, 120);
g.stroke();
 
//round
g.beginPath();
g.lineJoin = 'round'
g.moveTo(150, 170);
g.lineTo(150, y);
g.lineTo(225, 120);
g.stroke();
 
//bevel
g.beginPath();
g.lineJoin = 'bevel'
g.moveTo(275, 170);
g.lineTo(275, y);
g.lineTo(340, 120);
g.stroke();
 
//Красная линия
g.beginPath();
g.strokeStyle = 'red';
g.lineWidth = 6;
g.moveTo(5, y);
g.lineTo(370, y);
g.stroke();

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

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

Тени

Для задания теней существуют четыре свойства:

  • shadowOffsetX – смещение тени по горизонтали
  • shadowOffsetY – смещение по вертикали
  • shadowBlur – степень размытия
  • shadowColor – цвет тени

Чтобы продемонстрировать эти свойства в действии, я думаю, достаточно нарисовать прямоугольник, отбрасывающий тень.

1
2
3
4
5
6
7
8
9
var canv = document.getElementById('canv'),
  g = canv.getContext('2d');
 
g.shadowOffsetX = 10;
g.shadowOffsetY = 15;
g.shadowBlur = 4;
g.shadowColor = 'red';
 
g.fillRect(80, 80, 480, 320);

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

На сегодня всё. Следующий раз я научу вас отрисовывать текст на canvas’e.