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+Js制作漂亮时钟(附源码)
Apr 24 HTML / CSS
CSS3属性 line-clamp控制文本行数的使用
Mar 19 HTML / CSS
探究 canvas 绘图中撤销(undo)功能的实现方式详解
May 17 HTML / CSS
html5贪吃蛇游戏使用63行代码完美实现
Jun 25 HTML / CSS
HTML5 中新的全局属性(整理)
Jul 31 HTML / CSS
HTML5制作3D爱心动画教程 献给女友浪漫的礼物
Nov 05 HTML / CSS
HTML5中的强制下载属性download使用实例解析
May 12 HTML / CSS
HTML5调用手机发短信和打电话功能
Apr 29 HTML / CSS
简洁自适应404页面HTML好看的404源码
Dec 16 HTML / CSS
CSS3鼠标悬浮过渡缩放效果
Apr 17 HTML / CSS
CSS3实现列表无限滚动/轮播效果
Jun 23 HTML / CSS
HTML怎么设置下划线?html文字加下划线方法
Dec 06 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 Image Resize图片大小调整的函数代码
2011/01/17 PHP
php检测用户是否用手机(Mobile)访问网站的类
2014/01/09 PHP
php限制文件下载速度的代码
2015/10/20 PHP
深入理解PHP的远程多会话调试
2017/09/21 PHP
通过身份证号得到出生日期和性别的js代码
2009/11/23 Javascript
js DataSet数据源处理代码
2010/03/29 Javascript
JavaScript中判断对象类型的几种方法总结
2013/11/11 Javascript
JavaScript 32位整型无符号操作示例
2013/12/08 Javascript
js setTimeout()函数介绍及应用以倒计时为例
2013/12/12 Javascript
js设置文本框中焦点位置在最后的示例代码(简单实用)
2014/03/04 Javascript
jQuery+ajax中getJSON() 用法实例
2014/12/22 Javascript
js时间戳和c#时间戳互转方法(推荐)
2017/02/15 Javascript
微信小程序 本地图片按照屏幕尺寸处理
2017/08/04 Javascript
简单实现节流函数和防抖函数过程解析
2019/10/08 Javascript
基于vue-draggable 实现三级拖动排序效果
2020/01/10 Javascript
[01:28:56]2014 DOTA2华西杯精英邀请赛 5 24 CIS VS DK
2014/05/26 DOTA
Scrapy框架爬取西刺代理网免费高匿代理的实现代码
2019/02/22 Python
Python解析json时提示“string indices must be integers”问题解决方法
2019/07/31 Python
python  logging日志打印过程解析
2019/10/22 Python
基于Tensorflow高阶读写教程
2020/02/10 Python
VScode连接远程服务器上的jupyter notebook的实现
2020/04/23 Python
使用Python文件读写,自定义分隔符(custom delimiter)
2020/07/05 Python
Python+Selenium实现自动化的环境搭建的步骤(图文)
2020/09/01 Python
css3加js做一个简单的3D行星运转效果实例代码
2017/01/18 HTML / CSS
使用CSS3来代替JS实现交互
2017/08/10 HTML / CSS
英国马匹装备和马术用品购物网站:Equine Superstore
2019/03/03 全球购物
毕业生找工作的求职信范文
2013/12/24 职场文书
国际商务专业职业生涯规划书范文
2014/01/17 职场文书
上班看电影检讨书
2014/02/12 职场文书
幼儿园小班植树节活动方案
2014/03/04 职场文书
改革共识倡议书
2014/08/29 职场文书
教师遵守党的政治纪律情况对照检查材料
2014/09/26 职场文书
接触艺术对孩子学习思维有益
2019/08/06 职场文书
详解Vue slot插槽
2021/11/20 Vue.js
mysql timestamp比较查询遇到的坑及解决
2021/11/27 MySQL
Python+tkinter实现高清图片保存
2022/03/13 Python