canvas绘制动画的技巧
我们拿下图中的沿着线段轨迹移动的原点来举例,怎么来实现这个动画!

1)定义路径集合Path,里面规定关键坐标点如startPoint和endPoint,设置从startPoint移动到endPoint的时间duration。
如下json对象,我们有6段路径,分别进行了定义。我们将下面这个列表集合命名为path。
1 [
2 {
3 "startPoint": {
4 "x": 252.86249999999995,
5 "y": 191.39166666666665
6 },
7 "endPoint": {
8 "x": 252.86249999999995,
9 "y": 169.66666666666666
10 },
11 "duration": 3000
12 },
13 {
14 "startPoint": {
15 "x": 251.62499999999994,
16 "y": 169.66666666666666
17 },
18 "endPoint": {
19 "x": 393.52499999999986,
20 "y": 226.2833333333333
21 },
22 "duration": 15000
23 },
24 {
25 "startPoint": {
26 "x": 393.52499999999986,
27 "y": 226.2833333333333
28 },
29 "endPoint": {
30 "x": 393.52499999999986,
31 "y": 427.075
32 },
33 "duration": 15000
34 },
35 {
36 "startPoint": {
37 "x": 385.6874999999999,
38 "y": 420.4916666666667
39 },
40 "endPoint": {
41 "x": 385.6874999999999,
42 "y": 407.2916666666667
43 },
44 "duration": 3000
45 },
46 {
47 "startPoint": {
48 "x": 385.6874999999999,
49 "y": 407.2916666666667
50 },
51 "endPoint": {
52 "x": 125.8125,
53 "y": 421.94166666666666
54 },
55 "duration": 15000
56 },
57 {
58 "startPoint": {
59 "x": 126.6375,
60 "y": 421.94166666666666
61 },
62 "endPoint": {
63 "x": 126.6375,
64 "y": 434.31666666666666
65 },
66 "duration": 3000
67 }
68 ]
2)每次事件循环执行代码都会计算一个坐标值
怎么计算新坐标?具体就是如下代码:
this.curTime += this.timeFreshTime;
let currentX = Easing.Linear(this.curTime, this.movePath.startPoint.x, this.movePath.endPoint.x - this.movePath.startPoint.x, this.movePath.duration);
let currentY = Easing.Linear(this.curTime, this.movePath.startPoint.y, this.movePath.endPoint.y - this.movePath.startPoint.y, this.movePath.duration);
利用当前时间,起点,终点。我们借助时间曲线easing库,里面的计算专为动画设计,还有我之前介绍过一个运算库《Tween算法及缓动效果》都是一样的。
代码参考如下:

1 export class Easing {
2 // t: current time(当前时间),
3 // b: beginning value(初始值),
4 // c: chang in value (变化量),
5 // d: duration(持续时间)
6 static Linear = function (t, b, c, d) { return c * t / d + b; };
7 static Quad = {
8 easeIn: function (t, b, c, d) {
9 return c * (t /= d) * t + b;
10 },
11 easeOut: function (t, b, c, d) {
12 return -c * (t /= d) * (t - 2) + b;
13 },
14 easeInOut: function (t, b, c, d) {
15 if ((t /= d / 2) < 1) return c / 2 * t * t + b;
16 return -c / 2 * ((--t) * (t - 2) - 1) + b;
17 }
18 };
19 static Cubic = {
20 easeIn: function (t, b, c, d) {
21 return c * (t /= d) * t * t + b;
22 },
23 easeOut: function (t, b, c, d) {
24 return c * ((t = t / d - 1) * t * t + 1) + b;
25 },
26 easeInOut: function (t, b, c, d) {
27 if ((t /= d / 2) < 1) return c / 2 * t * t * t + b;
28 return c / 2 * ((t -= 2) * t * t + 2) + b;
29 }
30 };
31 static Quart = {
32 easeIn: function (t, b, c, d) {
33 return c * (t /= d) * t * t * t + b;
34 },
35 easeOut: function (t, b, c, d) {
36 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
37 },
38 easeInOut: function (t, b, c, d) {
39 if ((t /= d / 2) < 1) return c / 2 * t * t * t * t + b;
40 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
41 }
42 };
43 static Quint = {
44 easeIn: function (t, b, c, d) {
45 return c * (t /= d) * t * t * t * t + b;
46 },
47 easeOut: function (t, b, c, d) {
48 return c * ((t = t / d - 1) * t * t * t * t + 1) + b;
49 },
50 easeInOut: function (t, b, c, d) {
51 if ((t /= d / 2) < 1) return c / 2 * t * t * t * t * t + b;
52 return c / 2 * ((t -= 2) * t * t * t * t + 2) + b;
53 }
54 };
55 static Sine = {
56 easeIn: function (t, b, c, d) {
57 return -c * Math.cos(t / d * (Math.PI / 2)) + c + b;
58 },
59 easeOut: function (t, b, c, d) {
60 return c * Math.sin(t / d * (Math.PI / 2)) + b;
61 },
62 easeInOut: function (t, b, c, d) {
63 return -c / 2 * (Math.cos(Math.PI * t / d) - 1) + b;
64 }
65 };
66 static Expo = {
67 easeIn: function (t, b, c, d) {
68 return (t == 0) ? b : c * Math.pow(2, 10 * (t / d - 1)) + b;
69 },
70 easeOut: function (t, b, c, d) {
71 return (t == d) ? b + c : c * (-Math.pow(2, -10 * t / d) + 1) + b;
72 },
73 easeInOut: function (t, b, c, d) {
74 if (t == 0) return b;
75 if (t == d) return b + c;
76 if ((t /= d / 2) < 1) return c / 2 * Math.pow(2, 10 * (t - 1)) + b;
77 return c / 2 * (-Math.pow(2, -10 * --t) + 2) + b;
78 }
79 };
80 static Circ = {
81 easeIn: function (t, b, c, d) {
82 return -c * (Math.sqrt(1 - (t /= d) * t) - 1) + b;
83 },
84 easeOut: function (t, b, c, d) {
85 return c * Math.sqrt(1 - (t = t / d - 1) * t) + b;
86 },
87 easeInOut: function (t, b, c, d) {
88 if ((t /= d / 2) < 1) return -c / 2 * (Math.sqrt(1 - t * t) - 1) + b;
89 return c / 2 * (Math.sqrt(1 - (t -= 2) * t) + 1) + b;
90 }
91 };
92 static Elastic = {
93 easeIn: function (t, b, c, d, a, p) {
94 var s;
95 if (t == 0) return b;
96 if ((t /= d) == 1) return b + c;
97 if (typeof p == "undefined") p = d * .3;
98 if (!a || a < Math.abs(c)) {
99 s = p / 4;
100 a = c;
101 } else {
102 s = p / (2 * Math.PI) * Math.asin(c / a);
103 }
104 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
105 },
106 easeOut: function (t, b, c, d, a, p) {
107 var s;
108 if (t == 0) return b;
109 if ((t /= d) == 1) return b + c;
110 if (typeof p == "undefined") p = d * .3;
111 if (!a || a < Math.abs(c)) {
112 a = c;
113 s = p / 4;
114 } else {
115 s = p / (2 * Math.PI) * Math.asin(c / a);
116 }
117 return (a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b);
118 },
119 easeInOut: function (t, b, c, d, a, p) {
120 var s;
121 if (t == 0) return b;
122 if ((t /= d / 2) == 2) return b + c;
123 if (typeof p == "undefined") p = d * (.3 * 1.5);
124 if (!a || a < Math.abs(c)) {
125 a = c;
126 s = p / 4;
127 } else {
128 s = p / (2 * Math.PI) * Math.asin(c / a);
129 }
130 if (t < 1) return -.5 * (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
131 return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
132 }
133 };
134 static Back = {
135 easeIn: function (t, b, c, d, s) {
136 if (typeof s == "undefined") s = 1.70158;
137 return c * (t /= d) * t * ((s + 1) * t - s) + b;
138 },
139 easeOut: function (t, b, c, d, s) {
140 if (typeof s == "undefined") s = 1.70158;
141 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
142 },
143 easeInOut: function (t, b, c, d, s) {
144 if (typeof s == "undefined") s = 1.70158;
145 if ((t /= d / 2) < 1) return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
146 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
147 }
148 };
149 static Bounce = {
150 easeIn: function (t, b, c, d) {
151 return c - Easing.Bounce.easeOut(d - t, 0, c, d) + b;
152 },
153 easeOut: function (t, b, c, d) {
154 if ((t /= d) < (1 / 2.75)) {
155 return c * (7.5625 * t * t) + b;
156 } else if (t < (2 / 2.75)) {
157 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
158 } else if (t < (2.5 / 2.75)) {
159 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
160 } else {
161 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
162 }
163 },
164 easeInOut: function (t, b, c, d) {
165 if (t < d / 2) {
166 return Easing.Bounce.easeIn(t * 2, 0, c, d) * .5 + b;
167 } else {
168 return Easing.Bounce.easeOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
169 }
170 }
171 }
172 }
Easing
3)当前坐标点已计算更新,此时在新位置处绘制白色点,我们的事件循序间隔设置的50ms,所有能够产生平滑移动的效果。
4)实际需要几个移动的白点,那就需要定义几个path。如上gif图中我们有两个path,这两个path初始化的时间是错开的,所有才产生非同步移动的效果。
5)当一个path走完,再让其从头走(path的第一个startPoint endPoint),这样不断地循环下去。
canvas绘制动画的技巧的更多相关文章
- Android中使用SurfaceView和Canvas来绘制动画
事实上每一个View中都有Canvas能够用来绘制动画.仅仅须要在这个View中重载onDraw()方法就能够,可是SurfaceView类是一个专门用来制动动画的类. Canvas(中文叫做&quo ...
- canvas绘制简易动画
在canvas画布中制作动画相对来说很简单,实际上就是不断变化的坐标.擦除.重绘的过程 1.使用setInterval方法设置动画的间隔时间. setInterval(code,millisec) s ...
- canvas 绘制双线技巧
楔子 最近一个项目,需要绘制双线的效果,双线效果表示的是轨道(类似铁轨之类的),如下图所示: 负责这块功能开发的小伙,姑且称之为L吧,最开始是通过数学计算的方式来实现这种双线,也就是在原来的路径的基础 ...
- 第165天:canvas绘制圆环旋转动画
canvas绘制圆环旋转动画——面向对象版 1.HTML 注意引入Konva.js库 <!DOCTYPE html> <html lang="en"> &l ...
- h5学习-canvas绘制矩形、圆形、文字、动画
绘制矩形<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8 ...
- canvas绘制折线路径动画
最近有读者加我微信咨询这个问题: 其中的效果是一个折线路径动画效果,如下图所示: 要实现以上路径动画,一般可以使用svg的动画功能.或者使用canvas绘制,结合路径数学计算来实现. 如果用canva ...
- canvas小球动画
绘制小球 我们将会画一个小球用于动画学习,所以首先在画布上画一个球.下面的代码帮助我们建立画布. <canvas id="></canvas> 跟平常一样,我们需要先 ...
- 使用Canvas绘制背景图
原文 http://www.imququ.com/post/use-canvas-as-background-image.html 最近iCloud Web的Beta版换了UI,整体风格变得和iOS ...
- 使用 HTML5 Canvas 绘制出惊艳的水滴效果
HTML5 在不久前正式成为推荐标准,标志着全新的 Web 时代已经来临.在众多 HTML5 特性中,Canvas 元素用于在网页上绘制图形,该元素标签强大之处在于可以直接在 HTML 上进行图形操作 ...
随机推荐
- 数据库和SQL概述
一.数据库的概念 1.DB 数据库(database):存储数据的"仓库".它保存了一系列有组织的数据. 2.DBMS 数据库管理系统(Database Management Sy ...
- 问渠那得清如许?为有源头活水来——对【近取Key】产品进行的深度测评与解析
在 Build To Show 的场景中,大家各显身手,用各种办法展现技术,的确很难在单一的维度上确定谁赢谁输.但是,在 Build To Win 的场景中,往往市场就是那么一块, 竞争对手占了 70 ...
- [re模块、json&pickle模块]
[re模块.json&pickle模块] re模块 什么是正则? 正则就是用一些具有特殊含义的符号组合到一起(称为正则表达式)来描述字符或者字符串的方法.或者说:正则就是用来描述一类事物的规则 ...
- [bug] conda:Segmentation fault (core dumped)
参考 https://www.jianshu.com/p/5e230ef8a14d
- [Python] RPC实现
单线程同步 使用socket传输数据 使用json序列化消息体 struct将消息编码为二进制字节串,进行网络传输 消息协议 1 // 输入 2 { 3 in: "ping", 4 ...
- [前端] AJAX
背景 Asynchronous JavaScript And XML:异步js和XML,可实现异步刷新 用途 验证提交的用户名是否已存在 不使用AJAX,需要提交数据后,刷新页面来验证 使用AJAX, ...
- mate桌面用户 root 自动登录lightdm.conf -20190520 方法【fedora 21】mate
桌面用户自动登录lightdm.conf -20190520 方法修改 /etc/lightdm/lightdm.conf 步骤:1 vim /etc/lightdm/lightdm.conf 解除 ...
- stressapptest测试用例testcase方法aarch64
### https://github.com/stressapptest/stressapptest aarch64 To build from source, the build/installat ...
- who -b
~]# who -b 系统引导 2020-05-03 19:57[root@localhost ~]# who -r 运行级别 5 2020-05-03 19:58
- 《SystemVerilog验证-测试平台编写指南》学习 - 第2章 数据类型
<SystemVerilog验证-测试平台编写指南>学习 - 第2章 数据类型 2.1 内建数据类型 2.2 定宽数组 2.2.1 声明 2.2.2 常量数组 2.2.3 基本的数组操作 ...