let w,h,ratio,el,g,poly,dragQ,my={};function areacoordsMain(mode=5){let version='0.896' my.mode=mode my.modePts=5;if(isNaN(my.mode)){}else{my.modePts=Number(my.mode);} console.log("my.mode",my.mode,my.modePts);let canvasid="canvas"+my.mode;my.titleid="title"+my.mode;my.infoid="info"+my.mode;dragQ=false;my.dragScreenQ=false;w=540;h=360;my.graphWd=w;my.graphHt=h;let s='';s+='';s+='' s+='
';s+='';s+='
';s+='
Title
';s+='
Info
';s+='
';if(isNaN(my.mode)){s+='
';s+='';s+='
';s+='';s+='
';} let btns=[{id:'anglesBtn',name:'Angles'},{id:'sidesBtn',name:'Sides'},{id:'diagsBtn',name:'Diags'},{id:'coordsBtn',name:'Coords'},{id:'guidesBtn',name:'Guides'},{id:'snapBtn',name:'Snap'},{id:'regBtn',name:'Regular'},] s+='
';btns.map(btn=>{s+=`` s+='
';}) s+='
';s+='
';s+='Zoom:';s+='';s+=' ';s+='';s+='';s+='
';s+='
';s+='';s+='
';s+='';s+='';s+='
';s+='
';s+='
© 2020 MathsIsFun.com v'+version+'
';s+='
';document.write(s);el=document.getElementById(canvasid);ratio=2;el.width=w*ratio;el.height=h*ratio;el.style.width=w+"px";el.style.height=h+"px";g=el.getContext("2d");g.setTransform(ratio,0,0,ratio,0,0);my.currZoom=1;my.sttRect=[-1,-2.2,11,7.5];my.coords=new Coords(0,0,w,h,my.sttRect[0],my.sttRect[1],my.sttRect[2],my.sttRect[3],true);this.graph=new Graph(g,my.coords);my.dragNo=0;my.anglesQ=false;my.coordsQ=false;my.diagsQ=false;my.sidesQ=false;my.guidesQ=false;my.snapQ=false;my.regQ=false;poly=new Poly();if(my.mode=='coords'){my.modePts=3;} makeShapes();if(my.mode=='coords'){document.getElementById('anglesBtn').style.visibility='hidden';document.getElementById('diagsBtn').style.visibility='hidden';toggleCoords();}else{} if(my.mode=="diag"){toggleDiags();} el.addEventListener("mousedown",mouseDownListener,false);el.addEventListener('touchstart',ontouchstart,false);el.addEventListener("mousemove",dopointer,false);my.exs=[{name:"Triangle",coords:'(4.26,5.27), (6.16,1.33), (1.80,1.65)'},{name:"Rectangle",coords:'(7.50,4.50), (7.50,1.00), (3.50,1.00), (3.50,4.50)'},{name:"Circl-ish",coords:'(6.01,4.99), (6.96,4.77), (7.74,4.18), (8.21,3.32), (8.29,2.34), (7.97,1.42), (7.30,0.71), (6.39,0.33), (5.42,0.35), (4.53,0.77), (3.89,1.51), (3.61,2.44), (3.73,3.41), (4.24,4.25), (5.04,4.81)'},{name:"Tilted Square",coords:'(6.91,5.15), (7.59,1.36), (3.80,0.68), (3.12,4.47)'},{name:"Pentagon",coords:'(6.09,5.80), (2.68,4.90), (2.48,1.38), (5.76,0.10), (8.00,2.83)'},];doType();} function exNext(){my.exNo++ if(my.exNo>=my.exs.length)my.exNo=0 let coordStr=my.exs[my.exNo].coords decodeCSV(coordStr)} function getDescr(){let polyNames=["","","","Triangle","Quadrilateral","Pentagon","Hexagon","Heptagon","Octagon","Nonagon","Decagon","Hendecagon","Dodecagon","Triskaidecagon ","Tetrakaidecagon ","Pentadecagon","Hexakaidecagon ","Heptadecagon","Octakaidecagon ","Enneadecagon","Icosagon"];let area=poly.getArea();let descrStr="";let infoStr="";if(poly.isComplex()){descrStr+="Complex ";infoStr="(Shape intersects itself.)";}else{if(poly.isConcave()){descrStr+="Concave ";}else{if(poly.isRegular(0.01)){if(poly.pts.length>4){descrStr+="Regular ";}}} infoStr="Area = "+fmt(area,4);} if(poly.pts.length0)s+=', ';s+='(';s+=poly.pts[i].x.toFixed(my.coords.decDigN);s+=',';s+=poly.pts[i].y.toFixed(my.coords.decDigN);s+=')';} return s;} function decodeCSV(s){s=s.replace(/\s/g,"");s=s.replace(/\)\,\(/g,"~");s=s.replace(/\)\(/g,"~");s=s.replace(/\)/g,"");s=s.replace(/\(/g,"");s=s.replace(/\,/g,"_");decode(s);} function decode(s){let a=s.split("~");poly.pts=[];for(let i=0;i=2){poly.pts.push(new Pt(Number(xy[0]),Number(xy[1])));}} poly.pts2pxs() doType();} function reset(){my.coords=new Coords(0,0,w,h,my.sttRect[0],my.sttRect[1],my.sttRect[2],my.sttRect[3],true);makeShapes();update();} function update(){doType();} function getNum(){return parseInt(my.modePts);} function numDn(){let num=getNum();if(num>3){num--;chgNumPts(num);}} function numUp(){let num=getNum();if(num<=100){num++;chgNumPts(num);}} function chgNumPts(n){my.modePts=n;makeShapes();doType();} function toggleAngles(){my.anglesQ=!my.anglesQ;btn("anglesBtn",my.anglesQ);update();} function toggleCoords(){my.coordsQ=!my.coordsQ;btn("coordsBtn",my.coordsQ);update();} function toggleGuides(){my.guidesQ=!my.guidesQ;btn("guidesBtn",my.guidesQ);update();} function toggleDiags(){my.diagsQ=!my.diagsQ;btn("diagsBtn",my.diagsQ);update();} function toggleSides(){my.sidesQ=!my.sidesQ;btn("sidesBtn",my.sidesQ);update();} function toggleRegular(){my.regQ=!my.regQ;btn("regBtn",my.regQ);update();} function toggleSnap(){my.snapQ=!my.snapQ;btn("snapBtn",my.snapQ);update();} function btn(btn,onq){if(onq){document.getElementById(btn).classList.add("hi");document.getElementById(btn).classList.remove("lo");}else{document.getElementById(btn).classList.add("lo");document.getElementById(btn).classList.remove("hi");}} function ontouchstart(evt){let touch=evt.targetTouches[0];evt.clientX=touch.clientX;evt.clientY=touch.clientY;evt.touchQ=true;mouseDownListener(evt)} function ontouchmove(evt){let touch=evt.targetTouches[0];evt.clientX=touch.clientX;evt.clientY=touch.clientY;evt.touchQ=true;mouseMoveListener(evt);evt.preventDefault();} function ontouchend(evt){el.addEventListener('touchstart',ontouchstart,false);window.removeEventListener("touchend",ontouchend,false);if(dragQ){dragQ=false;window.removeEventListener("touchmove",ontouchmove,false);}} function dopointer(e){let bRect=el.getBoundingClientRect();let mouseX=(e.clientX-bRect.left)*(el.width/ratio/bRect.width);let mouseY=(e.clientY-bRect.top)*(el.height/ratio/bRect.height);let overQ=false;for(let i=0;ihighestIndex){my.dragHoldX=mouseX-poly.pxs[i].x;my.dragHoldY=mouseY-poly.pxs[i].y;highestIndex=i;my.dragNo=i;}}} if(!dragQ){dragQ=true;my.dragScreenQ=true;} if(evt.touchQ){window.addEventListener('touchmove',ontouchmove,false);}else{window.addEventListener("mousemove",mouseMoveListener,false);} console.log("mouseDownListener",dragQ,my.dragScreenQ,highestIndex);doType();if(evt.touchQ){el.removeEventListener("touchstart",ontouchstart,false);window.addEventListener("touchend",ontouchend,false);}else{el.removeEventListener("mousedown",mouseDownListener,false);window.addEventListener("mouseup",mouseUpListener,false);} if(evt.preventDefault){evt.preventDefault();} else if(evt.returnValue){evt.returnValue=false;} return false;} function mouseUpListener(evt){dragQ=false;el.addEventListener("mousedown",mouseDownListener,false);window.removeEventListener("mouseup",mouseUpListener,false);window.removeEventListener("mousemove",mouseMoveListener,false);} function mouseMoveListener(evt){let posX;let posY;let shapeRad=poly.pts[my.dragNo].rad;let minX=shapeRad;let maxX=el.width-shapeRad;let minY=shapeRad;let maxY=el.height-shapeRad;let bRect=el.getBoundingClientRect();let mouseX=(evt.clientX-bRect.left)*(el.width/ratio/bRect.width);let mouseY=(evt.clientY-bRect.top)*(el.height/ratio/bRect.height);if(my.dragScreenQ){let moveX=my.prevX-mouseX;let moveY=mouseY-my.prevY;if(Math.abs(moveX)>1||Math.abs(moveY)>1){my.coords.drag(moveX,moveY);my.prevX=mouseX;my.prevY=mouseY;poly.pxs=[] for(let i=0;imaxX)?maxX:posX);posY=mouseY-my.dragHoldY;posY=(posYmaxY)?maxY:posY);let xVal=my.coords.toXVal(posX) let yVal=my.coords.toYVal(posY) if(my.snapQ){let fact=my.coords.tick console.log('fact',fact) xVal=Math.round(xVal/fact)*fact yVal=Math.round(yVal/fact)*fact posX=my.coords.toXPix(xVal) posY=my.coords.toYPix(yVal)} poly.pts[my.dragNo].x=xVal poly.pts[my.dragNo].y=yVal poly.pxs[my.dragNo].x=posX;poly.pxs[my.dragNo].y=posY;} doType();} function hitTest(shape,mx,my){let dx;let dy;dx=mx-shape.x;dy=my-shape.y;return(dx*dx+dy*dyy)!=(yj>y))&&(x<(xj-xi)*(y-yi)/(yj-yi)+xi);if(intersect)inside=!inside;} return inside;} pts2pxs(){this.pxs=[] for(let i=0;i180) return true;} return false;} drawAngles(g){let angSum=0;let angDescr="";let angs=[];for(let i=0;i90){g.strokeStyle='#ff0000';d=Math.max(20,30-(angDeg-90)/6);}else{g.strokeStyle='#4444FF';} g.fillStyle="rgba(0, 0, 255, 0.3)";g.beginPath();g.moveTo(pt.x,pt.y);g.arc(pt.x,pt.y,d,pt.angleIn,pt.angleOut,false);g.closePath();g.fill();} let ang=this.userAngle(pt.getAngle());if(ia2) a2+=2*Math.PI;pt.angleIn=a1;pt.angleOut=a2;}} function getClockwise(pts){let numPoints=pts.length;let count=0;for(let i=0;i0){count++;}} if(count>0) return(1);if(count==0) return(0);return(-1);} function getSides(pts){let numPoints=pts.length;let sides=[];for(let i=0;imaxNo){currNo=minNo+(currNo-minNo)%range;} return currNo;} function constrain(min,val,max){return(Math.min(Math.max(min,val),max));} class Line{constructor(pt1,pt2){this.a=pt1;this.b=pt2;} isIntersect(b){let a=this;if(this.ccw(a.a,a.b,b.a)*this.ccw(a.a,a.b,b.b)>0){return false;} if(this.ccw(b.a,b.b,a.a)*this.ccw(b.a,b.b,a.b)>0){return false;} return true;} ccw(a,b,c){return((b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y));} getIntersection(ln,asSegmentsQ){let A=this.a;let B=this.b;let E=ln.a;let F=ln.b;let a1=B.y-A.y;let b1=A.x-B.x;let c1=B.x*A.y-A.x*B.y;let a2=F.y-E.y;let b2=E.x-F.x;let c2=F.x*E.y-E.x*F.y;let denom=a1*b2-a2*b1;if(denom==0){return null;} let ip=new Pt();ip.x=(b1*c2-b2*c1)/denom;ip.y=(a2*c1-a1*c2)/denom;if(asSegmentsQ){if(Math.pow(ip.x-B.x,2)+Math.pow(ip.y-B.y,2)>Math.pow(A.x-B.x,2)+Math.pow(A.y-B.y,2)){return null;} if(Math.pow(ip.x-A.x,2)+Math.pow(ip.y-A.y,2)>Math.pow(A.x-B.x,2)+Math.pow(A.y-B.y,2)){return null;} if(Math.pow(ip.x-F.x,2)+Math.pow(ip.y-F.y,2)>Math.pow(E.x-F.x,2)+Math.pow(E.y-F.y,2)){return null;} if(Math.pow(ip.x-E.x,2)+Math.pow(ip.y-E.y,2)>Math.pow(E.x-F.x,2)+Math.pow(E.y-F.y,2)){return null;}} return ip;} getMidPt(){return new Pt((this.a.x+this.b.x)/2,(this.a.y+this.b.y)/2);} getClosestPoint(toPt,inSegmentQ){let AP=toPt.translate(this.a,false);let AB=this.b.translate(this.a,false);let ab2=AB.x*AB.x+AB.y*AB.y;let ap_ab=AP.x*AB.x+AP.y*AB.y;let t=ap_ab/ab2;if(inSegmentQ){t=constrain(0,t,1);} return this.a.translate(AB.multiply(t));} setLen(newLen,fromMidQ){fromMidQ=typeof fromMidQ!=='undefined'?fromMidQ:true;let len=this.getLength();if(fromMidQ){let midPt=this.getMidPt();let halfPt=new Pt(this.a.x-midPt.x,this.a.y-midPt.y);halfPt.multiplyMe(newLen/len);this.a=midPt.translate(halfPt);this.b=midPt.translate(halfPt,false);}else{let diffPt=new Pt(this.a.x-this.b.x,this.a.y-this.b.y);diffPt.multiplyMe(newLen/len);this.b=this.a.translate(diffPt,false);}} getAngle(){return Math.atan2(this.b.y-this.a.y,this.b.x-this.a.x);}} class Coords{constructor(left,top,width,height,xStt,yStt,xEnd,yEnd,uniScaleQ){this.left=left;this.top=top;this.width=width;this.height=height;this.xStt=xStt;this.yStt=yStt;this.xEnd=xEnd;this.yEnd=yEnd;this.uniScaleQ=uniScaleQ;this.xLogQ=false;this.yLogQ=false;this.xScale;this.yScale;this.calcScale();} calcScale(){if(this.xLogQ){if(this.xStt<=0)this.xStt=1;if(this.xEnd<=0)this.xEnd=1;} if(this.yLogQ){if(this.yStt<=0)this.yStt=1;if(this.yEnd<=0)this.yEnd=1;} let temp;if(this.xStt>this.xEnd){temp=this.xStt;this.xStt=this.xEnd;this.xEnd=temp;} if(this.yStt>this.yEnd){temp=this.yStt;this.yStt=this.yEnd;this.yEnd=temp;} this.xSpan=this.xEnd-this.xStt;if(this.xSpan<=0)this.xSpan=0.1;this.xScale=this.xSpan/this.width;this.xLogScale=(Math.log(this.xEnd)-Math.log(this.xStt))/this.width;this.ySpan=this.yEnd-this.yStt;if(this.ySpan<=0)this.ySpan=0.1;this.yScale=this.ySpan/this.height;this.yLogScale=(Math.log(this.yEnd)-Math.log(this.yStt))/this.height;this.maxSpan=Math.max(this.xSpan,this.ySpan) this.tick=this.toTick(this.maxSpan/50) let pow10=Math.floor(Math.log(this.maxSpan)*Math.LOG10E) this.decDigN=3-pow10 if(this.uniScaleQ&&!this.xLogQ&&!this.yLogQ){let newScale=Math.max(this.xScale,this.yScale);this.xScale=newScale;this.xSpan=this.xScale*this.width;let xMid=(this.xStt+this.xEnd)/2;this.xStt=xMid-this.xSpan/2;this.xEnd=xMid+this.xSpan/2;this.yScale=newScale;this.ySpan=this.yScale*this.height;let yMid=(this.yStt+this.yEnd)/2;this.yStt=yMid-this.ySpan/2;this.yEnd=yMid+this.ySpan/2;} console.log('calcScale',this)} toTick(val){let index10=Math.floor(Math.log(val)*Math.LOG10E) let pow10=Math.pow(10,index10) let mantissa=val/pow10;let ticks=[1,2,5,10] let best=0 let found=-1 for(let i=0;i1)break if(score>best){best=score found=i}} if(found<0){console.log('Error: toTick',val) return 1}else{return ticks[found]*pow10}} getXScale(){return this.xScale;} getYScale(){return this.yScale;} scale(factor,xMid,yMid){if(typeof xMid=='undefined')xMid=(this.xStt+this.xEnd)/2;this.xStt=xMid-(xMid-this.xStt)*factor;this.xEnd=xMid+(this.xEnd-xMid)*factor;if(typeof yMid=='undefined')yMid=(this.yStt+this.yEnd)/2;this.yStt=yMid-(yMid-this.yStt)*factor;this.yEnd=yMid+(this.yEnd-yMid)*factor;this.calcScale();} drag(xPix,yPix){this.xStt+=xPix*this.xScale;this.xEnd+=xPix*this.xScale;this.yStt+=yPix*this.yScale;this.yEnd+=yPix*this.yScale;this.calcScale();} newCenter(x,y){let xMid=this.xStt+x*this.xScale;let xhalfspan=(this.xEnd-this.xStt)/2;this.xStt=xMid-xhalfspan;this.xEnd=xMid+xhalfspan;let yMid=this.yEnd-y*this.yScale;let yhalfspan=(this.yEnd-this.yStt)/2;this.yStt=yMid-yhalfspan;this.yEnd=yMid+yhalfspan;this.calcScale();} fitToPts(pts,borderFactor){for(let i=0;i=5){if(majorQ){return(5*pow10);}else{return(1*pow10);}} if(mantissa>=3){if(majorQ){return(2*pow10);}else{return(0.2*pow10);}} if(mantissa>=1.4){if(majorQ){return(0.5*pow10);}else{return(0.2*pow10);}} if(mantissa>=0.8){if(majorQ){return(0.5*pow10);}else{return(0.1*pow10);}} if(majorQ){return(0.2*pow10);}else{return(0.1*pow10);}}} class Graph{constructor(g,coords){this.g=g;my.coords=coords;this.xLinesQ=true;this.yLinesQ=true;this.xValsQ=true;this.yValsQ=true;this.majorTickClr="rgba(0,0,256,0.2)" this.minorTickClr="rgba(0,0,256,0.07)" this.skewQ=false;} drawGraph(){this.hzAxisY=my.coords.toYPix(0);if(this.hzAxisY<0)this.hzAxisY=0;if(this.hzAxisY>my.coords.height)this.hzAxisY=my.coords.height;this.hzNumsY=this.hzAxisY+14;if(this.hzAxisY>my.coords.height-10)this.hzNumsY=my.coords.height-3;this.vtAxisX=my.coords.toXPix(0);if(this.vtAxisX<0)this.vtAxisX=0;if(this.vtAxisX>my.coords.width)this.vtAxisX=my.coords.width;this.vtNumsX=this.vtAxisX-5;if(this.vtAxisX<10)this.vtNumsX=20;if(my.coords.xLogQ){this.drawLinesLogX();}else{if(this.xLinesQ){this.drawHzLines();}} if(my.coords.yLogQ){this.drawLinesLogY();}else{if(this.yLinesQ){this.drawVtLines();}}} drawVtLines(){let g=this.g;g.lineWidth=1;let ticks=my.coords.getTicks(my.coords.xStt,my.coords.xEnd-my.coords.xStt,my.graphWd/100);for(let i=0;i