当前位置: 首页 > Web前端 > HTML5

如何在Canvas中实现自定义路径动画

时间:2023-04-05 18:40:12 HTML5

最近一个项目中,作者需要提出一个新的需求:在canvas中实现自定义路径动画。这里所谓的自定义路径不仅包括一条直线,还包括多条直线的组合,甚至包括贝塞尔曲线。因此,这个动画可能看起来像这样:那么如何在canvas中实现呢?动画效果怎么样?其实很简单,svg非常擅长处理路径,所以要在canvas中实现自定义路径动画,就需要svg的强大功能。在创建Path来制作动画之前,首先要获取动画的路径。为此,我们可以直接使用svg的路径定义规则。比如我们定义了一个比较复杂的路径(大家可以自己试试,这里长啥样?如图所示),那么我们需要将定义好的路径导入到一个新生成的路径元素中(我们只是使用了svgapi,所以我们不需要将其插入页面)constpath='M0,0C8,33.9086125.90861,1648,16C70.09139,1688,33.9086188,56C88,78.09139105.90861,92128,92C150.09139,92160,72160,56C160,428242414896,4096,4096,56C9662105.90861,92128,92C154,93C154,93168,78168,78168,56C168,56C168,33.90861185.90861,1608616C16C16C16C16C16C16C16C16C16C16C16C16208616C16CAN,56,78.09139399139139139139139139,913913913913913913913913913913913913913913913991399139208,96L48,96C25.90861,968,78.091398,56Z';constpathElement=document.createElementNS('http://www.w3.org/2000/svg',"小路”);路径元素。setAttributeNS(null,'d',路径);getTotalLength和getPointAtLengthSVGPathElement提供的两个API非常重要。可以说是实现路径动画最核心的地方(svg中自定义路径动画的实现一般都是通过这两个api来解决)具体请点击:SVGPathElementMDNgetTotalLength方法可以获取SVGPathElement的总长度getPointAtLength方法,传入一个长度x,返回长度为x的终点距离SVGPathElement起点的坐标。使用这两个API,可以通过循环方式不断更新画布中绘制的图形坐标来实现路径动画:constlength=pathElement.getTotalLength();const持续时间=1000;//总动画持续时间constinterval=length/duration;constcanvas=document.querySelector('canvas');constcontext=canvas.getContext('2d');lettime=0,step=0;consttimer=setInterval(function(){if(time<=duration){constx=parseInt(pathElement.getPointAtLength(step).x);consty=parseInt(pathElement.getPointAtLength(step).y);move(x,y);//更新canvas绘制图形的坐标step++;}else{clearInterval(timer)}},interval);functionmove(x,y){context.clearRect(0,0,canvas.width,canvas.height);context.beginPath();context.arc(x,y,25,0,Math.PI*2,true);context.fillStyle='#f0f';context.fill();context.closePath();}最后我们封装它实现一个简单的函数在canvas中实现自定义动画:functioncustomizePath(path,func){constpathElement=document.createElementNS('http://www.w3.org/2000/svg',"路径");路径元素。设置属性eNS(空,'d',路径);constlength=pathElement.getTotalLength();const持续时间=1000;const间隔=长度/持续时间;让时间=0,步骤=0;consttimer=setInterval(function(){if(time<=duration){constx=parseInt(pathElement.getPointAtLength(step).x);consty=parseInt(pathElement.getPointAtLength(step).y);func(x,y);step++;}else{clearInterval(timer)}},interval);}constpath='M0,0C8,33.9086125.90861,1648,16C70.09139,1688,33.9086188,56C88,78.09139105.90861,92128,92C150.09139,92160,72160,56C160,40148,24128,24C108,2496,4096,56C96,72105.90861,92128,92C154,93168,78168,56C168,33.90861185.90861,16208,16C230.09139,16248,33.90861248,56C248,78.09139230.09139,96208,96L48,96Z25.90861,861,8868canvas=document.querySelector('canvas');constcontext=canvas.getContext('2d');functionmove(x,y){context.clearRect(0,0,canvas.width,canvas.height);context.beginPath();context.arc(x,y,25,0,Math.PI*2,true);context.fillStyle='#f0f';context.fill();context.closePath();}customizePath(path,move);实现思路大致如上,但这并不是最终的结果当我们决定在canvas上制作自定义路径动画时,我们不仅要考虑如何实现,还要考虑性能优化。比如这个实现思路,我们能不能减少不必要的渲染次数?如何控制帧率达到最佳?等等,虽然不在本文讨论范围之内,但应该值得我们深思。