Смещение, масштабирование и поворот координатной сетки

По умолчанию координатная сетка холста <canvas> имеет начало координат в левом верхнем углу, ось абсцисс направлена вправо, ось ординат вниз, а масштабный коэффициент равен одному пикселю. JavaScript имеет ряд функций, которые позволяют манипулировать координатной сеткой.

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

Метод save() - сохраняет все состояние холста.

Метод restore() восстанавливает последнее сохранённое состояние холста.

Состояние холста сохраняется в стеке. Каждый раз, когда вызывается метод save(), текущее состояние отрисовки записывается в стек.

Состояние отрисовки содержит:

  • Трансформации, которые были применены (например, translate, rotate and scale – см. ниже).
  • Текущее значение следующих атрибутов: strokeStyle, fillStyle, globalAlpha, lineWidth, lineCap, lineJoin, miterLimit, lineDashOffset, shadowOffsetX, shadowOffsetY, shadowBlur, shadowColor, globalCompositeOperation, font, textAlign, textBaseline, direction, imageSmoothingEnabled.

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

Параллельный перенос (смещение) координатной сетки:

translate(x, y) - перемещение холста на сетке. x и y - смещение по горизонтали и вертикали соответственно.

Поворот координатной сетки:

rotate(angle) - поворачивает холст по часовой стрелке вокруг начальной точки на угол anglе в радианах.

Масштабирование координатной сетки:

scale(x, y) - масштабирует единицы холста по x по горизонтали и по y по вертикали. Оба параметра являются действительными числами. Значения меньше 1,0 уменьшают размер блока, а значения выше 1,0 увеличивают размер блока.

По умолчанию одна единица на холсте равна одному пикселю. Если применить коэффициент масштабирования 0,5, результирующая единица измерения станет равной 0,5 пикселя, а фигуры будут отображаться в два раза меньше. Аналогичным образом установка коэффициента масштабирования на 2,0 увеличила бы размер единицы, и теперь одна единица становится двумя пикселями. Это приводит к тому, что фигуры рисуются в два раза больше.

Используя отрицательные числа, можно зеркально отразить оси.

Например,

ctx.translate(0, canvas.height); 
ctx.scale(1,-1); 

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

Пример использования всех трех методов:

var obj = document.getElementById('drawing'); // Получить объект холста
if (obj.getContext){
  var ctx = obj.getContext('2d');
  ctx.translate(200,300); // сдвиг оси координат
  ctx.scale(10,10);  // увеличение в 10 раз
  ctx.rotate(-Math.PI/6); // поворот против часовой стрелки на 30 градусов
  ctx.fillStyle = "rgb(0,0,200)";
  ctx.fillRect (4, 4, 8, 6);
}

Универсальный метод, основанный на матрице преобразований (см. Лекцию "Операции преобразования на плоскости"), позволяющий применить сразу несколько преобразований:

transform(a, b, c, d, e, f) - накладывает матрицу преобразований, заданную параметрами, на текущую матрицу. Матрица преобразования задаётся следующим образом:

$$\begin{pmatrix}
a & c & e \\
b & d & f \\
0 & 0 & 1 \\
\end{pmatrix}
$$

setTransform(a, b, c, d, e, f) - сбрасывает текущую матрицу преобразования, а затем вызывает transform() в соответствии с аргументами.

resetTransform() - сбрасывает текущую матрицу преобразования к значению по умолчанию. Аналогично вызову ctx.setTransform(1, 0, 0, 1, 0, 0).

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

var obj = document.getElementById('drawing'); // Получить объект холста
if (obj.getContext){ 
  var ctx = obj.getContext('2d');
 // ctx.translate(200,300);
 // ctx.scale(10,10);
 // ctx.rotate(-Math.PI/6);
  ctx.setTransform(10*0.86, -0.5*10, 0.5*10, 10*0.86, 200, 300);
  ctx.fillStyle = "rgb(0,0,200)";
  ctx.fillRect (4, 4, 8, 6);
}