Поверните треугольник в центре себя - PullRequest
1 голос
/ 03 октября 2019

Я хочу повернуть треугольник в центре самого себя. У меня есть этот скрипт:

  var ctx = canvas.getContext('2d');
  var angle = 30;
  setInterval(rotate, 50);
  function rotate() {
  ctx.fillStyle = "white";
  ctx.fillRect(0, 0, canvas.width, canvas.height);
  ctx.save();
    ctx.translate(150, 150); // x, y
    ctx.rotate(angle * Math.PI / 180)
    ctx.fillStyle = "yellow";
    var path=new Path2D();
    path.moveTo(-50+50,-25);
    path.lineTo(-50,-50-25);
    path.lineTo(-50-50,-25);
    ctx.fill(path);
    ctx.restore();
    angle++;
  }
<canvas id="canvas" width="1800" height="700"></canvas>

Вращается, но не в центре. Я хочу, чтобы это выглядело так:

  var ctx = canvas.getContext('2d'); 
  setInterval(rotate, 50);
  var angle = 30;
  function rotate() {
    ctx.fillStyle = "white";
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    ctx.save();
    ctx.translate(50, 50);
    ctx.rotate(angle * Math.PI / 180)

    ctx.fillStyle = "green";
    ctx.fillRect(-25, -25, 50, 50);
    ctx.restore();
    angle++;
    }
<canvas id="canvas" width="1800" height="700"></canvas>
Я думаю, мне просто нужно получить ширину и высоту треугольника и отклонить его на 2, но я не знаю, как это сделать. Спасибо за каждый ответ!

Ответы [ 2 ]

1 голос
/ 03 октября 2019

То, что вы хотите, это центроид вашей фигуры.

var ctx = canvas.getContext('2d');
var angle = 30;
var points = [
  {x:0, y:-25},
  {x:-50, y:-75},
  {x:-100, y:-25}
];
// first sum it all
var sums = points.reduce( (sum, point) => {
  sum.x += point.x;
  sum.y += point.y;
  return sum;
}, {x:0, y:0});
// we want the mean
var centroid = {
  x: sums.x / points.length,
  y: sums.y / points.length
};

rotate();
function rotate() {
  ctx.setTransform(1,0,0,1,0,0);
  ctx.fillStyle = "white";
  ctx.fillRect(0, 0, canvas.width, canvas.height);
  // general position in canvas
  ctx.translate(100, 100);
  // move to centroid of our triangle
  ctx.translate(centroid.x, centroid.y); // x, y
  // rotate
  ctx.rotate(angle * Math.PI / 180)
  // go back to our initial position
  ctx.translate(-centroid.x, -centroid.y); // x, y

  ctx.fillStyle = "yellow";
  var path=new Path2D();
  path.moveTo(points[0].x, points[0].y);
  path.lineTo(points[1].x, points[1].y);
  path.lineTo(points[2].x, points[2].y);
  ctx.fill(path);

  // demo only
  ctx.beginPath();
  ctx.arc(centroid.x, centroid.y, 50, 0, Math.PI*2)
  ctx.stroke();
  
  angle++;
  requestAnimationFrame( rotate );
}
<canvas id="canvas" width="1800" height="700"></canvas>
0 голосов
/ 03 октября 2019

Создайте путь один раз

Вы используете объект Path2D, который можно использовать повторно.

Если вы создаете треугольник, уже центрированный в его начале (или любом другом пути по этому вопросу), его тривиально повернуть.

Повторное использование объекта пути также выполняется намного быстрее, если вам нужно много визуализировать.

Функция для создания пути из набора точек. Он автоматически центрирует путь к своему собственному источнику (определяется по среднему значению его точек)

const point = (x, y) => ({x, y});
function createPath(...points) {
    var cx = 0; cy = 0;
    for (const p of points) {
        cx += p.x;
        cy += p.y;
    }
    cx /= points.length;
    cy /= points.length;

    const path = new Path2d;
    for (const p of points) { path.lineTo(p.x - cx, p.y - cy); }
    path.closePath();
    return path;
}

Чтобы создать треугольник

const triangle = createPath(point(0,-25), point(-50,-75), point(-100,-25));

Затем вы можете сделать так, чтобы он вращался вокруг своего собственного источникаwith

function drawPath(path, x, y, angle) {
     ctx.setTransform(1, 0, 0, 1, x, y);
     ctx.rotate(angle);
     ctx.stroke(path);
}

Пример

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

const point = (x, y) => ({x, y});
const triangle = createPath(point(0,-25), point(-50,-75), point(-100,-25));
const rectangle = createPath(point(0,-25), point(-50,-25), point(-50,-125), point(0,-125));
const thing = createPath(point(0,-12), point(-25,-12), point(-25,-62), point(0,-62), point(22,-35));

function drawPath(path, x, y, angle) {
    ctx.setTransform(1, 0, 0, 1, x, y);
    ctx.rotate(angle);
    ctx.stroke(path);
}

function renderLoop(time) {
    ctx.clearRect(0, 0, can.width, can.height);
    drawPath(triangle, 75, 74, time / 1000 * Math.PI); //360 every 2 second
    drawPath(rectangle, 125, 125, time / 2000 * Math.PI); //360 every 4 second
    drawPath(thing, 125, 100, time / 3000 * Math.PI); 
    
    ctx.setTransform(1, 0, 0, 1, 0, 0); 
    requestAnimationFrame(renderLoop);
}

requestAnimationFrame(renderLoop);
const can = Object.assign(document.createElement("canvas"), {width: 200, height: 200});
document.body.appendChild(can);
const ctx = can.getContext("2d");

function createPath(...points) {
    var cx = 0; cy = 0;
    for (const p of points) {
        cx += p.x;
        cy += p.y;
    }
    cx /= points.length;
    cy /= points.length;

    const path = new Path2D;
    for (const p of points) {
        path.lineTo(p.x - cx , p.y - cy);
    }
    path.closePath();
    return path;
}
...