#javascript #svg #canvas #html5-canvas
Вопрос:
У меня есть следующий элемент SVG:
lt;svg viewBox="0 0 1000 1000" xmlns="http://www.w3.org/2000/svg" version="1.1" aria-label="The Moon" role="img" unselectable="on" tabindex="-1" draggable="false" class="absolute -z-10 top-full right-full" data-phase="0.9033397192448547" data-age="26.676153687326483" gt; lt;path d="m500,0 a10,10 0 1,1 0,1000 a10,10 0 1,1 0,-1000" fill="rgba(255, 255, 255)"gt;lt;/pathgt; lt;path d="m500,0 a10,10 0 1,1 0,1000 a10,10 0 1,1 0,-1000" fill="rgba(31, 41, 55, 0.60)"gt;lt;/pathgt; lt;path d="m500,0 a 6.133588769794187,10 0 1, 0 0,1000 a10,10 0 1, 1 0,-1000" fill="#fff"gt;lt;/pathgt; lt;/svggt;
Однако мне было интересно … можно нарисовать эти пути, используя:
ctx.beginPath() const p = new Path2D( `m${radius},0 a 6.133588769794187,10 0 1, 0 0,${radius * 2} a10,10 0 1, 1 0,${radius * -2}` ) p.moveTo(x - radius / 2, y - radius / 2) ctx.stroke(p) ctx.fill(p) ctx.closePath()
Однако, похоже,он не хочет рисовать путь в позиции [x, y], которую я указываю, он просто помещает его в верхний левый угол моего холста …
Кажется, я не могу указать, как разместить 2D-путь в определенной координате x и y…
Я тоже пробовал это, но с не менее печальными результатами:
ctx.strokeStyle = '#fff' ctx.lineWidth = 1 ctx.fillStyle = '#fff' const p = new Path2D() p.moveTo(x - radius / 2, y - radius / 2) p.addPath( new Path2D( `m${radius},0 a 6.133588769794187,10 0 1, 0 0,${radius * 2} a10,10 0 1, 1 0,${radius * -2}` ) ) ctx.stroke(p) ctx.fill(p) ctx.closePath()
Любой путеводный свет был бы потрясающим!
Комментарии:
1. Вы пробовали
ctx.moveTo(x, y);
раньшеstroke
(вместоp.moveTo()
)?
Ответ №1:
Относительные команды вашего объявления пути не будут работать так, как вы ожидали здесь.
Они будут проанализированы при создании внутреннего пути 2d, у которого еще нет конечной точки, и, таким образом, все они будут относительно начальной 0,0
точки.
Как только этот внутренний путь 2d будет создан, тот факт, что объявление использовало относительные методы, будет потерян, все эти точки внутренне преобразуются в абсолютные координаты. Таким образом, последняя точка конечного пути 2D, по которой вы будете звонить addPath(path)
, не будет иметь значения.
Чтобы делать то, что вы хотите, у вас есть несколько решений:
- Вы могли бы добавить a
Mx,y
к своему объявлению пути:
const canvas = document.querySelector("canvas"); const ctx = canvas.getContext("2d"); ctx.strokeStyle = '#fff' ctx.lineWidth = 1 ctx.fillStyle = '#fff' const radius = 50; const x = 150; const y = 70; const p = new Path2D(`M${x - radius / 2},${y - radius / 2}m${radius},0 a 6.133588769794187,10 0 1, 0 0,${radius * 2} a10,10 0 1, 1 0,${radius * -2}`); ctx.stroke(p) ctx.fill(p)
body { background: #333; }
lt;canvasgt;lt;/canvasgt;
Хотя, идя этим путем, вы могли бы даже удалить следующее m
и объединить его в M
расчет:
const canvas = document.querySelector("canvas"); const ctx = canvas.getContext("2d"); ctx.strokeStyle = '#fff' ctx.lineWidth = 1 ctx.fillStyle = '#fff' const radius = 50; const x = 150; const y = 70; const p = new Path2D(`M${x - radius / 2 radius},${y - radius / 2}a 6.133588769794187,10 0 1, 0 0,${radius * 2} a10,10 0 1, 1 0,${radius * -2}`); ctx.stroke(p) ctx.fill(p)
body { background: #333; }
lt;canvasgt;lt;/canvasgt;
Или вы можете использовать матрицу преобразования контекста (CTM) для перемещения туда, где на самом деле нарисован путь:
const canvas = document.querySelector("canvas"); const ctx = canvas.getContext("2d"); ctx.strokeStyle = '#fff' ctx.lineWidth = 1 ctx.fillStyle = '#fff' const radius = 50; const x = 150; const y = 70; const p = new Path2D(`m${radius},0 a 6.133588769794187,10 0 1, 0 0,${radius * 2} a10,10 0 1, 1 0,${radius * -2}`); // set x, y through CTM ctx.translate(x - radius / 2, y - radius / 2); ctx.stroke(p) ctx.fill(p) // reset CTM to defaults ctx.setTransform(1, 0, 0, 1, 0, 0);
body { background: #333; }
lt;canvasgt;lt;/canvasgt;
Или вы можете использовать matrix
параметр Path2D.addPath(path, matrix)
для прямого перевода пути:
const canvas = document.querySelector("canvas"); const ctx = canvas.getContext("2d"); ctx.strokeStyle = '#fff' ctx.lineWidth = 1 ctx.fillStyle = '#fff' const radius = 50; const x = 150; const y = 70; const p1 = new Path2D(`m${radius},0 a 6.133588769794187,10 0 1, 0 0,${radius * 2} a10,10 0 1, 1 0,${radius * -2}`); const p = new Path2D(); const matrix = { e: x - radius / 2 , f: y - radius / 2 }; p.addPath(p1, matrix); ctx.stroke(p); ctx.fill(p);
body { background: #333; }
lt;canvasgt;lt;/canvasgt;
У каждого из этих решений есть свои преимущества, первые из которых, возможно, легче читаются, одно из них CTM лучше всего подходит на случай, если вы хотите менять положение вашего Path2D в каждом кадре, а последнее лучше всего, если вам нужно заполнить Path2D узорами или градиентами (на которые также повлияет CTM).