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 相关文章推荐
分享8款纯CSS3实现的搜索框功能
Sep 14 HTML / CSS
今天学到的CSS最新技术(与图片背景相关)
Dec 24 HTML / CSS
纯CSS3实现绘制各种图形实现代码详细整理
Dec 26 HTML / CSS
css3+jq创作含苞待放的荷花
Feb 20 HTML / CSS
纯CSS3制作漂亮带动画效果的主机价格表
Apr 25 HTML / CSS
CSS3制作酷炫的三维相册效果
Jul 01 HTML / CSS
css3编写浏览器背景渐变背景色的方法
Mar 05 HTML / CSS
html5 迷宫游戏(碰撞检测)实例一
Jul 25 HTML / CSS
html5实现的便签特效(实战分享)
Nov 29 HTML / CSS
谷歌浏览器小字体处理方案即12px以下字体
Dec 17 HTML / CSS
使用HTML5做的导航条详细步骤
Oct 19 HTML / CSS
纯html+css实现打字效果
Aug 02 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 strtr() 函数使用说明
2008/11/21 PHP
无需数据库在线投票调查php代码
2016/07/20 PHP
tp5.0框架隐藏index.php入口文件及模块和控制器的方法分析
2020/02/11 PHP
Javascript学习笔记5 类和对象
2010/01/11 Javascript
JavaScript节点及列表操作实例小结
2015/08/05 Javascript
js实现Select头像选择实时预览代码
2015/08/17 Javascript
JavaScript的Vue.js库入门学习教程
2016/05/23 Javascript
概述如何实现一个简单的浏览器端js模块加载器
2016/12/07 Javascript
nodejs实例解析(输出hello world)
2017/01/03 NodeJs
微信小程序中顶部导航栏的实现代码
2017/03/30 Javascript
JavaScript使用原型和原型链实现对象继承的方法详解
2017/04/05 Javascript
JS+Canvas绘制动态时钟效果
2017/11/10 Javascript
基于vue,vue-router, vuex及addRoutes进行权限控制问题
2018/05/02 Javascript
在vue项目中使用md5加密的方法
2018/09/14 Javascript
详解几十行代码实现一个vue的状态管理
2019/01/28 Javascript
async/await优雅的错误处理方法总结
2019/01/30 Javascript
gulp构建小程序的方法步骤
2019/05/31 Javascript
React+Redux实现简单的待办事项列表ToDoList
2019/09/29 Javascript
如何实现vue的tree组件
2020/12/03 Vue.js
用tensorflow实现弹性网络回归算法
2018/01/09 Python
Python(TensorFlow框架)实现手写数字识别系统的方法
2018/05/29 Python
Python实现的网页截图功能【PyQt4与selenium组件】
2018/07/12 Python
python tornado微信开发入门代码
2018/08/24 Python
python使用参数对嵌套字典进行取值的方法
2019/04/26 Python
简单了解python的一些位运算技巧
2019/07/13 Python
python实现多进程通信实例分析
2019/09/01 Python
python多线程实现代码(模拟银行服务操作流程)
2020/01/13 Python
python except异常处理之后不退出,解决异常继续执行的实现
2020/04/25 Python
Kears 使用:通过回调函数保存最佳准确率下的模型操作
2020/06/17 Python
Python字符串及文本模式方法详解
2020/09/10 Python
单位委托书范本
2014/04/04 职场文书
低碳生活倡议书
2014/04/14 职场文书
爱国主义教育活动总结
2014/05/07 职场文书
2014年生产管理工作总结
2014/12/23 职场文书
家长评语怎么写
2014/12/30 职场文书
Python进程间的通信之语法学习
2022/04/11 Python