资讯专栏INFORMATION COLUMN

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

Cympros / 2960人阅读

摘要:在最近的项目中笔者需要做一个新需求在中实现自定义的路径动画。当我们决定要在制作自定义路径动画时,我们不仅要考虑如何实现,更要考虑性能优化,比如在这个实现思路中,我们是否可以减少不必要的渲染次数帧率如何控制达到最优等等。

在最近的项目中笔者需要做一个新需求:在canvas中实现自定义的路径动画。这里所谓的自定义路径不单单包括一条直线,也许是多条直线的运动组合,甚至还包含了贝塞尔曲线,因此,这个动画也许是下面这个样子的:

那么如何才能在canvas中实现这种动画效果呢?其实很简单,对于路径的处理svg非常在行,因此在canvas中实现自定义路径动画,我们需要借助svg的力量。

创建Path

制作动画前,先要拿到动画的路径,对此我们可以直接使用svg的path定义规则,比如我们定义了一条较为复杂的路径(它到底长什么样大家可以自己试试,这里就不展示了),然后,我们需要将定义好的路径导入进一个新生成的path元素中(我们只是借助svg的api,因此并不需要将其插到页面内)

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);
getTotalLength与getPointAtLength

SVGPathElement提供的这两个api很关键,可以说它是实现路径动画的最为核心的地方(在svg内实现自定义路径动画一般也是通过这两个api去解决)详情请戳:SVGPathElement MDN

getTotalLength方法可以获取SVGPathElement的总长度

getPointAtLength方法,传入一个长度x,将返回距离SVGPathElement起点的长度为x的终点坐标。

利用这两个api,通过循环的方式不断去更新canvas内所绘制的图形坐标,即可实现路径动画:

const length = pathElement.getTotalLength();
const duration = 1000; // 动画总时长
const interval = length / duration;
const canvas = document.querySelector("canvas");
const context = canvas.getContext("2d");
let time = 0, step = 0; 

const timer = setInterval(function() {
  if (time <= duration) {
    const x = parseInt(pathElement.getPointAtLength(step).x);
    const y = parseInt(pathElement.getPointAtLength(step).y);
    move(x, y);  // 更新canvas所绘制图形的坐标
    step++;
  } else {
    clearInterval(timer)
  }
}, interval);

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();
}

最后,我们把它封装一下,即可实现一个在canvas中实现自定义动画的简易函数啦:

function customizePath(path, func) {
    const pathElement = document.createElementNS("http://www.w3.org/2000/svg","path"); 
    pathElement.setAttributeNS(null, "d", path);
      const length = pathElement.getTotalLength();
    const duration = 1000; 
    const interval = length / duration;
    let time = 0, step = 0; 
  
      const timer = setInterval(function() {
        if (time <= duration) {
              const x = parseInt(pathElement.getPointAtLength(step).x);
              const y = parseInt(pathElement.getPointAtLength(step).y);
              func(x, y);
              step++;
        } else {
              clearInterval(timer)
        }
     }, interval);
}

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 canvas = document.querySelector("canvas");
const context = canvas.getContext("2d");
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();
}
customizePath(path, move);

实现思路大致如上所述,然而这并不是最终成果。当我们决定要在canvas制作自定义路径动画时,我们不仅要考虑如何实现,更要考虑性能优化,比如在这个实现思路中,我们是否可以减少不必要的渲染次数?帧率如何控制达到最优?等等。

虽然它们并不在这篇文章的讨论范围中,当也应当值得我们思考。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/91871.html

相关文章

  • Neo4j中实现自定义中文全文索引

    摘要:默认采用实现可定制,如自定义实现的索引,但默认新建的索引只支持精确匹配,模糊查询的话需要以全文索引,控制后台的分词行为。本文以常用的分词器为例,介绍如何在中对字段新建全文索引实现模糊查询。 数据库检索效率时,一般首要优化途径是从索引入手,然后根据需求再考虑更复杂的负载均衡、读写分离和分布式水平/垂直分库/表等手段;索引通过信息冗余来提高检索效率,其以空间换时间并会降低数据写入的效率,因...

    张率功 评论0 收藏0
  • 前端动画调研-V1

    摘要:支持动画状态的,在动画开始,执行中,结束时提供回调函数支持动画可以自定义贝塞尔曲线任何包含数值的属性都可以设置动画仓库文档演示功能介绍一定程度上,也是一个动画库,适用所有的属性,并且实现的能更方便的实现帧动画,替代复杂的定义方式。 动画调研-V1 前言:动画从用途上可以分为两种,一种是展示型的动画,类似于一张GIF图,或者一段视频,另一种就是交互性的动画。这两种都有具体的应用场景,比如...

    ddongjian0000 评论0 收藏0

发表评论

0条评论

Cympros

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<