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 相关文章推荐
收集的22款给力的HTML5和CSS3帮助工具
Sep 14 HTML / CSS
css3绘制天猫logo实现代码
Nov 06 HTML / CSS
简单总结CSS3中视窗单位Viewport的常见用法
Feb 04 HTML / CSS
CSS3 linear-gradient线性渐变生成加号和减号的方法
Nov 21 HTML / CSS
浅谈css3中的渐进增强和优雅降级
Dec 01 HTML / CSS
使用HTML5 Canvas API中的clip()方法裁剪区域图像
Mar 25 HTML / CSS
video结合canvas实现视频在线截图功能
Jun 25 HTML / CSS
HTML5中判断横屏竖屏的方法(移动端)
Aug 04 HTML / CSS
详解通过focusout事件解决IOS键盘收起时界面不归位的问题
Jul 18 HTML / CSS
HTML5去掉输入框type为number时的上下箭头的实现方法
Jan 03 HTML / CSS
Canvas实现放大镜效果完整案例分析(附代码)
Nov 26 HTML / CSS
解决flex布局中子项目尺寸不受flex-shrink限制
May 11 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
非洲第一个咖啡超凡杯大赛承办国—卢旺达的咖啡怎么样
2021/03/03 咖啡文化
php self,$this,const,static,-&amp;gt;的使用
2009/10/22 PHP
PHP连接MongoDB示例代码
2012/09/06 PHP
PHP传参之传值与传址的区别
2015/04/24 PHP
学习PHP Cookie处理函数
2016/08/09 PHP
PHP编译configure时常见错误的总结
2017/08/17 PHP
让FireFox支持innerText的实现代码
2009/12/01 Javascript
jQuery调用WebService的实现代码
2011/06/19 Javascript
10款非常有用的 Ajax 插件分享
2012/03/14 Javascript
jquery 定位input元素的几种方法小结
2013/07/28 Javascript
学习JavaScript设计模式(多态)
2015/11/25 Javascript
jQuery实现简单倒计时功能的方法
2016/07/04 Javascript
使用bootstrapValidator插件进行动态添加表单元素并校验
2016/09/28 Javascript
JavaScript 继承详解(六)
2016/10/11 Javascript
JS组件系列之MVVM组件 vue 30分钟搞定前端增删改查
2017/04/28 Javascript
原生JavaScript实现remove()和recover()功能示例
2018/07/24 Javascript
js异步上传多张图片插件的使用方法
2018/10/22 Javascript
微信小程序实现动态显示和隐藏某个控件功能示例
2018/12/14 Javascript
Node.js操作系统OS模块用法分析
2019/01/04 Javascript
Vue实现数据请求拦截
2019/10/23 Javascript
Bootstrap table 服务器端分页功能实现方法示例
2020/06/01 Javascript
Python基础练习之用户登录实现代码分享
2017/11/08 Python
python读写文件write和flush的实现方式
2020/02/21 Python
css3新增颜色表示方式分享
2014/04/15 HTML / CSS
MCAKE蛋糕官方网站:一直都是巴黎的味道
2018/02/06 全球购物
Glamest意大利:女性在线奢侈品零售店
2019/04/28 全球购物
电子商务专业毕业生工作推荐信
2013/11/17 职场文书
金融行业务员的自我评价
2013/12/13 职场文书
采购类个人求职的自我评价
2014/02/18 职场文书
大专毕业生求职信
2014/07/05 职场文书
音乐教育专业自荐信
2014/09/18 职场文书
2014年个人年终总结
2015/03/09 职场文书
2015年妇产科工作总结
2015/05/18 职场文书
2016年精神文明建设先进个人事迹材料
2016/02/29 职场文书
员工保密协议范本,您一定得收藏!很有用!
2019/08/08 职场文书
golang slice元素去重操作
2021/04/30 Golang