Транcформации на canvas

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

Прежде чем я начну рассказывать про трансформации, я бы хотел обратить ваше внимание на два метода: save и restore. Эти методы используются для получения и восстановления состояния холста. Состояние холста — это положение системы координат и применённые стили. Каждый раз, при вызове метода save, состояние холста помещается в стек, а каждый раз при вызове метода restore достаётся оттуда.

Пример использования методов restore и save: [Посмотреть демо]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var g = document.getElementById('canv').getContext('2d'),
 
  rainbow = [
    'red',
    'orange',
    'yellow',
    'green',
    'lightblue',
    'blue',
    'purple'
  ];
 
for(var i = 0; i < 7; i++) {
  g.fillStyle = rainbow[i];
  g.globalAlpha = 1 / 7 * (i + 1);
  g.save();
  g.fillRect(10 + 40 * i, 40, 30, 400);   
}
 
for(var i = 0; i < 7; i++) {
  g.restore();
  g.fillRect(290 + 40 * i, 40, 30, 400);
}

Метод translate

Этот метод принимает в качестве аргументов смещения начала системы координат по горизонтали и вертикали. Желательно сохранять состояние холста перед трансформацией, так как вернуться к предыдущему состоянию проще, используя метод restore, чем делать обратное преобразование, которое вернёт систему координат в начальное состояние. Именно так я поступил при написании следующего примера: [Посмотреть демо]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var g = document.getElementById('canv').getContext('2d');
 
g.translate(5, 5);
 
for(var i = 0; i < 24; i++) {
  g.save();
  for(var j = 0; j < 24; j++) {
    g.fillStyle = rainbow[Math.floor(rainbow.length * Math.random())];
    g.fillRect(0, 0, 10, 10);
    g.translate(20, 0);
  }
  g.restore();
  g.translate(0, 20);
}

Поворот системы координат. Метод rotate

Метод rotate принимает в качестве аргумента единственный параметр — угол поворота системы координат по часовой стрелке в радианах. Поворот осуществляется относительно начала системы координат.

Пример: [Посмотреть демо]

1
2
3
4
5
6
7
8
9
10
11
var g = document.getElementById('canv').getContext('2d');
 
g.translate(320, 240);
 
for(var i = 0; i < 20; i++) {      
  g.beginPath();
  g.arc(0, 10 + 10 * i, 5 + i * 2, 0, Math.PI * 2, true);
  g.closePath();      
  g.fill();      
  g.rotate(Math.PI / 5);
}

Масштабирование. Метод scale

Метод scale принимает два параметра: коэффициент масштабирования по горизонтали и коэффициент масштабирования по вертикали. Например, строка кода

ctx.scalе(0.5, 0.5);

уменьшит координатную сетку вдвое.

Пример: [Посмотреть демо]

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
var g = document.getElementById('canv').getContext('2d');
 
g.globalAlpha = 0.33;
 
g.translate(320, 240);
 
g.fillStyle = 'red';
g.beginPath();		
g.arc(0, 0, 200, 0, Math.PI * 2, true);
g.closePath();
g.fill();
 
g.fillStyle = 'green';
g.scale(0.5, 1);
g.beginPath();
g.arc(0, 0, 200, 0, Math.PI * 2, true);
g.closePath();
g.fill();
 
g.fillStyle = 'blue';
g.scale(2, 0.5);
g.beginPath();
g.arc(0, 0, 200, 0, Math.PI * 2, true);
g.closePath();
g.fill();

Методы setTransform и transform

Этот метод заключает в себе все описанные ранее методы.

ctx.setTransform(a11, a12, а21, a22, dx, dy);

Аргументы а11 и а22 — это коэффициенты масштабирования по горизонтали и вертикали соответственно.

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

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

При вызове этого метода все преобразования системы координат сбрасываются. Начало системы координат снова располагается в верхнем левом углу холста, ось OX направляется вправо, ось OY – вниз.

1
2
3
4
5
6
7
8
9
// этот перенос не учтётся
g.translate(400, 400); 
 
/*
 * начало системы координат установится в точке (320, 240),
 * если до этого преобразований не было
 */
 
g.setTransform(1, 0, 0, 1, 320, 240);

Пример: [Посмотреть демо]

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
var g = document.getElementById('canv').getContext('2d'),
  a = 200,
  b = 100,
  x = 320,
  y = 50;
 
g.globalAlpha = 0.4;
 
g.fillStyle = 'red';
g.setTransform(1, 1.5, 0, 1, x, y);
g.fillRect(0, 0, a, b);
 
g.fillStyle = 'green';
g.setTransform(1, 1, 0, 1, x, y);		
g.fillRect(0, 0, a, b);
 
g.fillStyle = 'blue';
g.setTransform(1, 0.5, 0, 1, x, y);		
g.fillRect(0, 0, a, b);
 
g.fillStyle = 'red';
g.setTransform(-1, 1.5, 0, 1, x, y);
g.fillRect(0, 0, a, b);
 
g.fillStyle = 'green';
g.setTransform(-1, 1, 0, 1, x, y);		
g.fillRect(0, 0, a, b);
 
g.fillStyle = 'blue';
g.setTransform(-1, 0.5, 0, 1, x, y);		
g.fillRect(0, 0, a, b);

Метод transform полностью аналогичен, за исключением того, что при его использовании сделанные ранее преобразования системы координат не сбрасываются.

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