let my={} function init(){let version='0.882' let mode=getJSQueryVar('mode','angle') my.modes=[{id:'arc',numPts:2,angQ:true,resizeQ:false},{id:'arcs',numPts:2,angQ:false,resizeQ:false},{id:'arclen',numPts:2,angQ:true,resizeQ:false},{id:'angle',numPts:2,angQ:true,resizeQ:false},{id:'chord',numPts:2,angQ:false,resizeQ:false},{id:'sector',numPts:2,angQ:true,resizeQ:false},{id:'segment',numPts:2,angQ:true,resizeQ:false},{id:'inscribe',fn:drawInscribe,numPts:3,angQ:true,resizeQ:false},{id:'inscribe2',fn:drawInscribe2,numPts:3,angQ:true,resizeQ:false},{id:'radius',numPts:1,angQ:false,resizeQ:true},{id:'radian',numPts:1,angQ:false,resizeQ:true},{id:'thales',fn:drawThales,numPts:1,angQ:false,resizeQ:false},] let modeNo=0 for(let i=0;i' s+='
Drag a point!
' if(my.mode.id=='arclen'){s+='
Radius:
' s+='' s+='
?
'} if(my.mode.angQ){s+=wrap({id:'degBtn',tag:'btn',cls:'btn hi',pos:'abs',style:'right:3px; bottom:3px; z-index:3;',fn:"toggle('deg')"},'Deg')} s+=wrap({cls:'copyrt',pos:'abs',style:'left:5px; bottom:3px'},`© 2022 Rod Pierce v${version}`) s=wrap({cls:'js',style:'width:'+my.wd+'px; height:'+my.ht+'px;'},s) docInsert(s) my.can=new Can('canvas'+id,my.wd,my.ht,2) my.shapes=[] makeShapes() update() let el=my.can.el el.addEventListener('mousedown',mouseDownListener,false) el.addEventListener('touchstart',ontouchstart,false) el.addEventListener('mousemove',dopointer,false)} function ontouchstart(ev){let touch=ev.targetTouches[0] ev.clientX=touch.clientX ev.clientY=touch.clientY ev.touchQ=true mouseDownListener(ev)} function ontouchmove(ev){let touch=ev.targetTouches[0] ev.clientX=touch.clientX ev.clientY=touch.clientY ev.touchQ=true mouseMoveListener(ev) ev.preventDefault()} function ontouchend(){let el=my.can.el el.addEventListener('touchstart',ontouchstart,false) window.removeEventListener('touchend',ontouchend,false) if(my.drag.onQ){my.drag.onQ=false window.removeEventListener('touchmove',ontouchmove,false)}} function dopointer(ev){let[mouseX,mouseY]=my.can.mousePos(ev) let inQ=false for(let i=0;ihighestIndex){my.drag.holdX=mouseX-my.shapes[i].x my.drag.holdY=mouseY-my.shapes[i].y highestIndex=i my.drag.n=i}}} if(my.drag.onQ){document.getElementById('dragem').style.visibility='hidden' if(ev.touchQ){window.addEventListener('touchmove',ontouchmove,false)}else{window.addEventListener('mousemove',mouseMoveListener,false)}} let el=my.can.el if(ev.touchQ){el.removeEventListener('touchstart',ontouchstart,false) window.addEventListener('touchend',ontouchend,false)}else{el.removeEventListener('mousedown',mouseDownListener,false) window.addEventListener('mouseup',mouseUpListener,false)} if(ev.preventDefault){ev.preventDefault()} else if(ev.returnValue){ev.returnValue=false} return false} function mouseUpListener(){let el=my.can.el el.addEventListener('mousedown',mouseDownListener,false) window.removeEventListener('mouseup',mouseUpListener,false) if(my.drag.onQ){my.drag.onQ=false window.removeEventListener('mousemove',mouseMoveListener,false)}} function mouseMoveListener(ev){let posX let posY let shapeRad=my.shapes[my.drag.n].rad let minX=shapeRad let el=my.can.el let maxX=el.width-shapeRad let minY=shapeRad let maxY=el.height-shapeRad let[mouseX,mouseY]=my.can.mousePos(ev) posX=mouseX-my.drag.holdX posX=posXmaxX?maxX:posX posY=mouseY-my.drag.holdY posY=posYmaxY?maxY:posY if(my.drag.onQ){my.shapes[my.drag.n].x=posX my.shapes[my.drag.n].y=posY} update()} function hitTest(shape,mx,my){let dx let dy dx=mx-shape.x dy=my-shape.y return dx*dx+dy*dy30){g.beginPath() g.fillStyle='orange' g.font='16px Lucida Console' txt='radius' if(dx<0)txt='suidar' for(i=0;i0)txt='suidar' g.fillStyle='orange' dang=10/rad ang=1.57+dang*6 ang=-ang1+0.8 for(i=0;iangles[1])midAngle+=Math.PI lblX=Math.cos(midAngle)*60 lblY=-Math.sin(midAngle)*60 g.font='24px Arial' g.fillStyle=my.clrHi g.textAlign='center' g.fillText(angTxt(angleSnap),my.circle.x+lblX,my.circle.y+lblY+10)} break case 'sector':case 'segment':n0=0 n1=1 if(angDiff>Math.PI){let temp=n1 n1=n0 n0=temp angDiff=angles[n1]-angles[n0] if(angDiff<0)angDiff+=2*Math.PI angleSnap=parseInt(angleDeg(angDiff,true))} g.beginPath() g.fillStyle='rgba(255,255,184,1)' g.strokeStyle='blue' g.lineWidth=1.5 g.moveTo(pts[n0].x,pts[n0].y) if(my.mode.id=='sector')g.lineTo(my.circle.x,my.circle.y) g.lineTo(pts[n1].x,pts[n1].y) g.arc(my.circle.x,my.circle.y,my.circle.rad,-angles[n1],-angles[n0]) g.fill() g.stroke() if(my.mode.id=='sector'){if(angleSnap==90){g.drawBox(my.circle.x,my.circle.y,25,-Math.PI/2-angles[n0])}else{g.beginPath() g.arc(my.circle.x,my.circle.y,30,-angles[n1],-angles[n0]) g.stroke() midAngle=(angles[n0]+angles[n1])/2 if(angles[n0]>angles[n1])midAngle+=Math.PI lblX=Math.cos(midAngle)*60 lblY=-Math.sin(midAngle)*60 g.font='24px Arial' g.fillStyle='blue' g.textAlign='center' g.fillText(angTxt(angleSnap),my.circle.x+lblX,my.circle.y+lblY+10)}}else{g.font='24px Arial' g.fillStyle=my.clrHi g.textAlign='center' g.fillText(angTxt(angleSnap),my.circle.x,my.circle.y+10)} break case 'chord':n0=0 n1=1 if(angDiff>Math.PI){let temp=n1 n1=n0 n0=temp angDiff=angles[n1]-angles[n0] if(angDiff<0)angDiff+=2*Math.PI angleSnap=parseInt(angleDeg(angDiff,true))} g.beginPath() g.strokeStyle=my.clrHi g.lineWidth=2 g.moveTo(pts[n0].x,pts[n0].y) g.lineTo(pts[n1].x,pts[n1].y) g.stroke() break case 'arc':case 'arclen':g.beginPath() g.strokeStyle=my.clrHi g.lineWidth=3 g.arc(my.circle.x,my.circle.y,my.circle.rad,-angles[1],-angles[0]) g.stroke() g.lineWidth=1 midAngle=(angles[0]+angles[1])/2 if(angles[0]>angles[1])midAngle+=Math.PI lblX=Math.cos(midAngle)*70 lblY=-Math.sin(midAngle)*70 g.font='24px Arial' g.fillStyle=my.clrHi g.textAlign='center' angleSnap=parseInt(angleDeg(angDiff,true)) g.fillText(angTxt(angleSnap),my.circle.x+lblX,my.circle.y+lblY+10) g.font='18px Arial' lblX=Math.cos(midAngle)*116 lblY=-Math.sin(midAngle)*116 g.fillText('arc',my.circle.x+lblX,my.circle.y+lblY+10) if(my.mode.id=='arclen'){let r=document.getElementById('rad').value document.getElementById('len').innerHTML='Arc Length = '+(r*((angleSnap*Math.PI)/180.0)).toPrecision(6)} break case 'arcs':n0=0 n1=1 if(angDiff>Math.PI){let temp=n1 n1=n0 n0=temp angDiff=angles[n1]-angles[n0] if(angDiff<0)angDiff+=2*Math.PI angleSnap=parseInt(angleDeg(angDiff,true))} midAngle=(angles[n0]+angles[n1])/2 if(angles[n0]>angles[n1])midAngle+=Math.PI lblX=Math.cos(midAngle)*60 lblY=-Math.sin(midAngle)*60 g.font='18px Arial' g.fillStyle=my.clrHi g.textAlign='center' g.fillText('Minor\nArc',my.circle.x+lblX,my.circle.y+lblY+10) g.beginPath() g.strokeStyle=my.clrHi g.lineWidth=2 g.arc(my.circle.x,my.circle.x,my.circle.rad,-angles[n1],-angles[n0]) g.stroke() midAngle=(angles[n0]+angles[n1])/2 if(angles[n0]a2)a2+=2*Math.PI let flipQ=a2-a1>Math.PI if(centralQ){pt={x:my.circle.x,y:my.circle.y} a1=Math.atan2(ptm1.y-pt.y,ptm1.x-pt.x) a2=Math.atan2(ptp1.y-pt.y,ptp1.x-pt.x) if(a1>a2)a2+=2*Math.PI} if(flipQ){let temp=a1 a1=a2 a2=temp} let angDeg=((a2-a1)*180.0)/Math.PI if(angDeg<0)angDeg+=360.0 angDeg=Math.round(angDeg) let g=my.can.g g.beginPath() g.strokeStyle='hsla(60,100%,20%,1)' g.fillStyle='hsla(60,100%,80%,0.5)' if(angDeg==90){g.drawBox(pt.x,pt.y,30,a1)}else{g.moveTo(pt.x,pt.y) g.arc(pt.x,pt.y,30,a1,a2) g.lineTo(pt.x,pt.y) g.fill()} g.stroke() g.font='20px Arial' g.fillStyle=my.clrHi g.textAlign='center' let midAngle=(a1+a2)/2 if(a1>a2)midAngle+=Math.PI let lblX=Math.cos(midAngle)*50 let lblY=Math.sin(midAngle)*50 g.fillText(angTxt(angDeg),pt.x+lblX,pt.y+lblY+10) g.beginPath() g.strokeStyle=my.clrHi g.lineWidth=1 g.moveTo(pts[0].x,pts[0].y) g.lineTo(pt.x,pt.y) g.lineTo(pts[2].x,pts[2].y) g.stroke()} function angTxt(angDeg){return my.toggles.deg?angDeg.toString()+'°':(angDeg*(3.1416/180)).toFixed(3)} function drawThales(pts){let ptm1={x:my.circle.x-my.circle.rad,y:my.circle.y} let pt=pts[0] let ptp1={x:my.circle.x+my.circle.rad,y:my.circle.y} let a1=Math.atan2(ptm1.y-pt.y,ptm1.x-pt.x) let a2=Math.atan2(ptp1.y-pt.y,ptp1.x-pt.x) if(a1>a2)a2+=2*Math.PI if(a2-a1>Math.PI){let temp=a1 a1=a2 a2=temp} let angDeg=((a2-a1)*180.0)/Math.PI if(angDeg<0)angDeg+=360.0 angDeg=Math.round(angDeg) let g=my.can.g g.beginPath() g.strokeStyle='hsla(60,100%,20%,1)' g.fillStyle='hsla(60,100%,80%,0.5)' if(angDeg==90){g.drawBox(pt.x,pt.y,25,a1)}else{g.moveTo(pt.x,pt.y) g.arc(pt.x,pt.y,30,a1,a2) g.fill()} g.stroke() let midAngle=(a1+a2)/2 if(a1>a2)midAngle+=Math.PI let lblX=Math.cos(midAngle)*50 let lblY=Math.sin(midAngle)*50 g.font='20px Arial' g.fillStyle=my.clrHi g.textAlign='center' g.fillText(angTxt(angDeg),pt.x+lblX,pt.y+lblY+10) g.beginPath() g.strokeStyle=my.circle.clr g.lineWidth=1 g.moveTo(ptm1.x,ptm1.y) g.lineTo(ptp1.x,ptp1.y) g.stroke() g.beginPath() g.strokeStyle=my.clrHi g.lineWidth=1 g.moveTo(ptm1.x,ptm1.y) g.lineTo(pt.x,pt.y) g.lineTo(ptp1.x,ptp1.y) g.stroke()} function angleDeg(angleRad,snap90sQ){let angle=(angleRad*180.0)/Math.PI if(snap90sQ){if(angle<=1||angle>=359)angle=0 if(angle>=89&&angle<92)angle=90 if(angle>=179&&angle<182)angle=180 if(angle>=269&&angle<272)angle=270} return angle} CanvasRenderingContext2D.prototype.drawBox=function(midX,midY,radius,angle){let g=this g.beginPath() let pts=[[0,0],[Math.cos(angle),Math.sin(angle)],[Math.cos(angle)+Math.cos(angle+Math.PI/2),Math.sin(angle)+Math.sin(angle+Math.PI/2)],[Math.cos(angle+Math.PI/2),Math.sin(angle+Math.PI/2)],[0,0],] for(let i=0;i{if(cls.length==0)cls='btn' return '