Когда вы вызываете функцию rotate
, она поворачивает весь холст, представьте, что вы держите картину, а затем наклоняете ее. Это происходит вокруг происхождения всегда. Способ поворота вокруг другой точки - сначала translate
весь холст, затем rotate
it.
Возвращаясь к аналогии с картиной, если мы повернули нашу картину, как только мы нарисовали нашу линию Нам нужно восстановить картину в вертикальном положении. Таким образом, мы rotate(-ang)
. Если бы мы перевели, нам также пришлось бы отменить наш переход аналогичным образом.
Поворот и почему мы отменяем поворот
В приведенном ниже коде вы можете видеть, что я рисую базовый черный прямоугольник , а затем вызывая функцию, которая поворачивает холст на 0,5 радиана, и др aws еще один прямоугольник дважды. Я не отменил свое вращение, поэтому 3-й прямоугольник фактически повернут на 1 радиан.
let canvas = document.getElementById("canvas");
let ctx = canvas.getContext("2d");
function drawRotatedRectangle() {
ctx.rotate(0.5);
ctx.fillRect(0, 0, 60, 50);
}
// Draw base rectangle
ctx.fillRect(0, 0, 60, 50);
// Rotate and draw second rectangle
ctx.fillStyle = "#FF0000";
drawRotatedRectangle();
// rotate and draw third rectangle
ctx.fillStyle = "#00FF00";
drawRotatedRectangle();
<canvas id="canvas"></canvas>
Чтобы исправить это, мы модифицируем функцию drawRotatedRectangle()
, чтобы отменить все выполненные ею переводы и повороты:
let canvas = document.getElementById("canvas");
let ctx = canvas.getContext("2d");
function drawRotatedRectangle() {
ctx.rotate(0.5);
ctx.fillRect(0, 0, 60, 50);
ctx.rotate(-0.5);
}
// Draw base rectangle
ctx.fillRect(0, 0, 60, 50);
// Rotate and draw second rectangle
ctx.fillStyle = "#FF0000";
drawRotatedRectangle();
// rotate and draw third rectangle
ctx.fillStyle = "#00FF00";
drawRotatedRectangle();
<canvas id="canvas"></canvas>
Теперь мы видим, что красный (скрытый) прямоугольник и зеленый прямоугольник находятся под одним углом.
Поворот вокруг другой точки к origin
Чтобы продемонстрировать, как мы можем вращаться вокруг другого местоположения относительно источника, мы можем сначала перевести, где находится источник нашего контекста, а затем повернуть наш холст. Ниже я перемещаю начало координат в центр базового прямоугольника, вращаю холст и рисую повернутый прямоугольник поверх базового прямоугольника. Снова переводы и повороты восстанавливаются в порядке последнего применения.
let canvas = document.getElementById("canvas");
let ctx = canvas.getContext("2d");
function drawRotatedRectangle() {
// Move origin to center of rectangle
ctx.translate(30, 25);
// Rotate 0.5 radians
ctx.rotate(0.5);
// Draw rectangle where the center of the rectangle is the origin
ctx.fillRect(-30, -25, 60, 50);
// Undo our rotate
ctx.rotate(-0.5);
// Undo our translate
ctx.translate(-30, -25);
}
// Draw base rectangle
ctx.fillRect(0, 0, 60, 50);
// Rotate and draw second rectangle
ctx.fillStyle = "#FF0000";
drawRotatedRectangle();
// rotate and draw third rectangle
ctx.fillStyle = "#00FF00";
drawRotatedRectangle();
<canvas id="canvas"></canvas>
Редактировать - Обработка ошибок округления
Как упомянуто в комментариях Кайидо, функция rotate(a)
будет округлять ввод, который дается так просто выполнение обратной функции rotate(-a)
не вернет вас к исходному преобразованию.
Решение, которое они предложили, состоит в том, чтобы установить матрицу преобразования в нужное место с помощью setTransform()
, в этом примере мы только возвращаемся к исходное преобразование холста, чтобы мы могли использовать единичную матрицу:
ctx.setTransform(1,0,0,1,0,0)
Альтернативно, вы также можете использовать методы save()
и restore()
. Они будут действовать как выталкивание текущего состояния контекста холста в стек, и когда вы restore()
извлечете последнее состояние из стека, вернув вас к предыдущему преобразованию. Эта статья Якоба Дженкова объясняет этот метод несколькими примерами.