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+Js制作漂亮时钟(附源码)
Apr 24 HTML / CSS
CSS3+HTML5+JS 实现一个块的收缩与展开动画效果
Nov 17 HTML / CSS
html5使用Canvas绘图的使用方法
Nov 21 HTML / CSS
使用phonegap检测网络状态的方法
Mar 30 HTML / CSS
HTML5之SVG 2D入门2—图形绘制(基本形状)介绍及使用
Jan 30 HTML / CSS
html5跨域通讯之postMessage的用法总结
Nov 07 HTML / CSS
html5摇一摇代码优化包括DeviceMotionEvent等等
Sep 01 HTML / CSS
浅谈Html5中视频 音频标签 进度条的问题
Jul 26 HTML / CSS
详解移动端HTML5页面端去掉input输入框的白色背景和边框(兼容Android和ios)
Dec 15 HTML / CSS
HTML5本地存储和本地数据库实例详解
Sep 05 HTML / CSS
使用SVG实现提示框功能的示例代码
Jun 05 HTML / CSS
css实现左上角飘带效果的完整代码
Mar 18 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 session安全问题分析
2011/06/24 PHP
ajax php传递和接收变量实现思路及代码
2012/12/19 PHP
php数组去重的函数代码
2013/02/03 PHP
php的慢速日志引起的Mysql错误问题分析
2014/05/13 PHP
Yii框架关联查询with用法分析
2014/12/02 PHP
javascript Base类 包含基本的方法
2009/07/22 Javascript
JS 文件大小判断的实现代码
2010/04/07 Javascript
在UpdatePanel内jquery easyui效果失效的解决方法
2010/04/11 Javascript
关于jquery append() html时的小问题的解决方法
2010/12/16 Javascript
jQuery $.data()方法使用注意细节
2012/12/31 Javascript
查找页面中所有类为test的结点的方法
2014/03/28 Javascript
js 左右悬浮对联广告特效代码
2014/12/12 Javascript
javascript中JSON对象与JSON字符串相互转换实例
2015/07/11 Javascript
jquery实现经典的淡入淡出选项卡效果代码
2015/09/22 Javascript
jQuery自定义动画函数实例详解(附demo源码)
2015/12/10 Javascript
javascript js 操作数组 增删改查的简单实现
2016/06/20 Javascript
JavaScript实现图片瀑布流和底部刷新
2017/01/02 Javascript
vue 子组件向父组件传值方法
2018/02/26 Javascript
js实现动态改变radio状态的方法
2018/02/28 Javascript
浅谈webpack 构建性能优化策略小结
2018/06/13 Javascript
js笔试题-接收get请求参数
2019/06/15 Javascript
vue 更改连接后台的api示例
2019/11/11 Javascript
Vite和Vue CLI的优劣
2021/01/30 Vue.js
python操作xml文件示例
2014/04/07 Python
python实现数值积分的Simpson方法实例分析
2015/06/05 Python
Python使用回溯法子集树模板解决爬楼梯问题示例
2017/09/08 Python
python安装教程
2018/02/28 Python
Django中日期处理注意事项与自定义时间格式转换详解
2018/08/06 Python
Python根据文件名批量转移图片的方法
2018/10/21 Python
基于python实现判断字符串是否数字算法
2020/07/10 Python
多重CSS背景动画实现方法示例
2014/04/04 HTML / CSS
如何避免常见的6种HTML5错误用法
2017/11/06 HTML / CSS
htnl5利用svg页面高斯模糊的方法
2018/07/20 HTML / CSS
大专自我鉴定范文
2013/10/23 职场文书
老干部工作汇报材料
2014/10/28 职场文书
2014年社区工会工作总结
2014/12/18 职场文书