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变形的transform-style属性详解
May 23 HTML / CSS
CSS3圆角边框和边界图片效果实例
Jul 01 HTML / CSS
关于box-sizing的全面理解
Jul 28 HTML / CSS
CSS3 分类菜单效果
May 27 HTML / CSS
HTML5对手机页面长按会粘贴复制禁用的解决方法
Jul 19 HTML / CSS
HTML5实践-图片设置成灰度图
Nov 12 HTML / CSS
html5的画布canvas——画出简单的矩形、三角形实例代码
Jun 09 HTML / CSS
HTML5中input[type='date']自定义样式与日历校验功能的实现代码
Jul 11 HTML / CSS
SVG实现多彩圆环倒计时效果的示例代码
Nov 21 HTML / CSS
前端实现弹幕效果的方法总结(包含css3和canvas的实现方式)
Jul 12 HTML / CSS
深入理解margin塌陷和margin合并的解决方案
Jun 26 HTML / CSS
使用CSS实现一个搜索引擎的原理解析
Sep 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
DISCUZ 分页代码
2007/01/02 PHP
PHP类的使用 实例代码讲解
2009/12/28 PHP
php GeoIP的使用教程
2011/03/09 PHP
php调用自己java程序的方法详解
2016/05/13 PHP
Yii数据模型中rules类验证器用法分析
2016/07/15 PHP
jQuery1.4.2与老版本json格式兼容的解决方法
2011/02/12 Javascript
javascript之典型高阶函数应用介绍二
2013/01/10 Javascript
JS判断表单输入是否为空(示例代码)
2013/12/23 Javascript
如何判断微信内置浏览器(通过User Agent实现)
2014/09/01 Javascript
jQuery表单域选择器用法分析
2015/02/10 Javascript
jQuery实现带动画效果的多级下拉菜单代码
2015/09/08 Javascript
node.js实现微信JS-API封装接口的示例代码
2017/09/06 Javascript
JS Input里添加小图标的两种方法
2017/11/11 Javascript
JS兼容所有浏览器的DOMContentLoaded事件
2018/01/12 Javascript
Vue前端开发规范整理(推荐)
2018/04/23 Javascript
微信小程序防止多次点击跳转和防止表单组件输入内容多次验证功能(函数防抖)
2019/09/19 Javascript
jQuery实现简单评论区功能
2020/10/26 jQuery
简单介绍Python中的struct模块
2015/04/28 Python
Python实现递归遍历文件夹并删除文件
2016/04/18 Python
Google开源的Python格式化工具YAPF的安装和使用教程
2016/05/31 Python
python编写微信远程控制电脑的程序
2018/01/05 Python
浅谈Python_Openpyxl使用(最全总结)
2019/09/05 Python
python PyAUtoGUI库实现自动化控制鼠标键盘
2020/09/09 Python
CSS3模拟动画下拉菜单效果
2017/04/12 HTML / CSS
Expedia法国:全球最大在线旅游公司
2018/09/30 全球购物
小学生防溺水广播稿
2014/01/12 职场文书
银行服务感言
2014/03/01 职场文书
公司财务流程之主管工作流程
2014/03/03 职场文书
保险公司早会主持词
2014/03/22 职场文书
上班迟到检讨书
2014/09/15 职场文书
2015年物业管理工作总结
2015/04/23 职场文书
少先队工作总结2015
2015/05/13 职场文书
导游词之西安大清真寺
2019/12/17 职场文书
mysql创建存储过程及函数详解
2021/12/04 MySQL
Elasticsearch 配置详解
2022/04/19 Java/Android
详解Mysql数据库平滑扩容解决高并发和大数据量问题
2022/05/25 MySQL