HTML5 Функция поворота холста - PullRequest
0 голосов
/ 11 апреля 2020
function drawNumbers(){
    var rad, num;

    cx.font= "30px Arial";
    cx.textAlign = "center";
    cx.textBaseline = "middle";

    //numbers around the inner circumference
     for(num=1; num < 13; num++){
    rad = num * Math.PI/6; //angle for every number
     cx.rotate(rad);
     cx.translate(0, -175);
     cx.rotate(-rad);
     cx.fillText(num.toString(),0,0);
     cx.rotate(rad);
     cx.translate(0, 175);
     cx.rotate(-rad);
    }
}

function drawHands(){
    //getting the time
    var time = new Date();
    var hours = time.getHours();
    var minutes = time.getMinutes();
    var seconds = time.getSeconds();

    //setting the radians based on the time
    //hour hand
    hours %= 12;
    hours = (hours * Math.PI/6) + (minutes * Math.PI/360) + (seconds * Math.PI/21600);
    hands(hours, radius * 0.04, radius * 0.5);

    //minute hand
    minutes = (minutes * Math.PI/30) + (seconds * Math.PI/1800);
    hands(minutes, radius * 0.03, radius * 0.65);

    //second hand
    seconds = (seconds * Math.PI/30);
    hands(seconds, radius * 0.01, radius * 0.68);
}

function hands(ang, width, length){
    cx.beginPath();
    cx.lineWidth = width;
    cx.lineJoin = "round";
    cx.lineCap = "round";
    cx.moveTo(0, 0);
    cx.rotate(ang);
    cx.lineTo(0, -length);
    cx.stroke();
    cx.rotate(-ang);
}

Я изучал холст HTML5 в W3Schools, и учебник учил, как сделать рабочие часы. 1. Я просто не понимаю, как работают дополнительные повороты в функциях. 2. При применении функции поворота всегда ли она вращается от центра источника (0, 0) холста?

1 Ответ

0 голосов
/ 11 апреля 2020

Когда вы вызываете функцию 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() извлечете последнее состояние из стека, вернув вас к предыдущему преобразованию. Эта статья Якоба Дженкова объясняет этот метод несколькими примерами.

...