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 相关文章推荐
css背景图片的背景裁切、背景透明度、背景变换等效果运用
Dec 24 HTML / CSS
CSS3实现的文本3D效果附图
Sep 03 HTML / CSS
使用CSS3实现多列布局与多背景的技巧
Feb 29 HTML / CSS
简单掌握CSS3中resize属性的用法
Apr 01 HTML / CSS
详解CSS3实现响应式手风琴效果
Jun 10 HTML / CSS
css3中仿放大镜效果的几种方式原理解析
Dec 03 HTML / CSS
html5文本内容_动力节点Java学院整理
Jul 11 HTML / CSS
HTML5 常用语法一览(列举不支持的属性)
Jan 26 HTML / CSS
HTML5 placeholder(空白提示)属性介绍
Aug 07 HTML / CSS
html5基础标签(html5视频标签 html5新标签用法)
Dec 30 HTML / CSS
AmazeUI 网格的实现示例
Aug 13 HTML / CSS
css position fixed 左右双定位的实现代码
Apr 29 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命名空间学习详解
2014/02/27 PHP
zf框架db类的分页示例分享
2014/03/14 PHP
PHP实现的购物车类实例
2015/06/17 PHP
详解WordPress中调用评论模板和循环输出评论的PHP函数
2016/01/05 PHP
Yii2框架中使用PHPExcel导出Excel文件的示例
2017/08/09 PHP
Ajax+PHP实现的删除数据功能示例
2019/02/12 PHP
Javascript客户端脚本的设计和应用
2006/08/21 Javascript
用jquery设置按钮的disabled属性的实现代码
2010/11/28 Javascript
jQuery创建插件的代码分析
2011/04/14 Javascript
jqgrid 简单学习笔记
2011/05/03 Javascript
JavaScript forEach()遍历函数使用及介绍
2015/07/08 Javascript
js本地图片预览实现代码
2016/10/09 Javascript
JavaScript常用正则函数用法示例
2017/01/23 Javascript
基于VUE移动音乐WEBAPP跨域请求失败的解决方法
2018/01/16 Javascript
vue计算属性和监听器实例解析
2018/05/10 Javascript
vue-cli项目代理proxyTable配置exclude的方法
2018/09/20 Javascript
Vue 组件修改根实例的数据的方法
2019/04/02 Javascript
vuex + keep-alive实现tab标签页面缓存功能
2019/10/17 Javascript
element的el-table中记录滚动条位置的示例代码
2019/11/06 Javascript
vant IndexBar实现的城市列表的示例代码
2019/11/20 Javascript
python操作MySQL数据库的方法分享
2012/05/29 Python
Python3安装Scrapy的方法步骤
2017/11/23 Python
python 读取txt中每行数据,并且保存到excel中的实例
2018/04/29 Python
Python3.5 Pandas模块缺失值处理和层次索引实例详解
2019/04/23 Python
Django REST Framework之频率限制的使用
2019/09/29 Python
UGG英国官方网站:UGG UK
2018/02/08 全球购物
联想德国官网:Lenovo Germany
2018/07/04 全球购物
string = null 和string = ''的区别
2013/04/28 面试题
总经理办公室主任岗位职责
2013/11/12 职场文书
运动会通讯稿200字
2014/02/16 职场文书
工商管理自荐书
2014/07/06 职场文书
最新离婚协议书范本
2014/08/19 职场文书
爱牙日活动总结
2014/08/29 职场文书
党员先进事迹材料
2014/12/19 职场文书
中学感恩教育活动总结
2015/05/05 职场文书
Java中的继承、多态以及封装
2022/04/11 Java/Android