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 相关文章推荐
25个CSS3动画按钮和菜单教程分享
Oct 03 HTML / CSS
移动Web—CSS为Retina屏幕替换更高质量的图片
Dec 24 HTML / CSS
基于CSS3实现立方体自转效果
Mar 01 HTML / CSS
纯CSS3代码实现文字描边
Apr 25 HTML / CSS
详解Html5 Canvas画线有毛边解决方法
Mar 01 HTML / CSS
利用HTML5+css3+jquery+weui实现仿微信聊天界面功能
Jan 08 HTML / CSS
HTML5之SVG 2D入门12—SVG DOM及DOM操作介绍
Jan 30 HTML / CSS
html5文字阴影效果text-shadow使用示例
Jul 25 HTML / CSS
HTML5的自定义属性data-*详细介绍和JS操作实例
Apr 10 HTML / CSS
canvas需要在标签里直接定义宽高
Dec 17 HTML / CSS
浅谈HTML5 服务器推送事件(Server-sent Events)
Aug 01 HTML / CSS
html5中使用hotcss.js实现手机端自适配的方法
Apr 23 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/10/09 PHP
Zend Studio 无法启动的问题解决方法
2008/12/04 PHP
php读取msn上的用户信息类
2008/12/05 PHP
php 正则匹配函数体
2009/08/25 PHP
php获取本地图片文件并生成xml文件输出具体思路
2013/04/27 PHP
浅析HTTP消息头网页缓存控制以及header常用指令介绍
2013/06/28 PHP
YII Framework教程之异常处理详解
2016/03/14 PHP
ThinkPHP框架实现数据增删改
2017/05/07 PHP
使用PHP+MySql+Ajax+jQuery实现省市区三级联动功能示例
2017/09/15 PHP
php实现的AES加密类定义与用法示例
2018/01/29 PHP
(function(){})()的用法与优点
2007/03/11 Javascript
JavaScript 捕获窗口关闭事件
2009/07/26 Javascript
JQery jstree 大数据量问题解决方法
2010/03/09 Javascript
jquery下json数组的操作实现代码
2010/08/09 Javascript
dreamweaver 安装Jquery智能提示
2011/04/02 Javascript
javascript高级程序设计第二版第十二章事件要点总结(常用的跨浏览器检测方法)
2012/08/22 Javascript
细说javascript函数从函数的构成开始
2013/08/29 Javascript
关于JS数组追加数组采用push.apply的问题
2014/06/09 Javascript
jQuery ajax调用WCF服务实例
2014/07/16 Javascript
jQuery实现可高亮显示的二级CSS菜单效果
2015/09/01 Javascript
快速解决js开发下拉框中blur与click冲突
2016/10/10 Javascript
浅谈Emergence.js 检测元素可见性的 js 插件
2017/11/18 Javascript
JS+CSS3实现的简易钟表效果示例
2019/04/13 Javascript
jquery html添加元素/删除元素操作实例详解
2020/05/20 jQuery
解析Python中的__getitem__专有方法
2016/06/27 Python
pandas apply 函数 实现多进程的示例讲解
2018/04/20 Python
Python3实现获取图片文字里中文的方法分析
2018/12/13 Python
numpy按列连接两个维数不同的数组方式
2019/12/06 Python
使用 Python 遍历目录树的方法
2020/02/29 Python
深入理解HTML的FormData对象
2016/05/17 HTML / CSS
世界上最大的售后摩托车零配件超市:J&P Cycles
2017/12/08 全球购物
介绍一下Java中标识符的命名规则
2014/02/03 面试题
检讨书怎么写
2015/05/07 职场文书
乡镇安全生产月活动总结
2015/05/08 职场文书
详解python网络进程
2021/06/15 Python
Java 使用类型为Object的变量指向任意类型的对象
2022/04/13 Java/Android