let my={}
function init(){let version='0.94'
my.mode=getJSQueryVar('mode','bisect')
if(my.mode=='seg')my.mode='line segment'
my.lineTyps=['line','ray','line segment']
let canvasid='canvas'+my.mode
my.dragging=false
let w=540
let h=360
let s=''
s+='
'
s+='
'
if(my.lineTyps.indexOf(my.mode)!=-1){s+='
'}
s+='
'
s+=''+winnewSvg()+' '
s+='
'
s+='
'
s+='Coords '
s+='Reset '
s+='
'
s+=wrap({cls:'copyrt',pos:'abs',style:'left:5px; bottom:3px'},`© 2022 Rod Pierce v${version}`)
s+='
'
docInsert(s)
my.can=new Can(canvasid,w,h,2)
my.coords=new Coords(0,0,w,h,-2,-1.9,15,11,true)
my.graph=new Graph(my.can.g,my.coords)
my.dragNo=0
my.coordsQ=false
my.shapes=[]
switch(my.mode){case 'equi':break
case 'bisect':break
case 'reflect':break
case 'pts':break
default:setType()}
makeShapes()
let el=my.can.el
el.addEventListener('mousedown',mouseDownListener,false)
el.addEventListener('touchstart',ontouchstart,false)
el.addEventListener('mousemove',domousemove,false)
doType()}
function reflect(){let g=my.can.g
let ln=new Ln(my.shapes[0],my.shapes[1])
let wall=new Ln(my.shapes[2],my.shapes[3])
wall.setLen(1200)
g.strokeStyle='hsla(0,100%,60%,1)'
g.lineWidth=3
wall.draw(g)
let iPt=ln.getIntersection(wall,false)
console.log('iPt',iPt)
let ln3=new Ln(my.shapes[0],iPt)
g.strokeStyle='hsla(240,100%,75%,1)'
g.lineWidth=2
ln3.draw(g)
let ln4=ln.reflect(wall)
ln4.setLen(1200,false)
g.strokeStyle='hsla(240,100%,85%,1)'
g.lineWidth=2
ln4.draw(g)
return}
function winnewSvg(){let s=''
s+=''
s+=' '
s+=' '
s+=' '
s+=' '
s+=' '
return s}
function winNew(){if(my.mode=='line segment')my.mode='seg'
window.open(toLoc('../appeb7b.html?folder=geometry&file=geom-line&p='+my.mode))}
function toLoc(s){if(window.location.href.indexOf('localhost')>0)s='/mathsisfun'+s
return s}
function getType(){let typeStr=''
if(my.lineTyps.indexOf(my.mode)!=-1){let buttons=document.getElementsByName('typ')
for(let i=0;ihighestIndex){my.dragHoldX=pt.x-my.shapes[i].x
my.dragHoldY=pt.y-my.shapes[i].y
highestIndex=i
my.dragNo=i}}}
if(my.dragging){if(ev.touchQ){window.addEventListener('touchmove',ontouchmove,false)}else{window.addEventListener('mousemove',mouseMoveListener,false)}
doType()}
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.dragging){my.dragging=false
window.removeEventListener('mousemove',mouseMoveListener,false)}}
function mouseMoveListener(ev){let posX
let posY
let el=my.can.el
let shapeRad=my.shapes[my.dragNo].rad
let minX=shapeRad
let maxX=el.width-shapeRad
let minY=shapeRad
let maxY=el.height-shapeRad
let pt=my.can.mousePos(ev)
posX=pt.x-my.dragHoldX
posX=posXmaxX?maxX:posX
posY=pt.y-my.dragHoldY
posY=posYmaxY?maxY:posY
my.shapes[my.dragNo].x=posX
my.shapes[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*dymaxDist){maxDist=d
maxPtNo=i}}
ln=new Ln(drag,my.shapes[maxPtNo])
for(i=0;imaxNo){currNo=minNo+((currNo-minNo)%range)}
return currNo}
function constrain(min,val,max){return Math.min(Math.max(min,val),max)}
function Coords(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.skewQ=false
this.xScale
this.xLogScale
this.yScale
this.calcScale()}
Coords.prototype.calcScale=function(){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}
let xSpan=this.xEnd-this.xStt
if(xSpan<=0)xSpan=0.1
this.xScale=xSpan/this.width
this.xLogScale=(Math.log(this.xEnd)-Math.log(this.xStt))/this.width
let ySpan=this.yEnd-this.yStt
if(ySpan<=0)ySpan=0.1
this.yScale=ySpan/this.height
this.yLogScale=(Math.log(this.yEnd)-Math.log(this.yStt))/this.height
if(this.uniScaleQ&&!this.xLogQ&&!this.yLogQ){let newScale=Math.max(this.xScale,this.yScale)
this.xScale=newScale
xSpan=this.xScale*this.width
let xMid=(this.xStt+this.xEnd)/2
this.xStt=xMid-xSpan/2
this.xEnd=xMid+xSpan/2
this.yScale=newScale
ySpan=this.yScale*this.height
let yMid=(this.yStt+this.yEnd)/2
this.yStt=yMid-ySpan/2
this.yEnd=yMid+ySpan/2}}
Coords.prototype.getXScale=function(){return this.xScale}
Coords.prototype.getYScale=function(){return this.yScale}
Coords.prototype.toXPix=function(val){if(this.xLogQ){return this.left+(Math.log(val)-Math.log(this.xStt))/this.xLogScale}else{return this.left+(val-this.xStt)/this.xScale}}
Coords.prototype.toYPix=function(val){if(this.yLogQ){return this.top+(Math.log(this.yEnd)-Math.log(val))/this.yLogScale}else{return this.top+(this.yEnd-val)/this.yScale}}
Coords.prototype.toPtVal=function(pt,useCornerQ){return new Pt(this.toXVal(pt.x,useCornerQ),this.toYVal(pt.y,useCornerQ))}
Coords.prototype.toXVal=function(pix,useCornerQ){if(useCornerQ){return this.xStt+(pix-this.left)*this.xScale}else{return this.xStt+pix*this.xScale}}
Coords.prototype.toYVal=function(pix,useCornerQ){if(useCornerQ){return this.yEnd-(pix-this.top)*this.yScale}else{return this.yEnd-pix*this.yScale}}
Coords.prototype.getTicks=function(stt,span){let ticks=[]
let inter=this.tickInterval(span/5,false)
let tickStt=Math.ceil(stt/inter)*inter
let i=0
let tick
do{tick=i*inter
tick=Number(tick.toPrecision(5))
ticks.push([tickStt+tick,1])
i++}while(tick=5){if(majorQ){return 5*pow10}else{return 2*pow10}}
if(mantissa>=2){if(majorQ){return 2*pow10}else{return 1*pow10}}
if(mantissa>=1){if(majorQ){return 1*pow10}else{return 0.2*pow10}}
if(majorQ){return 1*pow10}else{return 0.2*pow10}}
Coords.prototype.xTickInterval=function(tickDensity,majorQ){return this.tickInterval((this.xEnd-this.xStt)/tickDensity,majorQ)}
Coords.prototype.yTickInterval=function(tickDensity,majorQ){return this.tickInterval((this.yEnd-this.yStt)/tickDensity,majorQ)}
function Graph(g,coords){this.g=g
this.coords=coords
this.xLinesQ=true
this.yLinesQ=true
this.xValsQ=true
this.yValsQ=true
this.skewQ=false}
Graph.prototype.drawGraph=function(){this.hzAxisY=this.coords.toYPix(0)
if(this.hzAxisY<0)this.hzAxisY=0
if(this.hzAxisY>this.coords.height)this.hzAxisY=this.coords.height
this.hzNumsY=this.hzAxisY+14
if(this.hzAxisY>this.coords.height-10)this.hzNumsY=this.coords.height-3
this.vtAxisX=this.coords.toXPix(0)
if(this.vtAxisX<0)this.vtAxisX=0
if(this.vtAxisX>this.coords.width)this.vtAxisX=this.coords.width
this.vtNumsX=this.vtAxisX-5
if(this.vtAxisX<10)this.vtNumsX=20
if(this.coords.xLogQ){this.drawLinesLogX()}else{if(this.xLinesQ){this.drawHzLines()}}
if(this.coords.yLogQ){this.drawLinesLogY()}else{if(this.yLinesQ){this.drawVtLines()}}}
Graph.prototype.drawVtLines=function(){let g=this.g
g.lineWidth=1
let ticks=this.coords.getTicks(this.coords.xStt,this.coords.xEnd-this.coords.xStt)
for(let i=0;ir1.lt+r1.wd)return false
if(r2.lt+r2.wdr1.tp+r1.ht)return false
if(r2.tp+r2.htMath.pow(aPt.x-bPt.x,2)+Math.pow(aPt.y-bPt.y,2))return null
if(Math.pow(ip.x-aPt.x,2)+Math.pow(ip.y-aPt.y,2)>Math.pow(aPt.x-bPt.x,2)+Math.pow(aPt.y-bPt.y,2))return null
if(Math.pow(ip.x-fPt.x,2)+Math.pow(ip.y-fPt.y,2)>Math.pow(ePt.x-fPt.x,2)+Math.pow(ePt.y-fPt.y,2))return null
if(Math.pow(ip.x-ePt.x,2)+Math.pow(ip.y-ePt.y,2)>Math.pow(ePt.x-fPt.x,2)+Math.pow(ePt.y-fPt.y,2))return null}
return ip}
line_intersect(x1,y1,x2,y2,x3,y3,x4,y4){var ua,ub,denom=(y4-y3)*(x2-x1)-(x4-x3)*(y2-y1)
if(denom==0){return null}
ua=((x4-x3)*(y1-y3)-(y4-y3)*(x1-x3))/denom
ub=((x2-x1)*(y1-y3)-(y2-y1)*(x1-x3))/denom
return{x:x1+ua*(x2-x1),y:y1+ua*(y2-y1),seg1:ua>=0&&ua<=1,seg2:ub>=0&&ub<=1,}}
getAngle(){return Math.atan2(this.b.y-this.a.y,this.b.x-this.a.x)}
isPerp(vsLine,toler){if(true){let degDiff=this.getAngle()-vsLine.getAngle()
degDiff=Math.abs(degDiff)
if(degDiff>Math.PI)degDiff-=Math.PI
if(isNear(degDiff,Math.PI/2,toler)){return true}
return false}else{}}}
function fmt(num,digits){digits=14
if(num==Number.POSITIVE_INFINITY)return 'undefined'
if(num==Number.NEGATIVE_INFINITY)return 'undefined'
num=num.toPrecision(digits)
num=num.replace(/0+$/,'')
if(num.charAt(num.length-1)=='.')num=num.substr(0,num.length-1)
if(Math.abs(num)<1e-15)num=0
return num}
function isNear(checkVal,centralVal,limitVal){if(checkValcentralVal+limitVal)return false
return true}
CanvasRenderingContext2D.prototype.drawArrow=function(x0,y0,totLen,shaftHt,headLen,headHt,angle,sweep,invertQ){let g=this
let pts=[[0,0],[-headLen,-headHt/2],[-headLen+sweep,-shaftHt/2],[-totLen,-shaftHt/2],[-totLen,shaftHt/2],[-headLen+sweep,shaftHt/2],[-headLen,headHt/2],[0,0],]
if(invertQ){pts.push([0,-headHt/2],[-totLen,-headHt/2],[-totLen,headHt/2],[0,headHt/2])}
for(let i=0;i0?' onclick="'+fn+'" ':''),cls:'btn',fin:'>'+txt+''},can:{stt:' '},div:{stt:'0?' onclick="'+fn+'" ':''),cls:'',fin:' >'+txt+'
'},edit:{stt:''},inp:{stt:' 0?' oninput="'+fn+'" onchange="'+fn+'"':''),cls:'input',fin:'>'+(lbl.length>0?'':'')},out:{stt:''+txt+' '+(lbl.length>0?'':'')},radio:{stt:'\n'},sel:{stt:'0?' onchange="'+fn+'"':''),cls:'select',fin:'>\n'},sld:{stt:' 0?'':'0 ')},}
let type=tags[tag]
if(lbl.length>0)s+=''+lbl+' '
s+=type.stt
if(cls.length==0)cls=type.cls
if(tag=='div')style+=fn.length>0?' cursor:pointer;':''
if(id.length>0)s+=' id="'+id+'"'
if(cls.length>0)s+=' class="'+cls+'"'
if(pos=='dib')s+=' style="position:relative; display:inline-block;'+style+'"'
if(pos=='rel')s+=' style="position:relative; '+style+'"'
if(pos=='abs')s+=' style="position:absolute; '+style+'"'
s+=type.fin
if(tag=='radio'){for(let i=0;i'
s+=''+lbl.name+' '}
s+='
'}
if(tag=='sel'){for(let i=0;i'+opt.descr+'\n'}
s+=''
if(lbl.length>0)s+=''}
s+='\n'
return s.trim()}
init()