贝塞尔曲线方程使用姿势

1.贝塞尔曲线方程

贝塞尔曲线方程是应用于二维图形的数学曲线,在前端一些动画效果中,贝塞尔曲线也有很多应用场景,不如大转盘之类的页面;

前端用的比较多是三次方的贝塞尔曲线方程

一个标准的3次贝塞尔曲线需要4个点:起始点、终止点(也称锚点)以及两个相互分离的中间点。

http://cubic-bezier.com/

上面的网站是给你提供贝塞尔中间2点的坐标,起点和终点默认(0,0)(0,1)

公式:

其中P0,P1,P2,P3都是二维xy向量, 拆开可以变成:

1
2
y = (1-t)^3*P0y + 3*(1-t)^2*t*P1y + 3*(1-t)*t^2P2y + t^3P3y;
x = (1-t)^3*P0x + 3*(1-t)^2*t*P1x + 3*(1-t)*t^2P2x + t^3P3x;

其中 P0 = (0,0), P3 = (1,1) ,然后代入后化简公式为:

1
2
// x = 3p1xt(1-t)^2 + 3p2xt^2*(1-t) + t^3
// y = 3p1yt(1-t)^2 + 3p2yt^2*(1-t) + t^3

根据公式然后和程序结合, 使用比较老土的二分法求值, 已知x求t,再根据t求y, 代码如下

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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
*{padding: 0; margin: 0;}
.box{
position: absolute;
left: 0;
right: 0;
bottom: 0;
top: 0;
width: 900px;
height: 800px;
margin: auto;
border: 1px solid #ccc;
}
.box div{
width: 100px;
height: 100px;
background: #f00;
margin-top: 40px;
}
</style>
</head>
<body>

<div class="box">
<div class="block1"></div>
<div class="block2"></div>
<div class="block3"></div>
</div>



<script
src="http://code.jquery.com/jquery-2.2.4.min.js"></script>
<script>
function Bezier(p1x,p1y,p2x,p2y){//贝塞尔求值
this.p1x = p1x;
this.p1y = p1y;
this.p2x = p2x;
this.p2y = p2y;
this.epsilon = 1e-6;

this.Solve = function(x){
var t0 = 0;
var t1 = 1;
var t = x;

while (Math.abs(this.getX(t) - x) > this.epsilon){
var x2 = this.getX(t)
if(x2 > x){
t1 = t
}else{
t0 = t
}
t = (t1-t0)/2 + t0
}

return this.getY(t)
}
this.getX = function(t){
return 3*this.p1x*Math.pow(1-t,2)*t + 3*this.p2x*Math.pow(t, 2)*(1-t) + Math.pow(t, 3)
}
this.getY = function(t){
return 3*this.p1y*Math.pow(1-t,2)*t + 3*this.p2y*Math.pow(t, 2)*(1-t) + Math.pow(t, 3)
}
}


window.onload = function(){ //加载各种运动
$(".block1").animate({marginLeft: 611}, 2000, 'linear') //jq匀速运动
animateJs()
animateBezier()
}

function animateJs(){ //普通匀速运动
var block = document.querySelector(".block2");
var start = 0;
var end = 611;
var deration = 2000;
var startTime = (+new Date())
var endTime = startTime + deration;

var loop = setInterval(function(){
var nowTime = (+new Date())
var remind = Math.max(endTime - nowTime, 0);
var percent = 1-(remind/deration);
block.style.marginLeft = percent*end+ "px"
if(percent == 1){
clearInterval(loop)
return
}
}, 13)
}

function animateBezier(){ //贝塞尔曲线运动,先慢后快再慢,可以作为大转盘运动模式
var block = document.querySelector(".block3");
var start = 0;
var end = 611;
var deration = 2000;
var startTime = (+new Date())
var endTime = startTime + deration;
var bezier = new Bezier(.92,.24,.13,.84);
var loop = setInterval(function(){
var nowTime = (+new Date())
var remind = Math.max(endTime - nowTime, 0);
var percent = 1-(remind/deration);

block.style.marginLeft = bezier.Solve(percent)*end+ "px"

if(percent == 1){
clearInterval(loop)
return
}
}, 13)
}
</script>
</body>
</html>

是不是简单得不得了,一个函数就可以解决贝塞尔曲线运动求值了,其实还有更方便的方法,在css3里面已经封装好贝塞尔给大伙直接调用了,大家可以连思考都不用思考直接用哈, 直接在css transition里写就可以了!

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
*{padding: 0; margin: 0;}

.box{
position: absolute;
left: 0;
right: 0;
bottom: 0;
top: 0;
width: 660px;
height: 660px;
margin: auto;
}
.box .img1{
position: absolute;
left: 0;
top: 0;
width: 100%;
display: block;
}
.box .img2{
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
margin: auto;
transition: all 10s cubic-bezier(.92,.24,.13,.84);
}
</style>
</head>
<body>

<div class="box">
<img class="img1" src="https://yuanxiaosi.github.io/blog/2017/09/15/170915-%E8%B4%9D%E5%A1%9E%E5%B0%94%E6%9B%B2%E7%BA%BF/pan1.png" />
<img class="img2" src="https://yuanxiaosi.github.io/blog/2017/09/15/170915-%E8%B4%9D%E5%A1%9E%E5%B0%94%E6%9B%B2%E7%BA%BF/pan2.png" />
</div>

<script>

function animateJs(){
var img2 = document.querySelector(".img2");
img2.style.webkitTransform = "rotateZ(4000deg)"
}

window.onload = function(){
animateJs()
}
</script>
</body>
</html>