Что означает startAngle в эллипсе холста HTML5? - PullRequest
0 голосов
/ 03 сентября 2018

Рисуя эллипс холста , я с удивлением обнаружил, что «startAngle» на самом деле, похоже, не определяет угол от начала эллипса. Как видно из фрагмента кода ниже, два эллипса с одинаковым 'startAngle', но разными значениями радиуса, начинают свои дуги в самых разных местах.

Высокий эллипс, кажется, начинается под углом 50 или 60 градусов, если измерять начало координат, тогда как угол широкого эллипса выглядит как 15 или 20 градусов.

Так что же такое startAngle?

https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/ellipse

var c = document.getElementById("canvas");
var ctx = c.getContext("2d");

var startAngle = 0.5;
var endAngle = Math.PI * 2;

ctx.beginPath();
ctx.ellipse(70, 150, 50, 140, 0, startAngle, endAngle);
ctx.stroke();

ctx.beginPath();
ctx.ellipse(300, 150, 140, 50, 0, startAngle, endAngle);
ctx.stroke();
<html>
<body>

<canvas id="canvas" width="500" height="300">

</body>
</html>

Ответы [ 2 ]

0 голосов
/ 03 сентября 2018

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

var c = document.getElementById("canvas");
var ctx = c.getContext("2d");

var startAngle = Math.PI * 2 / 360 * 45;
var endAngle = Math.PI * 2 / 360 * 315;

ctx.fillStyle = "rgba(255, 255, 255, 0.125)";

ctx.beginPath();
ctx.moveTo(70, 150);
ctx.ellipse(70, 150, 50, 50, 0, startAngle, endAngle);
ctx.lineTo(70, 150);
ctx.stroke();
ctx.fill();

ctx.beginPath();
ctx.moveTo(70, 150);
ctx.ellipse(70, 150, 50, 60, 0, startAngle, endAngle);
ctx.lineTo(70, 150);
ctx.stroke();
ctx.fill();

ctx.beginPath();
ctx.moveTo(70, 150);
ctx.ellipse(70, 150, 50, 70, 0, startAngle, endAngle);
ctx.lineTo(70, 150);
ctx.stroke();
ctx.fill();

ctx.beginPath();
ctx.moveTo(70, 150);
ctx.ellipse(70, 150, 50, 80, 0, startAngle, endAngle);
ctx.lineTo(70, 150);
ctx.stroke();
ctx.fill();

ctx.beginPath();
ctx.moveTo(70, 150);
ctx.ellipse(70, 150, 50, 90, 0, startAngle, endAngle);
ctx.lineTo(70, 150);
ctx.stroke();
ctx.fill();

ctx.beginPath();
ctx.moveTo(70, 150);
ctx.ellipse(70, 150, 50, 100, 0, startAngle, endAngle);
ctx.lineTo(70, 150);
ctx.stroke();
ctx.fill();

ctx.beginPath();
ctx.moveTo(70, 150);
ctx.ellipse(70, 150, 50, 110, 0, startAngle, endAngle);
ctx.lineTo(70, 150);
ctx.stroke();
ctx.fill();

ctx.beginPath();
ctx.moveTo(70, 150);
ctx.ellipse(70, 150, 50, 120, 0, startAngle, endAngle);
ctx.lineTo(70, 150);
ctx.stroke();
ctx.fill();

ctx.beginPath();
ctx.moveTo(70, 150);
ctx.ellipse(70, 150, 50, 130, 0, startAngle, endAngle);
ctx.lineTo(70, 150);
ctx.stroke();
ctx.fill();

ctx.beginPath();
ctx.moveTo(70, 150);
ctx.ellipse(70, 150, 50, 140, 0, startAngle, endAngle);
ctx.lineTo(70, 150);
ctx.stroke();
ctx.fill();

ctx.beginPath();
ctx.moveTo(300, 150);
ctx.ellipse(300, 150, 50, 50, 0, startAngle, endAngle);
ctx.lineTo(300, 150);
ctx.stroke();
ctx.fill();

ctx.beginPath();
ctx.moveTo(300, 150);
ctx.ellipse(300, 150, 60, 50, 0, startAngle, endAngle);
ctx.lineTo(300, 150);
ctx.stroke();
ctx.fill();

ctx.beginPath();
ctx.moveTo(300, 150);
ctx.ellipse(300, 150, 70, 50, 0, startAngle, endAngle);
ctx.lineTo(300, 150);
ctx.stroke();
ctx.fill();

ctx.beginPath();
ctx.moveTo(300, 150);
ctx.ellipse(300, 150, 80, 50, 0, startAngle, endAngle);
ctx.lineTo(300, 150);
ctx.stroke();
ctx.fill();

ctx.beginPath();
ctx.moveTo(300, 150);
ctx.ellipse(300, 150, 90, 50, 0, startAngle, endAngle);
ctx.lineTo(300, 150);
ctx.stroke();
ctx.fill();

ctx.beginPath();
ctx.moveTo(300, 150);
ctx.ellipse(300, 150, 100, 50, 0, startAngle, endAngle);
ctx.lineTo(300, 150);
ctx.stroke();
ctx.fill();

ctx.beginPath();
ctx.moveTo(300, 150);
ctx.ellipse(300, 150, 110, 50, 0, startAngle, endAngle);
ctx.lineTo(300, 150);
ctx.stroke();
ctx.fill();

ctx.beginPath();
ctx.moveTo(300, 150);
ctx.ellipse(300, 150, 120, 50, 0, startAngle, endAngle);
ctx.lineTo(300, 150);
ctx.stroke();
ctx.fill();

ctx.beginPath();
ctx.moveTo(300, 150);
ctx.ellipse(300, 150, 130, 50, 0, startAngle, endAngle);
ctx.lineTo(300, 150);
ctx.stroke();
ctx.fill();

ctx.beginPath();
ctx.moveTo(300, 150);
ctx.ellipse(300, 150, 140, 50, 0, startAngle, endAngle);
ctx.lineTo(300, 150);
ctx.stroke();
<html>
<body>

<canvas id="canvas" width="500" height="300">

</body>
</html>

Редактировать

Это работает так, как задумано OP
Формула взята из этого сообщения в блоге: Нахождение угла вокруг эллипса

var c = document.getElementById("canvas");
var ctx = c.getContext("2d");

var startAngle = Math.PI * 2 / 360 * 75;
var endAngle = Math.PI * 2 / 360 * 345;


ctx.fillStyle = "rgba(255, 255, 255, 0.125)";

function correctEllipse(ctx, cx, cy, w, h, r, sa, ea) {
  sa = Math.atan(w/h * Math.tan(sa))
  ea = Math.atan(w/h * Math.tan(ea))
  ctx.ellipse(cx, cy, w, h, r, sa, ea);
}


w = 50
h = 50

ctx.beginPath();
ctx.moveTo(70, 150);
correctEllipse(ctx, 70, 150, w, h, 0, startAngle, endAngle);
ctx.lineTo(70, 150);
ctx.stroke();
ctx.fill();

h = 60
ctx.beginPath();
ctx.moveTo(70, 150);
correctEllipse(ctx, 70, 150, w, h, 0, startAngle, endAngle);
ctx.lineTo(70, 150);
ctx.stroke();
ctx.fill();

h = 70
ctx.beginPath();
ctx.moveTo(70, 150);
correctEllipse(ctx, 70, 150, w, h, 0, startAngle, endAngle);
ctx.lineTo(70, 150);
ctx.stroke();
ctx.fill();

h = 80
ctx.beginPath();
ctx.moveTo(70, 150);
correctEllipse(ctx, 70, 150, w, h, 0, startAngle, endAngle);
ctx.lineTo(70, 150);
ctx.stroke();
ctx.fill();

h = 90
ctx.beginPath();
ctx.moveTo(70, 150);
correctEllipse(ctx, 70, 150, w, h, 0, startAngle, endAngle);
ctx.lineTo(70, 150);
ctx.stroke();
ctx.fill();

h = 100
ctx.beginPath();
ctx.moveTo(70, 150);
correctEllipse(ctx, 70, 150, w, h, 0, startAngle, endAngle);
ctx.lineTo(70, 150);
ctx.stroke();
ctx.fill();

h = 110
ctx.beginPath();
ctx.moveTo(70, 150);
correctEllipse(ctx, 70, 150, w, h, 0, startAngle, endAngle);
ctx.lineTo(70, 150);
ctx.stroke();
ctx.fill();

h = 120
ctx.beginPath();
ctx.moveTo(70, 150);
correctEllipse(ctx, 70, 150, w, h, 0, startAngle, endAngle);
ctx.lineTo(70, 150);
ctx.stroke();
ctx.fill();

h = 130
ctx.beginPath();
ctx.moveTo(70, 150);
correctEllipse(ctx, 70, 150, w, h, 0, startAngle, endAngle);
ctx.lineTo(70, 150);
ctx.stroke();
ctx.fill();

h = 140
ctx.beginPath();
ctx.moveTo(70, 150);
correctEllipse(ctx, 70, 150, w, h, 0, startAngle, endAngle);
ctx.lineTo(70, 150);
ctx.stroke();
ctx.fill();

h = 50
w = 50
ctx.beginPath();
ctx.moveTo(300, 150);
correctEllipse(ctx, 300, 150, w, h, 0, startAngle, endAngle);
ctx.lineTo(300, 150);
ctx.stroke();
ctx.fill();


w = 60
ctx.beginPath();
ctx.moveTo(300, 150);
correctEllipse(ctx, 300, 150, w, h, 0, startAngle, endAngle);
ctx.lineTo(300, 150);
ctx.stroke();
ctx.fill();

w = 70
ctx.beginPath();
ctx.moveTo(300, 150);
correctEllipse(ctx, 300, 150, w, h, 0, startAngle, endAngle);
ctx.lineTo(300, 150);
ctx.stroke();
ctx.fill();

w = 80
ctx.beginPath();
ctx.moveTo(300, 150);
correctEllipse(ctx, 300, 150, w, h, 0, startAngle, endAngle);
ctx.lineTo(300, 150);
ctx.stroke();
ctx.fill();

w = 90
ctx.beginPath();
ctx.moveTo(300, 150);
correctEllipse(ctx, 300, 150, w, h, 0, startAngle, endAngle);
ctx.lineTo(300, 150);
ctx.stroke();
ctx.fill();

w = 100
ctx.beginPath();
ctx.moveTo(300, 150);
correctEllipse(ctx, 300, 150, w, h, 0, startAngle, endAngle);
ctx.lineTo(300, 150);
ctx.stroke();
ctx.fill();

w = 110
ctx.beginPath();
ctx.moveTo(300, 150);
correctEllipse(ctx, 300, 150, w, h, 0, startAngle, endAngle);
ctx.lineTo(300, 150);
ctx.stroke();
ctx.fill();

w = 120
ctx.beginPath();
ctx.moveTo(300, 150);
correctEllipse(ctx, 300, 150, w, h, 0, startAngle, endAngle);
ctx.lineTo(300, 150);
ctx.stroke();
ctx.fill();

w = 130
ctx.beginPath();
ctx.moveTo(300, 150);
correctEllipse(ctx, 300, 150, w, h, 0, startAngle, endAngle);
ctx.lineTo(300, 150);
ctx.stroke();
ctx.fill();

w = 140
ctx.beginPath();
ctx.moveTo(300, 150);
correctEllipse(ctx, 300, 150, w, h, 0, startAngle, endAngle);
ctx.lineTo(300, 150);
ctx.stroke();
<html>
<body>

<canvas id="canvas" width="500" height="300">

</body>
</html>

Редактировать 2

Вам нужна фаза коррекции, потому что atan of tan правильна только в интервале
[-Math.PI / 2; Math.PI / 2]. За пределами этого интервала значение периодически сдвигается на k * Math.PI. См. Это QA по математике

// "use strict";

window.requestAnimFrame = (function(callback) {
  return (
    window.requestAnimationFrame ||
    window.webkitRequestAnimationFrame ||
    window.mozRequestAnimationFrame ||
    window.oRequestAnimationFrame ||
    window.msRequestAnimationFrame ||
    function(callback) {
      window.setTimeout(callback, 1000 / 60);
    }
  );
})();

var step = 0;

function animate() {
  requestAnimationFrame(animate);
  step++;

  if (step % 1 === 0) {
    ctx.clearRect(0, 0, 500, 300);
    step = 0;
    startAngle += 1;
    endAngle += 1;

    //   startAngle = ((startAngle + 180) % 360) - 180;
    //   endAngle = ((endAngle + 180) % 360) - 180;

    // endAngle += 1;

    // startAngle = startAngle % 360;
    // endAngle = endAngle % 360

    // if (endAngle < startAngle) {
    //   temp = endAngle
    //   endAngle = startAngle
    //   startAngle = temp
    // }

    // console.log(startAngle, endAngle)

    //startAngle = ((startAngle + 180) % 360) - 180;
    //endAngle = ((endAngle + 180) % 360) - 180;

    h = 50;
    w = 50;
    cx = 70;
    cy = 150;

    deltaW = 1;
    deltaH = 5;
    deltaCx = 3;
    deltaCy = 1;

    for (var i = 0; i < 15; i++) {
      currentW = w + deltaW * i;
      currentH = h + deltaH * i;
      currentCx = cx + deltaCx * i;
      currentCy = cy + deltaCy * i;
      angleEllipse(
        ctx,
        currentCx,
        currentCy,
        currentW,
        currentH,
        0,
        startAngle * Math.PI / 180,
        endAngle * Math.PI / 180
      );
    }

    h = 50;
    w = 50;
    cx = 300;
    cy = 150;

    deltaW = 5;
    deltaH = 1;
    deltaCx = 1;
    deltaCy = 3;
    for (var i = 0; i < 15; i++) {
      currentW = w + deltaW * i;
      currentH = h + deltaH * i;
      currentCx = cx + deltaCx * i;
      currentCy = cy + deltaCy * i;
      angleEllipse(
        ctx,
        currentCx,
        currentCy,
        currentW,
        currentH,
        0,
        startAngle * Math.PI / 180,
        endAngle * Math.PI / 180
      );
    }
  }
}

document.addEventListener("DOMContentLoaded", function() {
  animate();
});

var c = document.getElementById("canvas");
var ctx = c.getContext("2d");

var startAngle = 75;
var endAngle = 320;

ctx.fillStyle = "rgba(255, 255, 255, 0.125)";

function atantan(angle, w, h) {
  angle = (angle + Math.PI) % (2 * Math.PI) - Math.PI;
  var tempAngle = angle;
  angle = Math.atan(w / h * Math.tan(angle));
  if (tempAngle < -Math.PI / 2) {
    angle -= Math.PI;
  } else if (tempAngle > Math.PI / 2) {
    angle += Math.PI;
  }
  return angle;
}

function correctEllipse(ctx, cx, cy, w, h, r, sa, ea) {
  // sa should stay between negative Math.PI and positive Math.PI
  sa = atantan(sa, w, h);
  ea = atantan(ea, w, h);
  ctx.ellipse(cx, cy, w, h, r, sa, ea);
}

function angleEllipse(ctx, cx, cy, w, h, r, sa, ea) {
  ctx.beginPath();
  ctx.moveTo(cx, cy);
  correctEllipse(ctx, cx, cy, w, h, r, sa, ea);
  // ctx.ellipse(cx, cy, w, h, r, sa, ea);
  ctx.lineTo(cx, cy);
  ctx.stroke();
  ctx.fill();
}
<canvas id="canvas" width="500" height="300" />
0 голосов
/ 03 сентября 2018

StartAngle

void ctx.ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwise);

Начальная точка, измеренная от оси x, из которой она будет вытянута, выражена в радианах.

Углы измеряются в радианах - 1 градус = (Пи / 180)

Из документации https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/ellipse

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