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中31种选择器使用方法教程
Dec 05 HTML / CSS
纯CSS3实现鼠标悬停提示气泡效果
Feb 28 HTML / CSS
支持IE8的纯css3开发的响应式设计动画菜单教程
Nov 05 HTML / CSS
探究 canvas 绘图中撤销(undo)功能的实现方式详解
May 17 HTML / CSS
html5中canvas学习笔记2-判断浏览器是否支持canvas
Jan 06 HTML / CSS
html5的画布canvas——画出弧线、旋转的图形实例代码+效果图
Jun 09 HTML / CSS
HTML5在a标签内放置块级元素示例代码
Aug 23 HTML / CSS
HTML5 Canvas旋转动画的2个代码例子(一个旋转的太极图效果)
Apr 10 HTML / CSS
利用HTML5实现使用按钮控制背景音乐开关
Sep 21 HTML / CSS
HTML5 history新特性pushState、replaceState及两者的区别
Dec 26 HTML / CSS
通过canvas转换颜色为RGBA格式及性能问题的解决
Nov 22 HTML / CSS
canvas绘制树形结构可视图形的实现
Apr 03 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遍历文件夹与子目录的函数代码
2011/09/26 PHP
windows7下安装php的imagick和imagemagick扩展教程
2014/07/04 PHP
php实现无限级分类查询(递归、非递归)
2016/03/10 PHP
php实现图片以base64显示的方法
2016/10/13 PHP
利用ajax和PHP实现简单的流程管理
2017/03/23 PHP
微信公众平台开发教程⑥ 微信开发集成类的使用图文详解
2019/04/10 PHP
XML的代替者----JSON
2007/07/21 Javascript
jquery ajax 登录验证实现代码
2009/09/23 Javascript
Javascript中的for in循环和hasOwnProperty结合使用
2013/06/05 Javascript
js动态生成指定行数的表格
2013/07/11 Javascript
Javascript中的作用域和上下文深入理解
2015/07/03 Javascript
JS中的eval 为什么加括号
2016/04/13 Javascript
静态页面html中跳转传值的JS处理技巧
2016/06/22 Javascript
jQuery插件HighCharts绘制2D带Label的折线图效果示例【附demo源码下载】
2017/03/08 Javascript
Vue中使用vee-validate表单验证的方法
2018/05/09 Javascript
react.js组件实现拖拽复制和可排序的示例代码
2018/08/20 Javascript
基于jquery实现九宫格拼图小游戏
2018/11/30 jQuery
JavaScript中引用vs复制示例详析
2018/12/06 Javascript
vue如何搭建多页面多系统应用
2020/06/17 Javascript
用Python和MD5实现网站挂马检测程序
2014/03/13 Python
python实现封装得到virustotal扫描结果
2014/10/05 Python
在Python中使用mechanize模块模拟浏览器功能
2015/05/05 Python
Python中正则表达式详解
2017/05/17 Python
python密码错误三次锁定(实例讲解)
2017/11/14 Python
python-str,list,set间的转换实例
2018/06/27 Python
Python利用递归实现文件的复制方法
2018/10/27 Python
Python数据可视化之画图
2019/01/15 Python
python实现最大优先队列
2019/08/29 Python
Python中xml和dict格式转换的示例代码
2019/11/07 Python
Python xml、字典、json、类四种数据类型如何实现互相转换
2020/05/27 Python
HTML5 Convas APIs方法详解
2015/04/24 HTML / CSS
原生canvas制作画图小工具的踩坑和爬坑
2020/06/09 HTML / CSS
一个SQL面试题
2014/08/21 面试题
党支部三会一课计划
2014/09/24 职场文书
2016年优秀少先队员事迹材料
2016/02/26 职场文书
win10拖拽文件时崩溃怎么解决?win10文件不能拖拽问题解决方法
2022/08/14 数码科技