渐开线(evolent):在平面上,一条动直线(发生线)沿着一个固定的圆(基圆)作滚动的过程中,此直线上任意一点的轨迹,称为此基圆的一条渐开线。如果将一个圆轴固定在一个平面上,轴上缠线,拉紧一个线头,让该线绕圆轴运动且始终与圆轴相切,那么线上一个定点在该平面上的轨迹就是渐开线。上图中红色粗线是渐开线的轨迹。
下面是实现代码,代码采用了JS类的设计以分离数据和表现:
<!DOCTYPE html> <html lang="utf-8"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <head> <title>渐开线</title> </head> <body onload="draw()"> <canvas id="myCanvus" width="800px" height="800px" style="border:1px dashed black;"> 出现文字表示你的浏览器不支持HTML5 </canvas> </body> </html> <script type="text/javascript"> <!-- function draw(){ var canvas=document.getElementById('myCanvus'); canvas.width=800; canvas.height=800; context=canvas.getContext('2d'); context.translate(400,200); var e=new evolent(); e.updateCds(10); e.paintInnerCircle(context); e.paintTriangles(context); e.paintCurve(context); }; // 渐开线类 function evolent(){ var obj=new Object; // 属性 obj.radius=50;// 内圆半径 obj.initLen=20;// 初始线长 obj.turnAngle=30;// 转角 obj.cds=[{}];// 坐标数组 obj.paintInnerCircle=function(context){ context.strokeStyle = "black"; context.arc(0,0,this.radius,0,Math.PI*2); context.stroke(); }; // 画三角形 obj.paintTriangles=function(context){ for(var i=0; i<this.cds.length; i++){ context.strokeStyle = getColor(i % 15); context.beginPath(); context.moveTo(0, 0); context.lineTo(this.cds[i].x1,this.cds[i].y1); context.lineTo(this.cds[i].x2,this.cds[i].y2); context.closePath(); context.stroke(); } }; // 画渐开线曲线 obj.paintCurve=function(context){ context.lineWidth=2; context.strokeStyle = "red"; context.beginPath(); for(var i=0; i<this.cds.length; i++){ context.lineTo(this.cds[i].x2,this.cds[i].y2); } //context.closePath(); context.stroke(); }; // 设定渐开线坐标 obj.updateCds=function(count){ this.cds.pop(); for(var i=0;i<count;i++){ var theta=i*this.turnAngle; var x1=this.radius*Math.cos(getRad(theta)); var y1=this.radius*Math.sin(getRad(theta)); var leg=this.initLen+theta/360*2*Math.PI*this.radius; var delta=Math.atan(this.initLen/this.radius+theta/360*2*Math.PI); var hypotenuse=Math.sqrt(this.radius*this.radius+leg*leg); var angle=getRad(theta)-delta; var x2=hypotenuse*Math.cos(angle); var y2=hypotenuse*Math.sin(angle); var arr={"x1":x1,"y1":y1,"x2":x2,"y2":y2}; this.cds.push(arr); } }; return obj; } function animate(){ // 让浏览器自行决定帧速率 window.requestAnimationFrame(animate); } // 角度得到弧度 function getRad(degree){ return degree/180*Math.PI; } // 得到颜色 function getColor(index){ if(index==0){ return "green"; }else if(index==1){ return "silver"; }else if(index==2){ return "lime"; }else if(index==3){ return "gray"; }else if(index==4){ return "white"; }else if(index==5){ return "yellow"; }else if(index==6){ return "maroon"; }else if(index==7){ return "navy"; }else if(index==8){ return "red"; }else if(index==9){ return "blue"; }else if(index==10){ return "purple"; }else if(index==11){ return "teal"; }else if(index==12){ return "fuchsia"; }else if(index==13){ return "aqua"; }else if(index==14){ return "black"; } } //--> </script>