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


Posted in HTML / CSS onSeptember 18, 2017

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

html5如何在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制作自定义路径动画时,我们不仅要考虑如何实现,更要考虑性能优化,比如在这个实现思路中,我们是否可以减少不必要的渲染次数?帧率如何控制达到最优?等等。

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

HTML / CSS 相关文章推荐
纯CSS3实现3D旋转书本效果
Mar 21 HTML / CSS
结合CSS3的布局新特征谈谈常见布局方法
Jan 22 HTML / CSS
HTML5本地存储之IndexedDB
Jun 16 HTML / CSS
详解html5 shiv.js和respond.min.js
Jan 24 HTML / CSS
Html5与App的通讯方式详解
Oct 24 HTML / CSS
html5简介及新增功能介绍
May 18 HTML / CSS
HTML5 video循环播放多个视频的方法步骤
Aug 06 HTML / CSS
AmazeUI 输入框组的示例代码
Aug 14 HTML / CSS
AmazeUI中各种的导航式菜单与解决方法
Aug 19 HTML / CSS
HTML5实现移动端点击翻牌功能
Oct 23 HTML / CSS
企业开发CSS命名BEM代码规范实践
Feb 12 HTML / CSS
HTML5基础学习之文本标签控制
Mar 25 HTML / CSS
HTML5在线预览PDF的示例代码
Sep 14 #HTML / CSS
HTML5 拖放(Drag 和 Drop)详解与实例代码
Sep 14 #HTML / CSS
HTML5页面中尝试调起APP功能
Sep 12 #HTML / CSS
html5使用canvas实现弹幕功能示例
Sep 11 #HTML / CSS
基于HTML5+CSS3实现简单的时钟效果
Sep 11 #HTML / CSS
html5超简单的localStorage实现记住密码的功能实现
Sep 07 #HTML / CSS
HTML5本地存储和本地数据库实例详解
Sep 05 #HTML / CSS
You might like
php对mongodb的扩展(初出茅庐)
2012/11/11 PHP
php获取根域名方法汇总
2014/10/28 PHP
php制作文本式留言板
2015/03/18 PHP
js对象之JS入门之Array对象操作小结
2011/01/09 Javascript
JS字符串函数扩展代码
2011/09/13 Javascript
js数组的操作详解
2013/03/27 Javascript
JS简单的轮播的图片滚动实例
2013/06/17 Javascript
js切换光标示例代码
2013/10/10 Javascript
初识Javascript小结
2015/07/16 Javascript
JavaScript类型系统之基本数据类型与包装类型
2016/01/06 Javascript
微信小程序 swiper组件详解及实例代码
2016/10/25 Javascript
Bootstrap基本组件学习笔记之缩略图(13)
2016/12/08 Javascript
JS实现的系统调色板完整实例
2016/12/21 Javascript
jQuery实现的两种简单弹窗效果示例
2018/04/18 jQuery
如何把vuejs打包出来的文件整合到springboot里
2018/07/26 Javascript
Koa代理Http请求的示例代码
2018/10/10 Javascript
extract-text-webpack-plugin用法详解
2019/02/14 Javascript
[01:06:42]VP vs NewBee Supermajor 胜者组 BO3 第二场 6.5
2018/06/06 DOTA
Python简单网络编程示例【客户端与服务端】
2017/05/26 Python
python 设置文件编码格式的实现方法
2017/12/21 Python
浅谈Matplotlib简介和pyplot的简单使用——文本标注和箭头
2018/01/09 Python
Python闭包执行时值的传递方式实例分析
2018/06/04 Python
python 矢量数据转栅格数据代码实例
2019/09/30 Python
Django实现文件上传下载
2019/10/06 Python
浅谈PyTorch的可重复性问题(如何使实验结果可复现)
2020/02/20 Python
CSS3教程(8):CSS3透明度指南
2009/04/02 HTML / CSS
html5中使用hotcss.js实现手机端自适配的方法
2020/04/23 HTML / CSS
Jacadi Paris英国官网:法国童装品牌
2019/08/09 全球购物
幼儿园教师个人反思
2014/01/30 职场文书
中专生自荐信
2014/06/25 职场文书
测绘工程专业求职信
2014/07/15 职场文书
学习十八届四中全会依法治国心得体会
2014/11/03 职场文书
硕士学位申请报告
2015/05/15 职场文书
学校元旦晚会开场白
2015/05/29 职场文书
2019年市场部个人述职报告(三篇)
2019/10/23 职场文书
如何用Node.js编写内存效率高的应用程序
2021/04/30 Javascript