在画布中使用SVG路径移动对象

如果要在画布中(不仅是)对对象进行动画处理,则需要沿某个所需的路径(甚至可以随机或顺序选择的多个路径)移动它,那么可以使用svg路径来完成。 让我们从沿路径开始一个简单但绿色的正方形开始。

图片


为此,我们将使用一条或多条路径制作或借用svg。

使用document.createElementNS函数创建一个元素。 MDN告诉我们,该方法在所有现代浏览器中都具有基本支持。 然后将路径添加到创建的元素。

let path = document.createElementNS("http://www.w3.org/2000/svg", "path"); path.setAttribute('d', 'M148.185,118.975c0,0-92.592,39.507-80.247,79.013,s79.012,143.21,129.629,124.691s64.198-113.856,120.988-100.755s118.518,30.384,116.049,109.397s-82.715,118.519-97.53,201.235,s-92.593,139.505,0,159.259'); 

这里,在属性中,引入了一些svg文件的第一个引人注目的路径,即复制粘贴方法。 当然,这不是唯一的方法,也不是最方便的方法,但足够清晰,可以在第一个示例中使用。

现在在循环中,我们将获取航点的坐标并将其分配给我们的对象。 两个SVGGeometryElement方法足以满足此要求

 path.getTotalLength() 

返回总路径长度的计算值,并

  path.getPointAtLength(index) 

它接受一个float参数,并返回一个具有我们感兴趣的x和y坐标的SVGPoint对象。 如果参数值小于零或大于路径长度,则分别返回第一个或最后一个点作为结果。

更新框架时,我们得到了点并使用其坐标进行移动。

Codepen上的完整示例代码

但是,您可以使用更有趣的选项沿多个路径的坐标移动对象,例如:

图片


同样,采用带有多个路径的svg文件。 在示例中使用的是在Inscape编辑器中完成的。 现在,您需要获取这些路径,这可以通过解析对象来实现,或者,如果svg是作为文本文件接收的,则下一个使用正则表达式的函数可以将其作为字符串获取。

 extractPathsfromSvg: function(svg){ let results = svg.match(/<path\b([\s\S]*?)><\/path>/g); let paths = []; let len = results.length; for(let i = 0; i < len; i++){ let str = results[i]; let data = str.match(/[^\w]d="([\s\S]*?)"/); paths.push(data[1]); } return paths; } 

创建路径数组后,仍然需要依次提取它们并以与正方形移动的唯一路径相同的方式来处理它们。 得到有趣的效果。
请参见下面的示例的完整代码。

要在沿路径的坐标移动对象时添加更多控制,可以使用双胞胎。 对于测试用例,我采用了第一个引起我注意的GreenSock库,但事实证明它可能是其他任何库。

在第一种情况下,当正方形沿着唯一的路径移动时,创建一个中间对象助手,并将其传递以创建补间。

 var helper = {progress: 0} helper.update = function(value){ point = path.getPointAtLength(totalLength * helper.progress); x = point.x; y = point.y; ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.drawImage(img, x, y ); } var tw = new TweenLite.to(helper, 5, {progress: 0, }); tw.eventCallback("onUpdate", helper.update); 

您可以在补间笔的第一个示例中,通过勾选“使用补间”来查看使用补间的正方形沿路径的移动。

当沿着多条路径移动时,我们按以下步骤进行。 和以前一样,使用progress属性创建一个辅助对象。 我们计算所有路径的总长度,并将其分配给handler.progress。 让我们创建一个遍历的变量,其中将总结已经涵盖的路径。

要在当前路径上获得一个点,请从补间中更改的helper.progress减去,遍历已走过的路径。 我们照常使用点的坐标。

 var traversed = 0; helper.progress = totalLenghtAllPath; helper.update = function() { var localPoint = helper.progress - traversed; if(localPoint > curPath.getTotalLength()){ traversed += curPath.getTotalLength(); curPath = paths[next()]; if(curPath){ return false; } localPoint = helper.progress - traversed; } /*       */ } var tw = TweenLite.to( helper, 25, {progress: totalLenghtAllPath, ease: Power2.easeOut } ); tw.eventCallback("onUpdate", helper.update); 

代码经过简化,完整代码在这里:

Source: https://habr.com/ru/post/zh-CN432114/


All Articles