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 相关文章推荐
分享30个新鲜的CSS3打造的精美绚丽效果(附演示下载)
Dec 28 HTML / CSS
纯CSS实现颜色渐变效果(包含环形渐变、线性渐变、彩虹效果等)
May 07 HTML / CSS
CSS3绘制超炫的上下起伏波动进度加载动画
Apr 21 HTML / CSS
CSS的background属性及CSS3的背景图片设置总结
Jun 13 HTML / CSS
html5跨域通讯之postMessage的用法总结
Nov 07 HTML / CSS
canvas实现高阶贝塞尔曲线(N阶贝塞尔曲线生成器)
Jan 10 HTML / CSS
HTML如何让IMG自动适应DIV容器大小的实现方法
Feb 25 HTML / CSS
CSS 文字装饰 text-decoration & text-emphasis 详解
Apr 06 HTML / CSS
CSS3 实现NES游戏机的示例代码
Apr 21 HTML / CSS
HTML+CSS实现导航条下拉菜单的示例代码
Aug 02 HTML / CSS
使用CSS连接数据库的方式
Feb 28 HTML / CSS
css样式important规则的正确使用方式
Jun 10 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的一个完整SMTP类(解决邮件服务器需要验证时的问题)
2006/10/09 PHP
在PHP中执行系统外部命令
2006/10/09 PHP
用PHP的ob_start();控制您的浏览器cache!
2006/11/25 PHP
php入门之连接mysql数据库的一个类
2012/04/21 PHP
phpmyadmin config.inc.php配置示例
2013/08/27 PHP
PHP实现的多文件上传类及用法示例
2016/05/06 PHP
YII框架http缓存操作示例
2019/04/29 PHP
laradock环境docker-compose操作详解
2019/07/29 PHP
phpStorm2020 注册码
2020/09/17 PHP
广告代码静态化js通用函数
2007/05/09 Javascript
IE浏览器PNG图片透明效果代码
2008/09/02 Javascript
JavaScript 事件记录使用说明
2009/10/20 Javascript
jquery之empty()与remove()区别说明
2010/09/10 Javascript
学习从实践开始之jQuery插件开发 菜单插件开发
2012/05/03 Javascript
javascript学习笔记(十六) 系统对话框(alert、confirm、prompt)
2012/06/20 Javascript
js动画效果制件让图片组成动画代码分享
2014/01/14 Javascript
javascript函数自动执行常用方法汇总
2016/03/28 Javascript
Easyui在treegrid添加控件的实现方法
2017/06/23 Javascript
微信小程序使用navigateTo数据传递的实例
2017/09/26 Javascript
父组件中vuex方法更新state子组件不能及时更新并渲染的完美解决方法
2018/04/25 Javascript
js实现多张图片每隔一秒切换一张图片
2019/07/29 Javascript
利用QT写一个极简单的图形化Python闹钟程序
2015/04/07 Python
详解Python中__str__和__repr__方法的区别
2015/04/17 Python
Python3爬楼梯算法示例
2019/03/04 Python
Django如何使用第三方服务发送电子邮件
2019/08/14 Python
opencv 查找连通区域 最大面积实例
2020/06/04 Python
Appium+Python实现简单的自动化登录测试的实现
2021/01/26 Python
python爬虫今日热榜数据到txt文件的源码
2021/02/23 Python
韩国演唱会订票网站:StubHub韩国
2019/01/17 全球购物
为什么会有内存对齐
2016/10/10 面试题
规划编制实施方案
2014/03/15 职场文书
国家机关领导干部民主生活会对照检查材料思想汇报
2014/09/17 职场文书
群众路线教育实践活动心得体会(教师)
2014/10/31 职场文书
2014年办公室文员工作总结
2014/11/12 职场文书
九年级英语教学反思
2016/02/15 职场文书
springboot中一些比较常用的注解总结
2021/06/11 Java/Android