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对图片照片进行边缘模糊处理的实现
Aug 08 HTML / CSS
css3一款3D字体带阴影效果的实现步骤
Mar 20 HTML / CSS
CSS3提交意见输入框样式代码
Oct 30 HTML / CSS
CSS3中的Media Queries学习笔记
May 23 HTML / CSS
CSS3中的@keyframes关键帧动画的选择器绑定
Jun 13 HTML / CSS
CSS3利用text-shadow属性实现多种效果的文字样式展现方法
Aug 25 HTML / CSS
H5 canvas中width、height和style的宽高区别详解
Nov 02 HTML / CSS
HTML5注册表单的自动聚焦与占位文本示例代码
Jul 19 HTML / CSS
html5超简单的localStorage实现记住密码的功能实现
Sep 07 HTML / CSS
h5使用canvas画布实现手势解锁
Jan 04 HTML / CSS
AmazeUI 折叠面板的实现代码
Aug 17 HTML / CSS
HTML5中input输入框默认提示文字向左向右移动的示例代码
Sep 10 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常用代码
2006/11/23 PHP
PHP Socket 编程
2010/04/09 PHP
教你如何开启shopnc b2b2c 伪静态
2014/10/21 PHP
PHP多线程之内部多线程实例分析
2015/03/09 PHP
PHP生成随机密码方法汇总
2015/08/27 PHP
PHP实现清除wordpress里恶意代码
2015/10/21 PHP
PHP数据库操作三:redis用法分析
2017/08/16 PHP
源码分析 Laravel 重复执行同一个队列任务的原因
2017/12/25 PHP
JQuery 前台切换网站的样式实现
2009/06/22 Javascript
javascript使用onclick事件改变选中行的颜色
2013/12/30 Javascript
详解JavaScript中undefined与null的区别
2014/03/29 Javascript
JS兼容浏览器的导出Excel(CSV)文件的方法
2014/05/03 Javascript
js+csss实现的一个带复选框的下拉框
2014/09/29 Javascript
nodejs爬虫抓取数据之编码问题
2015/07/03 NodeJs
nodejs+express实现文件上传下载管理网站
2017/03/15 NodeJs
微信小程序webview 脚手架使用详解
2019/07/22 Javascript
javascript将16进制的字符串转换为10进制整数hex
2020/03/05 Javascript
学前端,css与javascript重难点浅析
2020/06/11 Javascript
[02:44]完美大师赛主赛事淘汰赛第二日观众采访
2017/11/24 DOTA
python命令行参数解析OptionParser类用法实例
2014/10/09 Python
Python对字符串实现去重操作的方法示例
2017/08/11 Python
基于python时间处理方法(详解)
2017/08/14 Python
python2 与 pyhton3的输入语句写法小结
2018/09/10 Python
Python3.4学习笔记之类型判断,异常处理,终止程序操作小结
2019/03/01 Python
python连接打印机实现打印文档、图片、pdf文件等功能
2020/02/07 Python
python 装饰器的使用示例
2020/10/10 Python
美国女性服饰销售网站:Nasty Gal(坏女孩)
2016/07/26 全球购物
Linux中如何用命令创建目录
2015/01/12 面试题
班组安全员工作职责
2014/02/01 职场文书
会计专业职业规划:规划自我赢取未来
2014/02/12 职场文书
集团公司党的群众路线教育实践活动工作总结
2014/03/03 职场文书
卫生院健康教育实施方案
2014/06/07 职场文书
初中开学典礼新闻稿
2015/07/17 职场文书
Python中tkinter的用户登录管理的实现
2021/04/22 Python
基于Python实现的购物商城管理系统
2021/04/27 Python
Python中Schedule模块使用详解 周期任务神器
2022/04/19 Python