Анимация рисования дуги для линий на холсте - PullRequest
0 голосов
/ 09 февраля 2020

Я пытаюсь реализовать анимацию рисования линии дуги на холсте. Например, для прямой линии анимация будет выглядеть следующим образом:

c = canvas.getContext("2d");

width = window.innerWidth;
height = window.innerHeight;
complete = false
var percent = 1

function drawEdge(x1, y1, x2, y2, color){
 c.beginPath();
 c.lineWidth = 10;
 c.strokeStyle = color;
 c.moveTo(x1, y1);
 c.lineTo(x2, y2);
 c.stroke();
 c.closePath();
}

function getPosition(x1, y1, x2, y2, percentageBetweenPoints){
 let xPosition = x1 + (x2 - x1) * (percentageBetweenPoints / 100);
 let yPosition = y1 + (y2 - y1) * (percentageBetweenPoints / 100);

 const position = {
     x: xPosition,
     y: yPosition,
 }
 return position
}

function drawLine(){
 if (!complete){
     requestAnimationFrame(drawLine);
 }

 if (percent >= 100){
     complete = true;
     percent = 100;
 } else{
     percent = percent + 1;
 }

 position = getPosition(300,300,1000,300,percent);
 c.clearRect(0, 0 , width, height);
 drawEdge(300,300,position.x,position.y, "black");

}

drawLine()

. Это создает анимацию линии, проводимой по экрану. Тем не менее, я испытываю затруднения, делая то же самое для линий arcTo. Есть ли способ реализовать это?

Ответы [ 2 ]

1 голос
/ 10 февраля 2020

Вы ищете что-то подобное?

let ctx = canvas.getContext('2d');
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.font = 'bold 18px Arial';

requestAnimationFrame(draw);

function draw(t) {
  t = t % 5e3 / 5e3;
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ctx.beginPath();
  ctx.arc(canvas.width/2, canvas.height/2, 50, 0, t * 2 * Math.PI);
  ctx.stroke();
  ctx.fillText((t*100).toFixed(0), canvas.width/2, canvas.height/2);
  requestAnimationFrame(draw);
}
<canvas id=canvas></canvas>
0 голосов
/ 10 февраля 2020

Взламывать или не взламывать?

Есть два способа сделать это

  1. Рассчитать начало, конец и длину каждого отрезка, начало , конечный угол, направление (CW или CCW) и центр каждого сегмента ar c. В основном, повторяя все математические операции и логику c (около 50 строк кода), что делает arcTo такой полезной функцией рендеринга.

    Подробную информацию о том, как подойти к полному решению, можно узнать из html5 холст треугольник с закругленными углами

  2. Используйте ctx.lineDash с длинным да sh и длинным пробелом. Переместите da sh с течением времени с помощью ctx.lineDashOffset, чтобы создать линию, растущую в длину (см. Демонстрацию) Значение смещения da sh меняется на обратное, начиная с максимальной длины и заканчивая нулем.

    ПРИМЕЧАНИЕ Существует одна проблема с этим методом. Вы не знаете длину линии, и, следовательно, вы не знаете, сколько времени потребуется для завершения линии. Вы можете сделать оценку. Чтобы узнать длину линии, вы должны сделать все расчеты (ну, там около)

Hack

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

Не так много, чтобы сказать об этом, он оживляет путь, созданный ctx.arcTo Дополнительным преимуществом является то, что он будет анимировать любой путь, отображаемый с использованием ctx.stroke

requestAnimationFrame(mainLoop);
// Line is defined in unit space. 
// Origin is at center of canvas, -1,-1 top left, 1, 1 bottom right
// Unit box is square and will be scaled to fit the canvas size.
// Note I did not use ctx.setTransform to better highlight what is scaled and what is not.
const ctx = canvas.getContext("2d");
var w, h, w2, h2;          // canvas size and half size
var linePos;               // current dash offset
var scale;                 // canvas scale
const LINE_WIDTH = 0.05;      // in units
const LINE_STYLE = "#000"; // black
const LINE_SPEED = 1;      // in units per second
const MAX_LINE_LENGTH = 9; // in units approx
const RADIUS = 0.08;       //Arc radius in units
const SHAPE = [[0.4, 0.2], [0.8, 0.2], [0.5, 0.5], [0.95, 0.95], [0.0, 0.5], [-0.95, 0.95], [-0.5, 0.5], [-0.8, 0.2], [-0.2, 0.2],  [-0.2, -0.2], [-0.8, -0.2], [-0.5, -0.5], [-0.95, -0.95], [0.0, -0.5], [0.95,-0.95], [0.5, -0.5], [0.8, -0.2], [0.2, -0.2], [0.2, 0.2], [0.6, 0.2], [0.8, 0.2]];

function sizeCanvas() {
    w2 = (w = canvas.width = innerWidth) / 2;
    h2 = (h = canvas.height = innerHeight) / 2;
    scale = Math.min(w2, h2);
    resetLine();
}

function addToPath(shape) {
   var p1, p2;
   for (p2 of shape) {
       !p2.length ? 
           ctx.closePath() :
           (p1 ? ctx.arcTo(p1[0] * scale + w2, p1[1] * scale + h2, p2[0] * scale + w2, p2[1] * scale + h2, RADIUS * scale) : 
                ctx.lineTo(p2[0] * scale + w2, p2[1] * scale + h2)
            );
       p1 = p2;
   }
}

function resetLine() {
    ctx.setLineDash([MAX_LINE_LENGTH * scale, MAX_LINE_LENGTH * scale]);
    linePos = MAX_LINE_LENGTH * scale;
    ctx.lineWidth = LINE_WIDTH  * scale;
    ctx.lineJoin = ctx.lineCap = "round";
}

function mainLoop() {
    if (w !== innerWidth || h !== innerHeight) { sizeCanvas() }
    else { ctx.clearRect(0, 0, w, h) }
    ctx.beginPath();
    addToPath(SHAPE);  
    ctx.lineDashOffset = (linePos -= LINE_SPEED * scale * (1 / 60));
    ctx.stroke();
    if (linePos <= 0) { resetLine() }
    requestAnimationFrame(mainLoop);
}
    
    
body {
   padding: 0px,
   margin: 0px;
}
canvas {
   position: absolute;
   top: 0px;
   left: 0px;
}
<canvas id="canvas"></canvas>
...