会动的齿轮
先上效果
用js里面的canas实现的,实际效果齿轮会动,还是比较有意思的,再配点音乐,那就完美了。
问题解析
js里面的canas知识大家可以参看https://www.runoob.com/html/html5-canvas.html,我这里就不介绍了,通过图形我们可以看出我们有两类齿轮,一类是外圈橘黄色的,一类是里面蓝色的。
大齿轮解析
大齿轮外圈是个圆,直接用arc画就行了,现在的问题主要是内圈的实现,我们看个大一点齿的外圈图:
针对一个齿来分析,建立坐标系,如下图:
可以看到D1ABCD可以构成一个最小单元的齿,我们只要将这个齿旋转进行循环旋转以后就可以得到外圈的内齿了,现在我们假定O圆心坐标为(x,y),内圆半径OT为r1,外圆半径OD1=r2,每个锯齿和锯齿间空隙对应的圆心角为w0,其中T是AB的中点,AT=BT=d,在这些条件下,容易得到下面的坐标:
x
T
=
r
1
∗
c
o
s
(
w
0
/
2
)
+
x
x_T=r_1*cos(w_0/2)+x
xT=r1∗cos(w0/2)+x
y
T
=
r
1
∗
s
i
n
(
w
0
/
2
)
+
y
y_T=r_1*sin(w_0/2)+y
yT=r1∗sin(w0/2)+y
则可以得到A,B坐标
x
A
=
r
1
∗
c
o
s
(
w
0
/
2
)
+
x
+
d
∗
s
i
n
(
w
0
/
2
)
x_A=r_1*cos(w_0/2)+x+d*sin(w_0/2)
xA=r1∗cos(w0/2)+x+d∗sin(w0/2)
y
A
=
r
1
∗
s
i
n
(
w
0
/
2
)
+
y
−
d
∗
c
o
s
(
w
0
/
2
)
y_A=r_1*sin(w_0/2)+y-d*cos(w_0/2)
yA=r1∗sin(w0/2)+y−d∗cos(w0/2)
x
B
=
r
1
∗
c
o
s
(
w
0
/
2
)
+
x
−
d
∗
s
i
n
(
w
0
/
2
)
x_B=r_1*cos(w_0/2)+x-d*sin(w_0/2)
xB=r1∗cos(w0/2)+x−d∗sin(w0/2)
y
B
=
r
1
∗
s
i
n
(
w
0
/
2
)
+
y
+
d
∗
c
o
s
(
w
0
/
2
)
y_B=r_1*sin(w_0/2)+y+d*cos(w_0/2)
yB=r1∗sin(w0/2)+y+d∗cos(w0/2)
C点和D点都在外圆上,因此坐标为:
x
C
=
r
2
∗
c
o
s
(
w
0
)
+
x
x_C=r_2*cos(w_0)+x
xC=r2∗cos(w0)+x
y
C
=
r
2
∗
s
i
n
(
w
0
)
+
y
y_C=r_2*sin(w_0)+y
yC=r2∗sin(w0)+y
x
D
=
r
2
∗
c
o
s
(
2
∗
w
0
)
+
x
x_D=r_2*cos(2*w_0)+x
xD=r2∗cos(2∗w0)+x
y
D
=
r
2
∗
s
i
n
(
2
∗
w
0
)
+
y
y_D=r_2*sin(2*w_0)+y
yD=r2∗sin(2∗w0)+y
思考为了使这个齿轮转动起来,那没初始角就不一定是0了,即D1不在坐标轴上,还有一个夹角,上面的坐标只需要把里面的角都加上初始角w0就可以了,按照这个思路用js实现代码如下:
function gear1(ctx,x,y,r1,r2,n,d,p0){
/*
ctx:用于画图的对象
x,y:圆心的坐标
r1:齿轮内元半径
r2:齿轮外圆半径
n:齿轮及间隔平分数量
d:齿的凸起的半距离
p0:初始角度
*/
var x0=x+r2;
var y0=y;
//每个齿对应的圆心角
var w0=2*Math.PI/n;
var w1=p0;
var w2=w0/2;
var rw=10;
ctx.beginPath();
ctx.arc(x,y,r2+10,0,2*Math.PI);
ctx.fillStyle="#ff7f50";
ctx.fill();
ctx.stroke();
ctx.beginPath();
ctx.arc(x,y,rw,0,2*Math.PI);
ctx.stroke();
ctx.beginPath();
//移动至初始位置
var Ax=r2*Math.cos(w1)+x;
var Ay=r2*Math.sin(w1)+y;
ctx.moveTo(Ax,Ay);
for(var i=0;i<n/2;i++){
w2=w1+w0/2;//初始夹角
//A点坐标
var Ax=r1*Math.cos(w2)+d*Math.sin(w2)+x;
var Ay=r1*Math.sin(w2)-d*Math.cos(w2)+y;
//B点坐标
var Bx=r1*Math.cos(w2)-d*Math.sin(w2)+x;
var By=r1*Math.sin(w2)+d*Math.cos(w2)+y;
//C点坐标
var w1=w1+w0;
var Cx=r2*Math.cos(w1)+x;
var Cy=r2*Math.sin(w1)+y;
//D点坐标
var w1=w1+w0;
var Dx=r2*Math.cos(w1)+x;
var Dy=r2*Math.sin(w1)+y;
//连线
ctx.lineTo(Ax,Ay);
ctx.lineTo(Bx,By);
ctx.lineTo(Cx,Cy);
ctx.lineTo(Dx,Dy);
}
ctx.stroke();
ctx.fillStyle="#ffffff";
ctx.fill();
}
小齿轮解析
小齿轮和大齿轮类似,不过小齿轮的齿是向外凸的,所以建立坐标系分析如下:
可以看到D1ABCD可以构成一个最小单元的齿,我们只要将这个齿旋转进行循环旋转以后就可以得到外圈的内齿了,现在我们假定O圆心坐标为(x,y),内圆半径OD1为r1,外圆半径OT=r2,每个锯齿和锯齿间空隙对应的圆心角为w0,其中T是AB的中点,AT=BT=d,在这些条件下,容易得到下面的坐标:
x
T
=
r
2
∗
c
o
s
(
w
0
/
2
)
+
x
x_T=r_2*cos(w_0/2)+x
xT=r2∗cos(w0/2)+x
y
T
=
r
2
∗
s
i
n
(
w
0
/
2
)
+
y
y_T=r_2*sin(w_0/2)+y
yT=r2∗sin(w0/2)+y
则可以得到A,B坐标
x
A
=
r
2
∗
c
o
s
(
w
0
/
2
)
+
x
+
d
∗
s
i
n
(
w
0
/
2
)
x_A=r_2*cos(w_0/2)+x+d*sin(w_0/2)
xA=r2∗cos(w0/2)+x+d∗sin(w0/2)
y
A
=
r
2
∗
s
i
n
(
w
0
/
2
)
+
y
−
d
∗
c
o
s
(
w
0
/
2
)
y_A=r_2*sin(w_0/2)+y-d*cos(w_0/2)
yA=r2∗sin(w0/2)+y−d∗cos(w0/2)
x
B
=
r
2
∗
c
o
s
(
w
0
/
2
)
+
x
−
d
∗
s
i
n
(
w
0
/
2
)
x_B=r_2*cos(w_0/2)+x-d*sin(w_0/2)
xB=r2∗cos(w0/2)+x−d∗sin(w0/2)
y
B
=
r
2
∗
s
i
n
(
w
0
/
2
)
+
y
+
d
∗
c
o
s
(
w
0
/
2
)
y_B=r_2*sin(w_0/2)+y+d*cos(w_0/2)
yB=r2∗sin(w0/2)+y+d∗cos(w0/2)
C点和D点都在外圆上,因此坐标为:
x
C
=
r
1
∗
c
o
s
(
w
0
)
+
x
x_C=r_1*cos(w_0)+x
xC=r1∗cos(w0)+x
y
C
=
r
1
∗
s
i
n
(
w
0
)
+
y
y_C=r_1*sin(w_0)+y
yC=r1∗sin(w0)+y
x
D
=
r
1
∗
c
o
s
(
2
∗
w
0
)
+
x
x_D=r_1*cos(2*w_0)+x
xD=r1∗cos(2∗w0)+x
y
D
=
r
1
∗
s
i
n
(
2
∗
w
0
)
+
y
y_D=r_1*sin(2*w_0)+y
yD=r1∗sin(2∗w0)+y
思考为了使这个齿轮转动起来,那没初始角就不一定是0了,即D1不在坐标轴上,还有一个夹角,上面的坐标只需要把里面的角都加上初始角w0就可以了,按照这个思路用js实现代码如下:
function gear(ctx,x,y,r1,r2,n,d,p0){
/*
ctx:用于画图的对象
x,y:圆心的坐标
r1:齿轮内元半径
r2:齿轮外圆半径
n:齿轮及间隔平分数量
d:齿的凸起的半距离
p0:初始角度
*/
var x0=x+r2;
var y0=y;
var w0=2*Math.PI/n;
var w1=p0;
var w2=w0/2;
var rw=10;
ctx.beginPath();
//移动至初始位置D1
var D1x=r1*Math.cos(w1)+x;
var D1y=r1*Math.sin(w1)+y;
ctx.moveTo(D1x,D1y);
for(var i=0;i<n/2;i++){
w2=w1+w0/2;
//A点坐标
var Ax=r2*Math.cos(w2)+d*Math.sin(w2)+x;
var Ay=r2*Math.sin(w2)-d*Math.cos(w2)+y;
//B点坐标
var Bx=r2*Math.cos(w2)-d*Math.sin(w2)+x;
var By=r2*Math.sin(w2)+d*Math.cos(w2)+y;
var w1=w1+w0;
//C点坐标
var Cx=r1*Math.cos(w1)+x;
var Cy=r1*Math.sin(w1)+y;
var w1=w1+w0;
//D点坐标
var Dx=r1*Math.cos(w1)+x;
var Dy=r1*Math.sin(w1)+y;
//连线
ctx.lineTo(Ax,Ay);
ctx.lineTo(Bx,By);
ctx.lineTo(Cx,Cy);
ctx.lineTo(Dx,Dy);
}
ctx.stroke();
ctx.fillStyle="#00BFFF";
ctx.closePath();
ctx.fill();
ctx.beginPath();
ctx.fillStyle="#808080";
ctx.arc(x,y,rw,0,2*Math.PI);//内部小圆
ctx.closePath();
ctx.fill();
}
齿轮位置
可以看出圆心的位置构成一个等边三角形,因此我们可以画出下面坐标:
假设A坐标为(x,y),该等边三角形边长为a,则我们容易求出其他几个点坐标:
x
B
=
x
+
a
x_B=x+a
xB=x+a
y
B
=
y
y_B=y
yB=y
x
C
=
x
+
a
2
x_C=x+\frac{a}{2}
xC=x+2a
y
C
=
y
+
a
∗
s
i
n
(
π
3
)
y_C=y+a*sin(\frac{π}{3})
yC=y+a∗sin(3π)
x
D
=
x
+
a
2
x_D=x+\frac{a}{2}
xD=x+2a
y
D
=
y
+
a
2
∗
t
a
n
(
π
6
)
y_D=y+\frac{a}{2}*tan(\frac{π}{6})
yD=y+2a∗tan(6π)
由此我们可以形成这段代码:
function load(){
n=0;
setInterval(function(){
var c=document.getElementById("mycanvas");
var ctx=c.getContext("2d");
ctx.fillStyle="#00BFFF";
ctx.clearRect(0,0,c.width,c.height);
var bl=200;
var x1=200;//A点坐标
var y1=200;
var x2=x1+bl;//B点坐标
var y2=y1;
var x3=x1+bl*Math.cos(Math.PI/3);//C点坐标
var y3=y1+bl*Math.sin(Math.PI/3);
var x4=x1+bl*Math.cos(Math.PI/3);//D点坐标
var y4=y1+Math.tan(Math.PI/6)*bl/2;
p0=2*Math.PI/64*n;
p1=-p0/2;
p2=-p0/5+2*Math.PI/32*2;
gear1(ctx,x3,y4,185,195,80,5,p2);
gear(ctx,x1,y1,70,80,32,5,p1);
gear(ctx,x2,y2,70,80,32,5,p1);
gear(ctx,x3,y3,70,80,32,5,p1);
gear(ctx,x3,y4,35,45,16,5,p0);
n++;
if(n==64){
n=0;
}
},20);
}
解释下齿数与角度的关系,外圈40齿(80份),内部相同的三个都是16齿(32份),中心齿轮是8齿(16份),因此齿数比是5:2:1,齿数多的转速就慢,因此他们的角速度比应该是:1:2:5,当然初始角度需要根据实际情况做一个调整,让齿轮能啮合在一起,最后把整体代码贴出来:
<!DOCTYPE HTML>
<html>
<head>
<title>ta</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<script type="text/javascript">
function load(){
n=0;
setInterval(function(){
var c=document.getElementById("mycanvas");
var ctx=c.getContext("2d");
ctx.fillStyle="#00BFFF";
ctx.clearRect(0,0,c.width,c.height);
var bl=200;
var x1=200;//A点坐标
var y1=200;
var x2=x1+bl;//B点坐标
var y2=y1;
var x3=x1+bl*Math.cos(Math.PI/3);//C点坐标
var y3=y1+bl*Math.sin(Math.PI/3);
var x4=x1+bl*Math.cos(Math.PI/3);//D点坐标
var y4=y1+Math.tan(Math.PI/6)*bl/2;
p0=2*Math.PI/64*n;
p1=-p0/2;
p2=-p0/5+2*Math.PI/32*2;
gear1(ctx,x3,y4,185,195,80,5,p2);
gear(ctx,x1,y1,70,80,32,5,p1);
gear(ctx,x2,y2,70,80,32,5,p1);
gear(ctx,x3,y3,70,80,32,5,p1);
gear(ctx,x3,y4,35,45,16,5,p0);
n++;
if(n==64){
n=0;
}
},20);
}
function gear(ctx,x,y,r1,r2,n,d,p0){
/*
ctx:用于画图的对象
x,y:圆心的坐标
r1:齿轮内元半径
r2:齿轮外圆半径
n:齿轮及间隔平分数量
d:齿的凸起的半距离
p0:初始角度
*/
var x0=x+r2;
var y0=y;
var w0=2*Math.PI/n;
var w1=p0;
var w2=w0/2;
var rw=10;
ctx.beginPath();
//移动至初始位置D1
var D1x=r1*Math.cos(w1)+x;
var D1y=r1*Math.sin(w1)+y;
ctx.moveTo(D1x,D1y);
for(var i=0;i<n/2;i++){
w2=w1+w0/2;
//A点坐标
var Ax=r2*Math.cos(w2)+d*Math.sin(w2)+x;
var Ay=r2*Math.sin(w2)-d*Math.cos(w2)+y;
//B点坐标
var Bx=r2*Math.cos(w2)-d*Math.sin(w2)+x;
var By=r2*Math.sin(w2)+d*Math.cos(w2)+y;
var w1=w1+w0;
//C点坐标
var Cx=r1*Math.cos(w1)+x;
var Cy=r1*Math.sin(w1)+y;
var w1=w1+w0;
//D点坐标
var Dx=r1*Math.cos(w1)+x;
var Dy=r1*Math.sin(w1)+y;
//连线
ctx.lineTo(Ax,Ay);
ctx.lineTo(Bx,By);
ctx.lineTo(Cx,Cy);
ctx.lineTo(Dx,Dy);
}
ctx.stroke();
ctx.fillStyle="#00BFFF";
ctx.closePath();
ctx.fill();
ctx.beginPath();
ctx.fillStyle="#808080";
ctx.arc(x,y,rw,0,2*Math.PI);//内部小圆
ctx.closePath();
ctx.fill();
}
function gear1(ctx,x,y,r1,r2,n,d,p0){
/*
ctx:用于画图的对象
x,y:圆心的坐标
r1:齿轮内元半径
r2:齿轮外圆半径
n:齿轮及间隔平分数量
d:齿的凸起的半距离
p0:初始角度
*/
var x0=x+r2;
var y0=y;
//每个齿对应的圆心角
var w0=2*Math.PI/n;
var w1=p0;
var w2=w0/2;
var rw=10;
ctx.beginPath();
ctx.arc(x,y,r2+10,0,2*Math.PI);
ctx.fillStyle="#ff7f50";
ctx.fill();
ctx.stroke();
ctx.beginPath();
ctx.arc(x,y,rw,0,2*Math.PI);
ctx.stroke();
ctx.beginPath();
//移动至初始位置
var D1x=r2*Math.cos(w1)+x;
var D1y=r2*Math.sin(w1)+y;
ctx.moveTo(D1x,D1y);
for(var i=0;i<n/2;i++){
w2=w1+w0/2;//初始夹角
//A点坐标
var Ax=r1*Math.cos(w2)+d*Math.sin(w2)+x;
var Ay=r1*Math.sin(w2)-d*Math.cos(w2)+y;
//B点坐标
var Bx=r1*Math.cos(w2)-d*Math.sin(w2)+x;
var By=r1*Math.sin(w2)+d*Math.cos(w2)+y;
//C点坐标
var w1=w1+w0;
var Cx=r2*Math.cos(w1)+x;
var Cy=r2*Math.sin(w1)+y;
//D点坐标
var w1=w1+w0;
var Dx=r2*Math.cos(w1)+x;
var Dy=r2*Math.sin(w1)+y;
//连线
ctx.lineTo(Ax,Ay);
ctx.lineTo(Bx,By);
ctx.lineTo(Cx,Cy);
ctx.lineTo(Dx,Dy);
}
ctx.stroke();
ctx.fillStyle="#ffffff";
ctx.fill();
}
</script>
<body onload="load()">
<canvas id="mycanvas" width="800" height="800"></canvas>
</body>
</html>