最简单太阳系H5动画canvas详解 零基础可入
最简单太阳系H5动画canvas详解 零基础可入
最终结果:(实际为动画效果,金星绕轨道转动)
页面准备/html
要使用canvas,需要首先在页面中要绘制的位置放入canvas标签元素,在后期的绘制脚本中通过选择器获取元素,此后脚本在该元素绘制效果。
<canvas id="myCanvas" // 非必要width="300"height="300" style="border:1px solid #000000" // 非必要
></canvas>
本案例中使用id为方便获取,实际操作中只要成功获取到元素即可,通过类名,标签等方式都可
canvas中提供两个属性width与height,可在标签中直接规定其大小
本案例中写入直联样式border只为增强视觉效果,非必要
初始化函数/init
要做动画,首先我们需要先做一个静态案例,再重绘使它动起来。
首先我们制作动画的初始化函数,函数中,我们将绘制需要的元素准备好,同时初始化函数作为绘制函数的入口。
这里将绘制函数分离出来是为了方便后面的重绘时的重复调用绘制函数,如果只希望绘制静态页面,也可直接放在一起。
let moon; // 月球元素 带有月球图片地址的图片元素 可绘制在canvas上
let venus; // 金星元素 带有金星图片地址的图片元素 可绘制在canvas上
let ctx; // 画笔
// 以上元素需要在初始化及绘制中使用,所以在外部定义 function init(){// 创建并引入月球图片moon = new Image();moon.src = "moon.jpg"venus = new Image();// 创建并引入金星图片venus.src = "venus.jpg";// 获得画板元素let canvas = document.querySelector("#myCanvas");// 激活画笔ctx = canvas.getContext("2d");// 在图片加载完成后开始绘制动画moon.onload = function (){draw();}
}
案例中所用的moon图片:
https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=3666816182,1910985606&fm=26&gp=0.jpg
案例中所用的venus图片:
http://qqpublic.qpic.cn/qq_public/0/0-2694106759-1EC786EC7E4BD7758742CEB938698DD7/0?fmt=jpg&size=22&h=480&w=422&ppv=1/0
如上,我们在init函数中做好了绘制前的准备,并激发了绘制函数。
绘制函数/draw
首先我们在绘制函数中,在canvas上简单的绘制一个在init中准备好的图片元素,以检验代码是否正常运作。
function draw(){// 绘制带有月球的基底图案ctx.drawImage(moon, 0, 0,300,300);
}
参数说明 drawImage(image, 位置坐标x, 位置坐标y, image_width, image_height))
此图片为基地图片,所以大小与canvas标签大小相同,为300*300
此刻效果:
接下来绘制轨道,绘制轨道需要用到画笔元素自带的方法arc
arc(x, y, r, startAngle, endAngle, anticlockwise): 以
(x, y)
为圆心,以r
为半径,从startAngle
弧度开始到endAngle
弧度结束。anticlosewise
是布尔值,true
表示逆时针,false
表示顺时针(默认是顺时针)。
当绘制轨道时,圆心在中央,也就是150*150处,此时我们可以选择移动画笔(移动原点),将画笔放置在中心,然后设置绘制圆心为0*0,也可以不移动画笔,设置圆心为150*150,案例中选择前者,因为画的是一个完整的圆,所以我们开始角度设置为0,结束角度设置为2 * Math.PI。
在draw中添加绘制轨道代码
function draw(){... ...ctx.translate(150, 150); // 绘制轨道 先将画笔移到中心,即月球的中心位置ctx.beginPath(); // 设置画笔为 绘制路径模式 构建一个路径ctx.strokeStyle = "rgba(255,255,255,.3)"; // 确定该路径颜色ctx.arc(0, 0, 100, 0, 2 * Math.PI); // 确定该路径ctx.stroke(); // 绘制该路径到canvas上
}
此刻效果:
接下来绘制金星,金星在案例中是一个动态元素,但是我们可以先绘制一个静态的元素,再将它改为动态,有助于我们理解案例。
function draw(){... ...// 绘制金星元素ctx.translate(100, 0); // 将坐标原点在X轴上移动一个轨道半径的距离,使原点正好落在轨道上ctx.drawImage(venus, -17, -12,35,40) // 绘制金星元素 图片大小和位置可以自己微调
}
drawImage(image, 位置坐标x, 位置坐标y, image_width, image_height))
此刻效果:
此时金星是不会动的,让其动作起来,要增加三个要素
首先,我们要多次循环激发绘制函数,引发重绘,动画的重绘有特定的api,该api会在下一次屏幕时激发重绘。
在draw函数最后一行添加该api即可。
function draw(){... ...requestAnimationFrame(draw); // 触发重绘
}
其次,刚刚我们在绘制中多次改变了原点状态,而重绘的时候状态需要还原,才能保证重绘时不会偏离原来的位置,对此我们有两个api用来保存canvas当前的状态和还原状态。
canvas的状态是通过栈来维护的。
function draw(){ctx.save(); // 在第一次translate(改变坐标系或原点) 前保存初始状态... ...ctx.restore(); // 在完成绘制,激发重绘前还原状态requestAnimationFrame(draw); // 触发重绘
}
最后,现在可以成功重绘了,但是仍然看不到效果,因为每次重绘都是一致的,而我们希望每次重绘金星的位置都有所变化,通过观察得知,金星围绕中心转动,也就是每次绘制对于中心的角度发生变化,我们可以通过原点在中心时,改变坐标系角度,再移动原点到外轨道上的方式。
function draw(){... ... // 绘制动态金星元素let time = new Date();ctx.rotate(2 * Math.PI / 60 * time.getSeconds() + 2 * Math.PI / 60000 * time.getMilliseconds());ctx.translate(100, 0); // 将坐标原点在X轴上移动一个轨道半径的距离,使原点正好落在轨道上ctx.drawImage(venus, -17, -12,35,40) // 绘制金星元素 图片大小和位置可以自己微调... ...
}
rotate(angle)
旋转坐标轴。
这个方法只接受一个参数:旋转的角度(angle),它是顺时针方向的,以弧度为单位的值。
旋转的中心是坐标原点。
本案例中的角度是根据时间推算出的,旋转周期为一分钟,旋转角度由时间和一周的角度算出
此时,案例动起来了。
如果觉得动画过于单调,可以为金星也加一圈轨道。
最终结果:
旋转坐标轴。
这个方法只接受一个参数:旋转的角度(angle),它是顺时针方向的,以弧度为单位的值。
旋转的中心是坐标原点。
本案例中的角度是根据时间推算出的,旋转周期为一分钟,旋转角度由时间和一周的角度算出
此时,案例动起来了。
如果觉得动画过于单调,可以为金星也加一圈轨道。
最终结果:(实际为动画效果)
整体代码:
let moon;let venus;let ctx;function init(){// 创建并引入月球图片moon = new Image();moon.src = "https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=3666816182,1910985606&fm=26&gp=0.jpg"venus = new Image();// 创建并引入金星图片venus.src = "http://qqpublic.qpic.cn/qq_public/0/0-2694106759-1EC786EC7E4BD7758742CEB938698DD7/0?fmt=jpg&size=22&h=480&w=422&ppv=1/0";// 获得画板元素let canvas = document.querySelector("#myCanvas");// 激活画笔ctx = canvas.getContext("2d");// 在图片加载完成后开始绘制动画moon.onload = function (){draw();}}init();function draw(){// 绘制基底图案 moonctx.drawImage(moon, 0, 0,300,300);ctx.save();// 绘制轨道 先将画笔移到中心,即月球的中心位置ctx.translate(150, 150);ctx.beginPath();ctx.strokeStyle = "rgba(255,255,255,.3)";ctx.arc(0, 0, 100, 0, 2 * Math.PI)ctx.stroke()let time = new Date();ctx.rotate(2 * Math.PI / 60 * time.getSeconds() + 2 * Math.PI / 60000 * time.getMilliseconds());ctx.translate(100, 0);ctx.beginPath();ctx.strokeStyle = "rgba(255,255,255,.3)";ctx.arc(0, 0, 30, 0, 2 * Math.PI);ctx.stroke()ctx.drawImage(venus, -17, -20,35,40)ctx.restore();requestAnimationFrame(draw);}
有网友在评论中指出,对代码中的角度计算公式不太理解,特此补充。
ctx.rotate(2 * Math.PI / 60 * time.getSeconds() + 2 * Math.PI / 60000 * time.getMilliseconds());
上面代码公式是一个角度计算公式,需要一点数学思维。
首先我们代码中设定的是一分钟转一圈,也就是60秒转360度,
Math.PI是180度,乘2是360度,也就是一周,2 * Math.PI / 60是获得一秒钟转动的角度。
time.getSeconds() 为获取当前秒数 也就是一秒钟转动的角度乘以当前秒数 得出此时应该转动的最终角度 每过一秒 转动的角度大一些,
此时如果不加后面的也可以,就变成了秒针滴答的感觉,因为一秒变一次还是人眼可捕捉的。
为了视觉平滑效果,我们添加一个补充角度,也就是当前毫秒数,让位移变为毫秒级。
与前面相同 2 * Math.PI / 60000 获得每毫秒转动的角度 time.getMilliseconds() 取得当前毫秒。
最简单太阳系H5动画canvas详解 零基础可入相关推荐
- html5 canvas基础与动画开发详解-吴华-专题视频课程
html5 canvas基础与动画开发详解-533人已学习 课程介绍 一.本课程几乎包括所有canvas常用的api用法讲解 二.包括以下案例应用: 1.坐标系绘制 2.图片裁剪与填充 ...
- Android 动画框架详解,第 1 部分
2019独角兽企业重金招聘Python工程师标准>>> Android 平台提供了一套完整的动画框架,使得开发者可以用它来开发各种动画效果,本文将向读者阐述 Android 的动画框 ...
- Android 吸入动画效果详解(仿mac退出效果)
转载自:http://m.blog.csdn.net/blog/leehong2005/9127095 [转]Android 吸入动画效果详解 1,背景 吸入(Inhale)效果,最初我是在iOS上面 ...
- Android 动画框架详解
Android 动画框架详解 基本原理 朱 韦伟, 软件工程师, IBM 李 浩, 软件工程师, 爱格码 简介: Android 平台提供了一套完整的动画框架,使得开发者可以用它来开发各种动画效果.A ...
- Unity动画系统详解10:子状态机是什么?
摘要:除了使用Layer还有没有更好的组织状态的方式呢?感觉一个Layer里面状态多的时候,还是很显得很乱. 洪流学堂,让你快人几步.你好,我是跟着大智学Unity的萌新,我叫小新,这是复(yu)习( ...
- Unity动画系统详解5:BlendTree混合树是什么?
摘要:"Animator中有一个功能,用来解决多个动画之间的混合,经常用于移动动画之间的混合,这个功能叫做BlendTree,混合树." 洪流学堂,让你快人几步.你好,我是跟着大智 ...
- unity velocity_Unity动画系统详解5:BlendTree混合树是什么?
摘要:"Animator中有一个功能,用来解决多个动画之间的混合,经常用于移动动画之间的混合,这个功能叫做BlendTree,混合树." 洪流学堂,让你快人几步.你好,我是跟着大智 ...
- T4M插件放入unity后怎么找不到_Unity动画系统详解4:如何用代码控制动画?
摘要:通过上一篇咱们知道了播放动画需要使用Animator,那么如何用代码控制动画呢? 洪流学堂,让你快人几步.你好,我是跟着大智学Unity的萌新,我叫小新,这几周一起来复(yu)习(xi)动画系统 ...
- 拐道交叉的css3动画,CSS3图片翻转动画技术详解
CSS动画非常的有趣:这种技术的美就在于,通过使用很多简单的属性,你能创建出漂亮的消隐效果.其中代表性的一种就是CSS图片翻转效果,能让你看到一张卡片的正反两面上的内容.本文就是要用最简单的方法向大家 ...
最新文章
- 【OpenCV 4开发详解】窗口交互操作
- 大型网站技术架构(八)网站的安全架构
- nsis使用汇总(一)
- 闲话WPF之十五(WPF的数据处理 [2])
- Jmeter CSV 参数化/检查点/断言
- [转]如何将属性表嵌入对话框中显示
- keil的主要功能和作用_组合式空调机组各功能段的主要作用
- GitLab+Nornor3.0.0完成CI/CD流水线配置(更新版)
- Unity 接入科大讯飞进行在线语音合成
- 精益生产管理专家——安岷老师
- Python 日历模块 calendar
- IC、FPGA验证学习
- 4. ElasticSearch——aggregations聚合分析
- 立创eda学习笔记二十二:如何修改pcb网络颜色?
- 自签名多级证书亲测可用
- 李宁卖咖啡,意欲何为?
- [1064]旅途时间
- 数学基础:斜率、正切与 math.tan()
- 博弈论2-哈尔冰工业大学
- spdlog日志库使用说明
热门文章
- 【python+Selenium】Selenium使用步骤解析
- StringBoot中String转JSON,JSON转Map或List
- 一种通用的数据仓库分层方法
- C# winfrom调用Bartender打印,具名打印,以及数据库打印
- sublime 打开报错 Error loading syntax file “Packages/HTML/HTML.sublime-syntax“: Apparent recursion withi
- [附源码]计算机毕业设计校园二手交易平台Springboot程序
- css 图片自适应屏幕大小
- GEE(Google Earth Engine)计算全球的NDVI和SAVI!
- IBM ServerGuide引导盘地址
- 《基于NXP+DSP车载音频软件结构框图》