-
Notifications
You must be signed in to change notification settings - Fork 0
/
cubic.js
60 lines (56 loc) · 1.62 KB
/
cubic.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
let progress = 0
class Cubic {
constructor (a, b, c, d) {
this.px3 = 3 * a
this.px2 = 3 * (c - a) - this.px3
this.px1 = 1 - this.px3 - this.px2
this.py3 = 3 * b
this.py2 = 3 * (d - b) - this.py3
this.py1 = 1 - this.py3 - this.py2
this.epsilon = 1e-7 // 目标精度
}
getX(t) {
return ((this.px1 * t + this.px2) * t + this.px3) * t
}
getY(t) {
return ((this.py1 * t + this.py2) * t + this.py3) * t
}
solve(x) {
if (x === 0 || x === 1) { // 对 0 和 1 两个特殊 t 不做计算
return this.getY(x)
}
let t = x
for (let i = 0; i < 8; i++) { // 进行 8 次迭代
let g = this.getX(t) - x
if (Math.abs(g) < this.epsilon) { // 检测误差到可以接受的范围
return this.getY(t)
}
let d = (3 * this.px1 * t + 2 * this.px2) * t + this.px3 // 对 x 求导
if (Math.abs(d) < 1e-6) { // 如果梯度过低,说明牛顿迭代法无法达到更高精度
break
}
t = t - g / d
}
return this.getY(t) // 对得到的近似 t 求 y
}
}
/**
*
* @param {*} startTime 起始时间
* @param {*} totalTime 共需时间
* @param {*} startPX 起始值
* @param {*} totalPX 最终值
* @returns
*/
function init(startTime, totalTime, startPX, totalPX){
let cubic = new Cubic(.23,.75,.64,.98);
function getCurrent(time){
progress = (time - startTime) / totalTime;
if (progress >= 1) {
progress = 1
}
const result = cubic.solve(progress) * (totalPX - startPX) + startPX;
return Math.round(result)
}
return getCurrent;
}