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了, 要他把这个东西给你, 你不就轻轻松松做出一个自定义动画了。设计师肯定会夸你🐂

相关文章
|
前端开发
canvas生成自定义大小图片
canvas生成自定义大小图片
|
3月前
|
XML 前端开发 JavaScript
如何使用 SVG 和 Canvas 来创建动画?
【10月更文挑战第24天】使用 SVG 和 Canvas 创建动画都有各自的特点和优势,SVG 更适合基于 XML 和 CSS 的简单动画,而 Canvas 则更适合通过 JavaScript 实现复杂的、高性能的动画效果。在实际应用中,可以根据具体的需求和场景选择合适的技术来创建动画。
95 1
|
7月前
|
前端开发
css动画 —— 自定义不规则的动画路径 offset-path (含不规则的动画路径参数获取方法)
css动画 —— 自定义不规则的动画路径 offset-path (含不规则的动画路径参数获取方法)
148 1
|
9月前
|
Web App开发 前端开发 iOS开发
CSS3 转换,深入理解Flutter动画原理,前端基础图形
CSS3 转换,深入理解Flutter动画原理,前端基础图形
|
9月前
|
前端开发
自定义View绘制基础之Canvas
自定义View绘制基础之Canvas
78 0
|
前端开发 JavaScript
优美的Reactl列表动画:Styled-Components动画实践
优美的Reactl列表动画:Styled-Components动画实践
|
存储 容器
flutter系列之:做一个修改组件属性的动画
什么是动画呢?动画实际上就是不同的图片连续起来形成的。flutter为我们提供了一个AnimationController来对动画进行详尽的控制,不过直接是用AnimationController是比较复杂的,如果只是对一个widget的属性进行修改,可以做成动画吗? 答案是肯定的,一起来看看吧。
|
Dart 开发者
【Flutter】Animation 动画 ( AnimatedBuilder 动画使用流程 | 创建动画控制器 | 创建动画 | 创建动画作用的组件 | 关联动画与组件 | 动画执行 )(三)
【Flutter】Animation 动画 ( AnimatedBuilder 动画使用流程 | 创建动画控制器 | 创建动画 | 创建动画作用的组件 | 关联动画与组件 | 动画执行 )(三)
198 0
【Flutter】Animation 动画 ( AnimatedBuilder 动画使用流程 | 创建动画控制器 | 创建动画 | 创建动画作用的组件 | 关联动画与组件 | 动画执行 )(三)
|
Dart API 开发者
【Flutter】Hero 动画 ( Hero 动画使用流程 | 创建 Hero 动画核心组件 | 创建源页面 | 创建目的页面 | 页面跳转 )
【Flutter】Hero 动画 ( Hero 动画使用流程 | 创建 Hero 动画核心组件 | 创建源页面 | 创建目的页面 | 页面跳转 )
251 0
【Flutter】Hero 动画 ( Hero 动画使用流程 | 创建 Hero 动画核心组件 | 创建源页面 | 创建目的页面 | 页面跳转 )
【Flutter】Animation 动画 ( AnimatedBuilder 动画使用流程 | 创建动画控制器 | 创建动画 | 创建动画作用的组件 | 关联动画与组件 | 动画执行 )(一)
【Flutter】Animation 动画 ( AnimatedBuilder 动画使用流程 | 创建动画控制器 | 创建动画 | 创建动画作用的组件 | 关联动画与组件 | 动画执行 )(一)
180 0