Взламывать или не взламывать?
Есть два способа сделать это
Рассчитать начало, конец и длину каждого отрезка, начало , конечный угол, направление (CW или CCW) и центр каждого сегмента ar c. В основном, повторяя все математические операции и логику c (около 50 строк кода), что делает arcTo
такой полезной функцией рендеринга.
Подробную информацию о том, как подойти к полному решению, можно узнать из html5 холст треугольник с закругленными углами
Используйте 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>