前言
大家好!!又到周末了,最近项目忙完了,有时间写文章了。之前有粉丝问我, fly哥怎么实现自定义路径动画, 当时给他说的就是路径无非不就是直线 或者曲线。也就这两种, 直线的话 可以用直线方程, 曲线的话稍微复杂点 ,需要用贝塞尔曲线去做lerp。也就是动画的每一幁的算出路径的对应的坐标就可以了。但是这套方案学习成本太高了, 有没有一种更加简单的方式呢?本篇文章大概花费你5分钟, 你可以学到什么呢
- svg 的 两个无敌api 后面介绍
- 封装了一个自定义路径动画函数
创建Path
制作动画前,先要拿到动画的路径,对此我们可以直接使用svg的path定义规则,比如我们定义了一条较为复杂的路径(它到底长什么样大家可以自己试试,这里就不展示了),然后,我们需要将定义好的路径导入进一个新生成的path元素中(我们只是借助svg的api,因此并不需要将其插到页面内)但是为了看效果, 我还是在页面放了 svg 的图形, 毕竟直观点。
代码如下:
<canvas id="canvas" width="800" height="600" tabindex="0"></canvas> <svg width="100%" height="100%" viewBox="0 0 400 400" xmlns="http://www.w3.org/2000/svg"> <path d='M0,0 C8,33.90861 25.90861,16 48,16 C70.09139,16 88,33.90861 88,56 C88,78.09139 105.90861,92 128,92 C150.09139,92 160,72 160,56 C160,40 148,24 128,24 C108,24 96,40 96,56 C96,72 105.90861,92 128,92 C154,93 168,78 168,56 C168,33.90861 185.90861,16 208,16 C230.09139,16 248,33.90861 248,56 C248,78.09139 230.09139,96 208,96 L48,96 C25.90861,96 8,78.09139 8,56 Z' fill="orange" stroke="black" stroke-width="3" /> </svg>
我们先看下路径:
path
左边是canvas, 右边是svg 。等下我们注意观察小球的运动!!!!
创建svg路径
这就是创建dom节点, 然后往svg 加 path 属性。然后继续就可以了。
const path = 'M0,0 C8,33.90861 25.90861,16 48,16 C70.09139,16 88,33.90861 88,56 C88,78.09139 105.90861,92 128,92 C150.09139,92 160,72 160,56 C160,40 148,24 128,24 C108,24 96,40 96,56 C96,72 105.90861,92 128,92 C154,93 168,78 168,56 C168,33.90861 185.90861,16 208,16 C230.09139,16 248,33.90861 248,56 C248,78.09139 230.09139,96 208,96 L48,96 C25.90861,96 8,78.09139 8,56 Z'; const pathElement = document.createElementNS('http://www.w3.org/2000/svg',"path"); pathElement.setAttributeNS(null, 'd', path); document.body.appendChild(pathElement)
然后呢我们就有了 这个 svg 节点, 有了节点就可以做一些操作了, 这里给大家揭秘下这两个api
- 「getTotalLength」
- 「getPointAtLength」
getTotalLength
我们先看下第一个的官方解释:
**SVGPathElement.getTotalLength()**
该方法返回用户代理对路径总长度(以用户单位为单位)的计算值。
顾名思义就是会计算出,你设置svg Path 的总路径 总长度。有了总长度, 可以算出在某个长度的 x 和 y坐标呢??
就是下面这个api
getPointAtLength
**SVGGeometryElement.getPointAtLength()**
方法沿路径返回给定距离的点。
我总觉得官方写的不够直白, 不过看 API 应该就能明白求出在某个长度的点。有个这两个其实动画就出来了
我给大家画一个图 去模拟下:
image-20211205002020987
你可以从一开始的地方,可以获得距离 起点任意长度的 点的坐标。这样从动画的角度,你就可以在单位时间内不停地改变图形的位置,从而达成连续的效果,其实也就是动画了。直接上代码
const length = pathElement.getTotalLength(); const duration = 1000; // 动画总时长 const interval = length / duration; const canvas = document.getElementById('canvas'); const context = canvas.getContext('2d'); // 定义了步数 let step = 0; function move(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(); } // animate() function animate() { if(step > length) { step = 0; } const x = parseInt(pathElement.getPointAtLength(step).x); const y = parseInt(pathElement.getPointAtLength(step).y); move(x,y) step++ requestAnimationFrame(animate) }
这里的在 requestAnimation 中不断地 去增加步数, 然后大于总长度 就让长度变为0 。实现了循环往复。看下效果:
ani
大家自己想象一下。然后你就可以做任意路径的动画了,如果设计 要你做一个什么路径动画。这时候你可以小装一波, 直接指导他。
第一步:建立工作路径
image-20211205003031825
第二步:路径导出
image-20211205003109787
第三步:用AI 打开这个 路径
image-20211205003200981
然后就可以导出 svg path了, 要他把这个东西给你, 你不就轻轻松松做出一个自定义动画了。设计师肯定会夸你🐂