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

简介: 前言大家好!!又到周末了,最近项目忙完了,有时间写文章了。之前有粉丝问我, fly哥怎么实现自定义路径动画, 当时给他说的就是路径无非不就是直线 或者曲线。也就这两种, 直线的话 可以用直线方程, 曲线的话稍微复杂点 ,需要用贝塞尔曲线去做lerp。也就是动画的每一幁的算出路径的对应的坐标就可以了。但是这套方案学习成本太高了, 有没有一种更加简单的方式呢?本篇文章大概花费你5分钟, 你可以学到什么呢svg 的 两个无敌api 后面介绍封装了一个自定义路径动画函数创建Path制作动画前,先要拿到动画的路径,对此我们可以直接使用svg的path定义规则,比如我们定义了一条较为复杂的路径

前言



大家好!!又到周末了,最近项目忙完了,有时间写文章了。之前有粉丝问我, fly哥怎么实现自定义路径动画, 当时给他说的就是路径无非不就是直线 或者曲线。也就这两种, 直线的话 可以用直线方程, 曲线的话稍微复杂点 ,需要用贝塞尔曲线去做lerp。也就是动画的每一幁的算出路径的对应的坐标就可以了。但是这套方案学习成本太高了, 有没有一种更加简单的方式呢?本篇文章大概花费你5分钟, 你可以学到什么呢


  1. svg 的 两个无敌api 后面介绍


  1. 封装了一个自定义路径动画函数


创建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>


我们先看下路径:


image.png

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


  1. 「getTotalLength」


  1. 「getPointAtLength」


getTotalLength


我们先看下第一个的官方解释:


**SVGPathElement.getTotalLength()** 该方法返回用户代理对路径总长度(以用户单位为单位)的计算值。


顾名思义就是会计算出,你设置svg Path 的总路径 总长度。有了总长度, 可以算出在某个长度的 x 和 y坐标呢??


就是下面这个api

getPointAtLength


**SVGGeometryElement.getPointAtLength()** 方法沿路径返回给定距离的点。


我总觉得官方写的不够直白, 不过看 API 应该就能明白求出在某个长度的点。有个这两个其实动画就出来了


我给大家画一个图 去模拟下:


image.png


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 。实现了循环往复。看下效果:

image.png


ani


大家自己想象一下。然后你就可以做任意路径的动画了,如果设计 要你做一个什么路径动画。这时候你可以小装一波, 直接指导他。


第一步:建立工作路径


image.png


image-20211205003031825


第二步:路径导出


image.png


image-20211205003109787


第三步:用AI 打开这个 路径

image.png


image-20211205003200981


然后就可以导出 svg path了, 要他把这个东西给你, 你不就轻轻松松做出一个自定义动画了。设计师肯定会夸你🐂

相关文章
|
10月前
|
前端开发
canvas生成自定义大小图片
canvas生成自定义大小图片
|
9月前
|
XML 编解码 JavaScript
封装svg图标组件
封装svg图标组件
169 0
|
2月前
|
前端开发
自定义View绘制基础之Canvas
自定义View绘制基础之Canvas
49 0
|
2月前
|
前端开发
|
10月前
|
前端开发
css改变滚动条的颜色-横向滚动demo效果示例(整理)
css改变滚动条的颜色-横向滚动demo效果示例(整理)
|
Web App开发 移动开发 前端开发
H5:画布Canvas基础知识讲解(一)之canvas基础、2D context API、路径
H5:画布Canvas基础知识讲解(一)之canvas基础、2D context API、路径
|
Dart 开发者
【Flutter】Animation 动画 ( AnimatedBuilder 动画使用流程 | 创建动画控制器 | 创建动画 | 创建动画作用的组件 | 关联动画与组件 | 动画执行 )(三)
【Flutter】Animation 动画 ( AnimatedBuilder 动画使用流程 | 创建动画控制器 | 创建动画 | 创建动画作用的组件 | 关联动画与组件 | 动画执行 )(三)
156 0
【Flutter】Animation 动画 ( AnimatedBuilder 动画使用流程 | 创建动画控制器 | 创建动画 | 创建动画作用的组件 | 关联动画与组件 | 动画执行 )(三)
|
Dart API 开发者
【Flutter】Hero 动画 ( Hero 动画使用流程 | 创建 Hero 动画核心组件 | 创建源页面 | 创建目的页面 | 页面跳转 )
【Flutter】Hero 动画 ( Hero 动画使用流程 | 创建 Hero 动画核心组件 | 创建源页面 | 创建目的页面 | 页面跳转 )
194 0
【Flutter】Hero 动画 ( Hero 动画使用流程 | 创建 Hero 动画核心组件 | 创建源页面 | 创建目的页面 | 页面跳转 )
|
前端开发 JavaScript
《JS原理、方法与实践》- canvas作图(三)- 修改颜色和样式
《JS原理、方法与实践》- canvas作图(三)- 修改颜色和样式
353 0
|
前端开发 JavaScript
《JS原理、方法与实践》- canvas作图(六)- 坐标操作
《JS原理、方法与实践》- canvas作图(六)- 坐标操作
97 0