【作品】Function Curve 2.0
【功能】
一款用于绘制函数图像的工具,只要能写出解析式和定义域,函数图线将自动为您生成。
【版本】
2.0
【截图】

【代码】
<!DOCTYPE html> <html lang="utf-8"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <head> <title>标题</title> <style type="text/css"> .canvasDiv{ margin:0 auto; border:0px solid red; width:1200px;height:600px; } </style> </head> <body onload="draw();"> <div class="canvasDiv"> <canvas id="myCanvas" width="10px" height="10px" style="border:0px dashed black;"> 如果看到这段文字说明您的浏览器尚不支持HTML5 Canvas,请更换浏览器再试. </canvas> </div> </body> </html> <script type="text/javascript"> <!-- /***************************************************************** * Function Curve 2.0 * 一款用于绘制函数图像的工具,只要能写出解析式和定义域,函数图线将 * 自动为您生成。 * * 作者:逆火狂飙 * 官方主页:https://www.cnblogs.com/heyang78/p/3292777.html * * 用法:拷贝本文件全部代码,粘贴到文本编辑器中,另存为.html文件, * 再用chrome浏览器打开,就能看到效果。 ******************************************************************/ // 可以手动调整的量定义处 const TITLE="Draft14 y=e^x/x"; // 图像标题 const WIDTH=1200; // 画布宽度,请根据您的浏览器高宽设定 const HEIGHT=600; // 画布高度,请根据您的浏览器高宽设定 const TIME_END=10000; // 动画运作的期限,单位毫秒(1000毫秒=1秒) const SCALE_UNIT_X=180; // 缩放比例 25对应x∈[-24,24],100对应x∈[-6,6] const SCALE_UNIT_Y=60; // 缩放比例 25对应y∈[-24,24],100对应y∈[-6,6] var ZERO_POINT=createPt(-1,-3); // 原点位置(虚拟坐标,是估计值) // 系统变量定义处,慎重修改 var X_PRECISION=0.01; // 横坐标右移的精度值 var context=0; // 画布环境 var stage; // 舞台对象 var timeElapsed=0; // 动画运作的的时间 var mousePos=createPt(0,0); // 鼠标位置 /*------------------------------------------------------------------------ 绘图系统函数:Canvas开始运作,由body_onload调用 ------------------------------------------------------------------------*/ function draw(){ document.title=TITLE; // 画图前初始化 var canvas=document.getElementById('myCanvas'); canvas.width=WIDTH; canvas.height=HEIGHT; context=canvas.getContext('2d'); // 进行屏幕坐标系到笛卡尔坐标系的变换 // 处置完成前,原点在左上角,向右为X正向,向下为Y的正向 // 处置完毕后,原点移动到画布中央,向右为X正向,向上为Y的正向 context.translate(WIDTH/2,HEIGHT/2); context.rotate(Math.PI); context.scale(-1,1); // 鼠标移动时实时显示鼠标虚拟位置 canvas.addEventListener('mousemove', function(event) { var vPos=getVirtualPosition(event.offsetX,event.offsetY); mousePos={"x":vPos.x.toFixed(3),"y":vPos.y.toFixed(3)}; }); // 初始化舞台 stage=new Stage(); // 开始动画 animate(); }; /*------------------------------------------------------------------------ 绘图系统函数:在指定期限内不断重绘 ------------------------------------------------------------------------*/ function animate(){ timeElapsed+=1;// 时间每轮增加1 stage.update(timeElapsed); stage.paintBg(context); stage.paint(context); stage.paintBorder(context); if(timeElapsed<TIME_END){ window.requestAnimationFrame(animate); } } /*------------------------------------------------------------------------ 绘图系统函数:舞台对象定义处 ------------------------------------------------------------------------*/ function Stage(){ // 内置对象(非必要勿更改) var obj=new Object; // 对象下的曲线数组(非必要勿更改) obj.curves=[]; // 塞入曲线1(按需修改设定项) obj.curves.push({ name:"曲线:y=e^x/x", xEnd:4, x:0, y:0, setY:function(x){ this.y=Math.pow(Math.E,x)/x;// 解析式 swallowCoord(x,this.y,this.pts0) }, "markMaxMin":false, "pts0":[], "pts1":[], }); // 塞入曲线2(按需修改设定项) obj.curves.push({ name:"曲线:y=4", xEnd:3.3, x:0, y:0, setY:function(x){ this.y=4;// 解析式 swallowCoord(x,this.y,this.pts0) }, "markMaxMin":false, "pts0":[], "pts1":[], }); // 随时间更新位置(非必要勿更改) obj.update=function(t){ for(var i=0;i<this.curves.length;i++){ var curve=this.curves[i]; if(curve.x<curve.xEnd){ curve.x+=X_PRECISION; curve.setY(curve.x); } } }; // 画前景(主要是描点和画函数曲线) obj.paint=function(ctx){ markPoint(ctx,1,Math.E,"low(1,e)","red",16); markPoint(ctx,0.36,4,"a","black",16); markPoint(ctx,0.36,0,"x1","red",16,20); markPoint(ctx,2.16,4,"b","black",16); markPoint(ctx,2.16,0,"x2","red",16,20); // 文字左上角实际位置(可手动修改设定值) const X_START=-300; // 文字横起点 const Y_START=200; // 文字纵起点 const OFFSET=50; // 文字间隔 // 遍历曲线数组(非必要勿更改) for(var i=0;i<this.curves.length;i++){ var curve=this.curves[i];// 曲线对象 var color;// 曲线及文字说明颜色 if(curve.color){ color=curve.color; }else{ color=getColor(i); } // 曲线名称 drawText(ctx,curve.name,X_START,Y_START-i*OFFSET,color,18); // 曲线当前点坐标 drawText(ctx,"当前 X:"+curve.x.toFixed(3)+" Y:"+curve.y.toFixed(3),X_START,Y_START-20-(i)*OFFSET,color,18); // 绘制曲线 if(curve.pts0){ sketchCurve(ctx,color,curve.pts0); // 绘制曲线分段1的高低点(可选) var mm=findMaxMin(curve.pts0); if(curve.markMaxMin){ markMaxMin(ctx,mm,color); } } } }; // 画背景(主要是画数轴和刻度及网格线,非必要不更改) obj.paintBg=function(ctx){ var w=WIDTH;// 取画布高宽 var h=HEIGHT; // 清屏 ctx.clearRect(-w/2,-h/2,w,h); ctx.fillStyle="#FFFFFF";// 背景色 ctx.fillRect(-w/2,-h/2,w,h); // 画坐标轴 drawAxisX(ctx); drawAxisY(ctx); markZeroPoint(ctx); drawScalesX(ctx); drawScalesY(ctx); drawGrid(ctx); // 左上角标题 var metrics = ctx.measureText(TITLE); var textWidth = metrics.width; drawText(ctx,TITLE,-w/2+textWidth+20,h/2-30,"black",18); // 右下角作者,日期 const waterMarkTxt="逆火制图@"+(new Date()).toLocaleString(); metrics = ctx.measureText(waterMarkTxt); textWidth = metrics.width; drawText(ctx,waterMarkTxt,w/2-textWidth,-h/2+6,"grey",16); // 右上角鼠标当前位置 if(mousePos.x && mousePos.y){ var posTxt="X="+mousePos.x+",Y="+mousePos.y; drawText(ctx,posTxt,w/2-textWidth+45,h/2-30,"navy",17); } }; // 绘制边框 obj.paintBorder=function(ctx){ var w=WIDTH;// 取画布高宽 var h=HEIGHT; // 外黑粗边框 ctx.save(); ctx.strokeStyle="gray"; ctx.lineWidth=4; ctx.beginPath(); ctx.moveTo(-WIDTH/2,-HEIGHT/2); ctx.lineTo(+WIDTH/2,-HEIGHT/2); ctx.lineTo(+WIDTH/2,+HEIGHT/2); ctx.lineTo(-WIDTH/2,+HEIGHT/2); ctx.closePath(); ctx.stroke(); ctx.restore(); // 中夹层 ctx.save(); ctx.strokeStyle="rgb(252,245,229)"; ctx.lineWidth=4; ctx.beginPath(); var GAP=5; ctx.moveTo(-WIDTH/2+GAP,-HEIGHT/2+GAP); ctx.lineTo(+WIDTH/2-GAP,-HEIGHT/2+GAP); ctx.lineTo(+WIDTH/2-GAP,+HEIGHT/2-GAP); ctx.lineTo(-WIDTH/2+GAP,+HEIGHT/2-GAP); ctx.closePath(); ctx.stroke(); ctx.restore(); // 内黑细边框 ctx.save(); ctx.strokeStyle="black"; ctx.lineWidth=1; ctx.beginPath(); var GAP=7; ctx.moveTo(-WIDTH/2+GAP,-HEIGHT/2+GAP); ctx.lineTo(+WIDTH/2-GAP,-HEIGHT/2+GAP); ctx.lineTo(+WIDTH/2-GAP,+HEIGHT/2-GAP); ctx.lineTo(-WIDTH/2+GAP,+HEIGHT/2-GAP); ctx.closePath(); ctx.stroke(); ctx.restore(); }; return obj;// 返回舞台对象 } /*---------------------------------------------------------- 专用函数:将一个点纳入容器 x:横坐标 y:纵坐标 container:坐标数组 ----------------------------------------------------------*/ function swallowCoord(x,y,container){ const RIGHT=WIDTH/2-5;// 右边界 const LEFT=-WIDTH/2;// 左边界 const TOP=HEIGHT/2-5;// 上边界 const BOTTOM=-HEIGHT/2;// 下边界 var realPt=getRealPosition(x,y) if( LEFT<realPt.x && realPt.x<RIGHT && BOTTOM<realPt.y && realPt.y<TOP ){ let coord={"x":x,"y":y}; container.push(coord); } } /*---------------------------------------------------------- 专用函数:找到坐标数组的最大最小值 cds:坐标数组 返回值:最大最小值对象 ----------------------------------------------------------*/ function findMaxMin(cds){ if(cds.length<1){ return null; } var retval={max:-10000,max_x:0,min:10000,min_x:0}; for(var i=0;i<cds.length;i++){ var y=cds[i].y; if(y>retval.max){ retval.max=y; retval.max_x=cds[i].x; } if(y<retval.min){ retval.min=y; retval.min_x=cds[i].x; } } return retval; } /*---------------------------------------------------------- 专用函数:绘出最大最小值 ctx:绘图上下文 mm:最大最小值对象 color:颜色 ----------------------------------------------------------*/ function markMaxMin(ctx,mm,color){ if(mm==null){ return; } // 最大值 var x=mm.max_x; var y=mm.max; var realPos=getRealPosition(x,y); ctx.save(); ctx.strokeStyle=color; ctx.beginPath(); ctx.arc(realPos.x,realPos.y,5,0,Math.PI*2,false); ctx.closePath(); ctx.stroke(); ctx.restore(); var text="max@x="+x.toFixed(3)+" y="+y.toFixed(3); drawText(ctx,text,realPos.x,realPos.y,color,12); // 最小值 var x=mm.min_x; var y=mm.min; var realPos=getRealPosition(x,y); ctx.save(); ctx.strokeStyle=color; ctx.beginPath(); ctx.arc(realPos.x,realPos.y,5,0,Math.PI*2,false); ctx.closePath(); ctx.stroke(); ctx.restore(); var text="min@x="+x.toFixed(3)+" y="+y.toFixed(3); drawText(ctx,text,realPos.x,realPos.y,color,12); } /*---------------------------------------------------------- 专用函数:从虚拟坐标得到实际坐标 virtualX:虚拟横坐标 virtualY:虚拟纵坐标 返回值:实际点对象,其x,y属性就是横纵坐标 ----------------------------------------------------------*/ function getRealPosition(virtualX,virtualY){ var xReal=(virtualX+ZERO_POINT.x)*SCALE_UNIT_X; var yReal=(virtualY+ZERO_POINT.y)*SCALE_UNIT_Y; return createPt(xReal,yReal); } /*---------------------------------------------------------- 专用函数:从实际坐标得到虚拟坐标 realX:实际横坐标 realY:实际纵坐标 返回值:虚拟点对象,其x,y属性就是横纵坐标 ----------------------------------------------------------*/ function getVirtualPosition(realX,realY){ var x=(realX-WIDTH/2-ZERO_POINT.x*SCALE_UNIT_X)/1/SCALE_UNIT_X; var y=-(realY-HEIGHT/2+ZERO_POINT.y*SCALE_UNIT_Y)/1/SCALE_UNIT_Y; return createPt(x,y); } /*---------------------------------------------------------- 专用函数:连点成线画曲线,算是本软件的核心功能 ctx:绘图上下文 color:文本颜色 cds:坐标数组 ----------------------------------------------------------*/ function sketchCurve(ctx,color,cds){ ctx.save(); ctx.strokeStyle = color; ctx.lineWidth=1; ctx.beginPath(); for(var i=0; i<cds.length; i++){ let x=cds[i].x; let y=cds[i].y; var realPos=getRealPosition(x,y); ctx.lineTo(realPos.x,realPos.y); } ctx.stroke(); ctx.restore(); } /*---------------------------------------------------------- 专用函数:描绘并标识一个点 ctx:绘图上下文 x:虚拟横坐标(从屏幕上直观看到的点的横坐标) y:虚拟纵坐标(从屏幕上直观看到的点的纵坐标) text:说明标识点的文本 color:文本颜色 fontSize:字体大小 offsetY:上下偏移值 ----------------------------------------------------------*/ function markPoint(ctx,x,y,text,color,fontSize,offsetY){ var realPos=getRealPosition(x,y); ctx.strokeStyle=color; ctx.lineWidth=0.5; // 纵横位置点划线,可人为选择 ctx.save(); ctx.setLineDash([5,5]); ctx.beginPath(); ctx.moveTo(realPos.x,ZERO_POINT.y*SCALE_UNIT_Y); ctx.lineTo(realPos.x,realPos.y); ctx.lineTo(ZERO_POINT.x*SCALE_UNIT_X,realPos.y); ctx.stroke(); ctx.restore(); // 画圈 ctx.beginPath(); ctx.arc(realPos.x,realPos.y,4,0,Math.PI*2,false); ctx.closePath(); ctx.stroke(); // 写文字 var metrics = ctx.measureText(text); var textWidth = metrics.width; var biasY=0; if(offsetY){ biasY=offsetY; } drawText(ctx,text,realPos.x-textWidth/2+2,realPos.y-20+biasY,color,fontSize); } /*---------------------------------------------------------- 专用函数:绘制网格线 ctx:绘图上下文 ----------------------------------------------------------*/ function drawGrid(ctx){ const RIGHT=WIDTH/2;// 右边界 const LEFT=-WIDTH/2;// 左边界 const TOP=HEIGHT/2;// 上边界 const BOTTOM=-HEIGHT/2;// 下边界 var N=10; // Y轴分十格,这与画布的高度成比例 var STEP=HEIGHT/N; // 每一格的步长,上行或是下行的步伐大小 // 1.从原点往上画横向网格线(粗格) for(var y=ZERO_POINT.y*SCALE_UNIT_Y+STEP;y<TOP;y+=STEP){ var start=createPt(LEFT,y); var end=createPt(RIGHT,y); ctx.save();// 画刻度线 ctx.lineWidth=0.5; ctx.strokeStyle="skyblue"; ctx.beginPath(); ctx.moveTo(start.x,start.y); ctx.lineTo(end.x,end.y); ctx.stroke(); ctx.restore(); } // 2.从原点往下画横向网格线(粗格) for(var y=ZERO_POINT.y*SCALE_UNIT_Y-STEP;y>BOTTOM;y-=STEP){ var start=createPt(LEFT,y); var end=createPt(RIGHT,y); ctx.save();// 画刻度线 ctx.lineWidth=0.5; ctx.strokeStyle="skyblue"; ctx.beginPath(); ctx.moveTo(start.x,start.y); ctx.lineTo(end.x,end.y); ctx.stroke(); ctx.restore(); } // 3.从原点往上画横向网格线(细格,10代表分十份) for(var y=ZERO_POINT.y*SCALE_UNIT_Y;y<TOP;y+=STEP/10){ var start=createPt(LEFT,y); var end=createPt(RIGHT,y); ctx.save();// 画刻度线 ctx.lineWidth=0.3; ctx.strokeStyle="lightgrey"; ctx.setLineDash([1,1]);// 设置虚线,起止点间包含五空格五划线共十段 ctx.beginPath(); ctx.moveTo(start.x,start.y); ctx.lineTo(end.x,end.y); ctx.stroke(); ctx.restore(); } // 4.从原点往下画横向网格线(细格,10代表分十份) for(var y=ZERO_POINT.y*SCALE_UNIT_Y;y>BOTTOM;y-=STEP/10){ var start=createPt(LEFT,y); var end=createPt(RIGHT,y); ctx.save();// 画刻度线 ctx.lineWidth=0.3; ctx.strokeStyle="lightgrey"; ctx.setLineDash([1,1]);// 设置虚线,起止点间包含五空格五划线共十段 ctx.beginPath(); ctx.moveTo(start.x,start.y); ctx.lineTo(end.x,end.y); ctx.stroke(); ctx.restore(); } var N=20; // X轴分十格,这与画布的高度成比例 var STEP=WIDTH/N; // 每一格的步长,上行或是下行的步伐大小 // 5.从原点往右画竖向网格线(粗格) for(var x=ZERO_POINT.x*SCALE_UNIT_X+STEP;x<RIGHT;x+=STEP){ var start=createPt(x,TOP); var end=createPt(x,BOTTOM); ctx.save();// 画刻度线 ctx.lineWidth=0.5; ctx.strokeStyle="skyblue"; ctx.beginPath(); ctx.moveTo(start.x,start.y); ctx.lineTo(end.x,end.y); ctx.stroke(); ctx.restore(); } // 6.从原点往左画竖向网格线(粗格) for(var x=ZERO_POINT.x*SCALE_UNIT_X-STEP;x>LEFT;x-=STEP){ var start=createPt(x,TOP); var end=createPt(x,BOTTOM); ctx.save();// 画刻度线 ctx.lineWidth=0.5; ctx.strokeStyle="skyblue"; ctx.beginPath(); ctx.moveTo(start.x,start.y); ctx.lineTo(end.x,end.y); ctx.stroke(); ctx.restore(); } // 7.从原点往右画竖向网格线(细格,10代表分十份) for(var x=ZERO_POINT.x*SCALE_UNIT_X;x<RIGHT;x+=STEP/10){ var start=createPt(x,TOP); var end=createPt(x,BOTTOM); ctx.save();// 画刻度线 ctx.lineWidth=0.3; ctx.strokeStyle="lightgrey"; ctx.setLineDash([1,1]);// 设置虚线,起止点间包含五空格五划线共十段 ctx.beginPath(); ctx.moveTo(start.x,start.y); ctx.lineTo(end.x,end.y); ctx.stroke(); ctx.restore(); } // 8.从原点往左画竖向网格线(细格,10代表分十份) for(var x=ZERO_POINT.x*SCALE_UNIT_X;x>LEFT;x-=STEP/10){ var start=createPt(x,TOP); var end=createPt(x,BOTTOM); ctx.save();// 画刻度线 ctx.lineWidth=0.3; ctx.strokeStyle="lightgrey"; ctx.beginPath(); ctx.moveTo(start.x,start.y); ctx.lineTo(end.x,end.y); ctx.stroke(); ctx.restore(); } } /*---------------------------------------------------------- 专用函数:得到整型后的刻度 scale:整型前的刻度 返回值:整型后的刻度 ----------------------------------------------------------*/ function formatScale(scale){ var s=scale*10; if(s % 5==0){ return scale+""; }else{ return scale.toFixed(1); } } /*---------------------------------------------------------- 专用函数:画Y轴上的刻度和文字 ctx:绘图上下文 ----------------------------------------------------------*/ function drawScalesY(ctx){ const TOP=HEIGHT/2; // 上边界 const BOTTOM=-HEIGHT/2; // 下边界 const N=10; // Y轴分十格,这与画布的高度成比例 const STEP=HEIGHT/N; // 每一格的步长,上行或是下行的步伐大小 // 从原点往上标注 for(var y=ZERO_POINT.y*SCALE_UNIT_Y+STEP;y<TOP;y+=STEP){ var start=createPt(ZERO_POINT.x*SCALE_UNIT_X,y); var end=createPt(ZERO_POINT.x*SCALE_UNIT_X+5,y);// 5为刻度线长度 ctx.save();// 画刻度线 ctx.lineWidth=0.5; ctx.strokeStyle="navy"; ctx.beginPath(); ctx.moveTo(start.x,start.y); ctx.lineTo(end.x,end.y); ctx.stroke(); ctx.restore(); // 标记文字 var text=formatScale(end.y/SCALE_UNIT_Y-ZERO_POINT.y); drawText(ctx,text,end.x-30,end.y-10,"navy",16); } // 从原点往下标注 for(var y=ZERO_POINT.y*SCALE_UNIT_Y-STEP;y>BOTTOM;y-=STEP){ var start=createPt(ZERO_POINT.x*SCALE_UNIT_X,y); var end=createPt(ZERO_POINT.x*SCALE_UNIT_X+5,y);// 5为刻度线长度 ctx.save();// 画刻度线 ctx.lineWidth=0.5; ctx.strokeStyle="navy"; ctx.beginPath(); ctx.moveTo(start.x,start.y); ctx.lineTo(end.x,end.y); ctx.stroke(); ctx.restore(); // 标记文字 var text=formatScale(end.y/SCALE_UNIT_Y-ZERO_POINT.y); drawText(ctx,text,end.x-30,end.y-10,"navy",16); } } /*---------------------------------------------------------- 专用函数:画横轴上的刻度和文字 ctx:绘图上下文 ----------------------------------------------------------*/ function drawScalesX(ctx){ const RIGHT=WIDTH/2; // 右边界 const LEFT=-WIDTH/2; // 左边界 const N=20; // Y轴分十格,这与画布的高度成比例 const STEP=WIDTH/N; // 每一格的步长,上行或是下行的步伐大小 // 从原点往右标注 for(var x=ZERO_POINT.x*SCALE_UNIT_X+STEP;x<RIGHT;x+=STEP){ var start=createPt(x,ZERO_POINT.y*SCALE_UNIT_Y); //drawSolidCircle(ctx,start.x,start.y,3,"red"); var end=createPt(x,ZERO_POINT.y*SCALE_UNIT_Y+5);// 5为刻度线长度 ctx.save();// 画刻度线 ctx.lineWidth=0.5; ctx.strokeStyle="navy"; ctx.beginPath(); ctx.moveTo(start.x,start.y); ctx.lineTo(end.x,end.y); ctx.stroke(); ctx.restore(); // 标记文字 var text=formatScale(end.x/SCALE_UNIT_X-ZERO_POINT.x); drawText(ctx,text,end.x,end.y-25,"navy",16); } // 从原点往左标注 for(var x=ZERO_POINT.x*SCALE_UNIT_X-STEP;x>LEFT;x-=STEP){ var start=createPt(x,ZERO_POINT.y*SCALE_UNIT_Y); //drawSolidCircle(ctx,start.x,start.y,3,"red"); var end=createPt(x,ZERO_POINT.y*SCALE_UNIT_Y+5);// 5为刻度线长度 ctx.save();// 画刻度线 ctx.lineWidth=0.5; ctx.strokeStyle="navy"; ctx.beginPath(); ctx.moveTo(start.x,start.y); ctx.lineTo(end.x,end.y); ctx.stroke(); ctx.restore(); // 标记文字 var text=formatScale(end.x/SCALE_UNIT_X-ZERO_POINT.x); drawText(ctx,text,end.x,end.y-25,"navy",16); } } /*---------------------------------------------------------- 专用函数:画横轴 ctx:绘图上下文 ----------------------------------------------------------*/ function drawAxisX(ctx){ const RIGHT=WIDTH/2-5;// 右边界 const LEFT=-WIDTH/2;// 左边界 ctx.save(); ctx.lineWidth=1; ctx.strokeStyle="black"; ctx.beginPath();// 向右直线 ctx.moveTo(ZERO_POINT.x*SCALE_UNIT_X,ZERO_POINT.y*SCALE_UNIT_Y); ctx.lineTo(RIGHT,ZERO_POINT.y*SCALE_UNIT_Y); ctx.stroke(); // 画右箭头 ctx.fillStyle="black"; ctx.beginPath(); var a=createPt(RIGHT-3,(ZERO_POINT.y+0)*SCALE_UNIT_Y); var b=createPt3(a,10,-Math.PI/8*7); var c=createPt3(a,6,-Math.PI); var d=createPt3(a,10,Math.PI/8*7); ctx.moveTo(a.x,a.y); ctx.lineTo(b.x,b.y); ctx.lineTo(c.x,c.y); ctx.lineTo(d.x,d.y); ctx.closePath(); ctx.fill(); ctx.beginPath();// 向左直线 ctx.moveTo(ZERO_POINT.x*SCALE_UNIT_X,ZERO_POINT.y*SCALE_UNIT_Y); ctx.lineTo(LEFT,(ZERO_POINT.y+0)*SCALE_UNIT_Y); ctx.stroke(); ctx.restore(); } /*---------------------------------------------------------- 专用函数:画纵轴 ctx:绘图上下文 ----------------------------------------------------------*/ function drawAxisY(ctx){ const TOP=HEIGHT/2-5;// 上边界 const BOTTOM=-HEIGHT/2;// 下边界 ctx.save(); ctx.lineWidth=1; ctx.strokeStyle="black"; ctx.beginPath();// 向右直线 ctx.moveTo(ZERO_POINT.x*SCALE_UNIT_X,ZERO_POINT.y*SCALE_UNIT_Y); ctx.lineTo(ZERO_POINT.x*SCALE_UNIT_X,TOP); ctx.stroke(); // 画上箭头 ctx.fillStyle="black"; ctx.beginPath(); var a=createPt(ZERO_POINT.x*SCALE_UNIT_X,TOP-3); var b=createPt3(a,10,-Math.PI/8*5); var c=createPt3(a,6,-Math.PI/2); var d=createPt3(a,10,-Math.PI/8*3); ctx.moveTo(a.x,a.y); ctx.lineTo(b.x,b.y); ctx.lineTo(c.x,c.y); ctx.lineTo(d.x,d.y); ctx.closePath(); ctx.fill(); ctx.beginPath();// 向左下直线 ctx.moveTo(ZERO_POINT.x*SCALE_UNIT_X,ZERO_POINT.y*SCALE_UNIT_Y); ctx.lineTo(ZERO_POINT.x*SCALE_UNIT_X,BOTTOM); ctx.stroke(); ctx.restore(); } /*---------------------------------------------------------- 专用函数:标记原点 ctx:绘图上下文 ----------------------------------------------------------*/ function markZeroPoint(ctx){ var a=createPt(ZERO_POINT.x*SCALE_UNIT_X,ZERO_POINT.y*SCALE_UNIT_Y); drawText(ctx,"0",a.x-10,a.y-20,"red",16); } /*---------------------------------------------------------- 基础函数:用于在定点绘制实心圆,编程中多用于判断点坐标正确性 编程后多删除或屏蔽的函数,相当于几何绘图中的辅助线 ctx:绘图上下文 x:矩形中心横坐标 y:矩形中心纵坐标 r:圆半径 style:填充圆的方案 ----------------------------------------------------------*/ function drawSolidCircle(ctx,x,y,r,style){ ctx.fillStyle=style; ctx.beginPath(); ctx.arc(x,y,r,0,Math.PI*2,false); ctx.closePath(); ctx.fill(); } /*---------------------------------------------------------- 基础函数:由角度得到弧度 degree:角度 返回值:弧度 ----------------------------------------------------------*/ function getRad(degree){ return degree/180*Math.PI; } /*---------------------------------------------------------- 基础函数:创建一个二维坐标点 base:基准点,入参必需有x和y两参数 radius:当前点到基准点的距离 theta:当前点到基准点的角度 Pt即Point ----------------------------------------------------------*/ function createPt3(base,radius,theta){ var retval={}; retval.x=base.x+radius*Math.cos(theta); retval.y=base.y+radius*Math.sin(theta); return retval; } /*---------------------------------------------------------- 基础函数:创建一个二维坐标点 baseX:基准点横坐标 baseY:基准点纵坐标 radius:当前点到基准点的距离 theta:当前点到基准点的角度 Pt即Point ----------------------------------------------------------*/ function createPt2(baseX,baseY,radius,theta){ var retval={}; retval.x=baseX+radius*Math.cos(theta); retval.y=baseY+radius*Math.sin(theta); return retval; } /*---------------------------------------------------------- 基础函数:创建一个二维坐标点 x:横坐标 y:纵坐标 Pt即Point ----------------------------------------------------------*/ function createPt(x,y){ var retval={}; retval.x=x; retval.y=y; return retval; } /*---------------------------------------------------------- 基础函数:书写文字 ctx:绘图上下文 x:横坐标 y:纵坐标 text:文字 font:字体 color:颜色 ----------------------------------------------------------*/ function drawText(ctx,text,x,y,color,size){ ctx.save(); ctx.translate(x,y) ctx.rotate(Math.PI) ctx.scale(-1,1) ctx.textBaseline="bottom"; ctx.textAlign="center"; ctx.fillStyle=color; ctx.font = size+"px consolas"; ctx.fillText(text,0,0); ctx.restore(); } /*---------------------------------------------------------- 基础函数:按数组序号得到颜色 index:数组序号 返回值:代表颜色的字符串 ----------------------------------------------------------*/ function getColor(index){ var arr=[ "maroon" /* 栗色 */, "orange" /* 橙色 */, "blue" /* 蓝色 */, "green" /* 绿色 */, "fuchsia"/* 紫红 */, "grey" /* 灰色 */, "lime" /* 酸橙 */, "navy" /* 海蓝 */, "purple" /* 紫色 */, "skyblue"/* 天蓝 */, "teal" /* 蓝绿 */, "yellow" /* 亮黄 */, "aqua" /* 湖绿 */, "red" /* 红色 */, "black" /* 黑色 */, ]; return arr[index % arr.length]; } /*---------------------------------------------------------- 你知道吗? 人生凡是妥协的决策,基本上都是错的; 一开始就将就的事情,到最后都得推倒重来; 违背内心的选择,到最终都会回到起点。 ----------------------------------------------------------*/ //--> </script>
END
浙公网安备 33010602011771号