首页 > 解决方案 > 沿 SVG 路径绘制

问题描述

我有一个使用贝塞尔曲线的 SVG 路径,例如:

m 776,2226 c 0,0 258.61385,-173.7593 289.34025,-325.8576 57.158,-282.9367 15.5277,-622.2212 50.8732,-933.13714 12.8345,-112.89946 104.2775,-278.6582 22.2568,-340.66923 -50.5144,-38.19103 -158.97817,99.97904 -158.97817,99.97904

在我的应用程序中,我想从初始点(x=776,y=2226)开始,慢慢绘制路径。例如,当用户按下按钮时,路径会显示更多。

我想使用 HTML 画布来做到这一点。

请注意,此路径不是封闭路径。

想过用Canvas的isPointInPath()功能,从初始点开始,逐个绘制像素。但是,如何找到路径中的所有点?

什么是替代方法?

标签: algorithmsvgcanvashtml5-canvas

解决方案


就像在 SVG 中一样,Canvas2D API 具有 dash-offset 和 stroke-dasharray 选项,分别通过lineDashOffsetproperty 和setLineDash方法。

然而,这个 API 仍然缺乏测量路径长度的正确方法(早期有关于扩展 Path2D API 的讨论,但还没有具体的内容)。
您可以自己计算该长度,但是路径越复杂,您出错的可能性就越大……所以实际上最简单的可能是使用 SVGGeometry 元素,它确实公开了一个.getTotalLength()方法。

const declaration = `M 10,30
       A 20,20 0,0,1 50,30
       A 20,20 0,0,1 90,30
       Q 90,60 50,90
       Q 10,60 10,30 z`;

const geom = document.createElementNS( "http://www.w3.org/2000/svg", "path" );
geom.setAttribute( "d", declaration );
const length = geom.getTotalLength();

const path = new Path2D( declaration );
const canvas = document.querySelector( "canvas" );
const ctx = canvas.getContext( "2d" );
// [ dash - hole ]
ctx.setLineDash( [ length, length ] );

const duration = 2000;
const start = performance.now();
requestAnimationFrame( draw );

ctx.fillStyle = "green";
ctx.strokeStyle = "red";

function draw(now) {
  ctx.clearRect( 0, 0, canvas.width, canvas.height );
  const delta = (now % duration) / duration;
  ctx.lineDashOffset = length - (length * delta);
  ctx.stroke( path );
  requestAnimationFrame( draw );
}
<canvas width="100" height="100"></canvas>

对于那些为了标题而来到这里并想要沿着路径移动形状的人,我们可以继续使用我们的 SVGGeometryElement 及其getPointAtLength方法:

const declaration = `M 10,30
       A 20,20 0,0,1 50,30
       A 20,20 0,0,1 90,30
       Q 90,60 50,90
       Q 10,60 10,30 z`;

const geom = document.createElementNS( "http://www.w3.org/2000/svg", "path" );
geom.setAttribute( "d", declaration );
const length = geom.getTotalLength();

const path = new Path2D( declaration );
const canvas = document.querySelector( "canvas" );
const ctx = canvas.getContext( "2d" );

const duration = 2000;
const start = performance.now();
requestAnimationFrame( draw );

ctx.fillStyle = "green";
ctx.strokeStyle = "red";

function draw(now) {
  ctx.clearRect( 0, 0, canvas.width, canvas.height );
  const delta = (now % duration) / duration;
  const point = geom.getPointAtLength( length * delta );
  ctx.fillRect( point.x - 10, point.y -10, 20, 20 );
  ctx.stroke( path );
  requestAnimationFrame( draw );
}
<canvas width="100" height="100"></canvas>

现在,在您的情况下,我想您仍然需要做一些工作才能正确缩放返回的值,就像您在画布上绘制时可能缩放路径一样,但我将把它作为练习(不太复杂) .


推荐阅读