let s,i,my={}
function init(imode){my.version='0.891'
my.mode=typeof imode!=='undefined'?imode:'equn'
my.modes=[]
my.modes['equn']={extendQ:true,slopeQ:false}
my.modes['slope']={extendQ:true,slopeQ:true}
my.modes['intery']={extendQ:true,slopeQ:false}
my.modes['pt']={extendQ:true,slopeQ:false}
my.modes['mid']={extendQ:false,slopeQ:false}
canvasid='canvas4'
titleid='title4'
infoid='info4'
dragging=false
w=540
h=360
let s=''
s+=''
s+='
'
s+='
'
s+='
'
s+='
'
if(my.mode=='pt'){my.slope=0.5
s+='
Slope:'
s+='
'
s+='
'+my.slope+'
'}
s+='
'
s+='
'
s+='
'
s+='
© 2018 MathsIsFun.com v'+my.version+'
'
s+='
'
docInsert(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)
this.coords=new Coords(0,0,w,h,-2,-1.9,15,11,true)
this.graph=new Graph(g,coords)
this.coordsQ=true
shapes=[]
makeShapes()
drawPts()
el.addEventListener('mousedown',mouseDownListener,false)
el.addEventListener('touchstart',ontouchstart,false)
el.addEventListener('mousemove',domousemove,false)
doType()}
function onSlopeChg(n,v){v=Number(v)
my.slope=v
document.getElementById('slope').innerHTML=v
update()}
function reset(){makeShapes()
update()}
function update(){doType()}
function toggleCoords(){this.coordsQ=!this.coordsQ
toggleBtn('coordsBtn',this.coordsQ)
update()}
function toggleBtn(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(dragging){dragging=false
window.removeEventListener('touchmove',ontouchmove,false)}}
function domousemove(e){document.body.style.cursor='default'
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)
for(let i=0;ihighestIndex){dragHoldX=mouseX-shapes[i].x
dragHoldY=mouseY-shapes[i].y
highestIndex=i
dragIndex=i}}}
if(dragging){if(evt.touchQ){window.addEventListener('touchmove',ontouchmove,false)}else{window.addEventListener('mousemove',mouseMoveListener,false)}
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){el.addEventListener('mousedown',mouseDownListener,false)
window.removeEventListener('mouseup',mouseUpListener,false)
if(dragging){dragging=false
window.removeEventListener('mousemove',mouseMoveListener,false)}}
function mouseMoveListener(evt){let posX
let posY
let shapeRad=shapes[dragIndex].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)
posX=mouseX-dragHoldX
posX=posXmaxX?maxX:posX
posY=mouseY-dragHoldY
posY=posYmaxY?maxY:posY
shapes[dragIndex].x=posX
shapes[dragIndex].y=posY
doType()}
function hitTest(shape,mx,my){let dx
let dy
dx=mx-shape.x
dy=my-shape.y
return dx*dx+dy*dy0){xstr='(x − '+x1+')'}else{xstr='x'}}
let ystr
if(y1<0){ystr=' + '+-y1}else{if(y1>0){ystr=' − '+y1}else{ystr=''}}
if(my.slope==1){let simplifyQ=false
if(simplifyQ){let diff=round2(y1-x1)
if(diff<0){s='y = x − '+-diff}else{if(diff>0){s='y = x + '+diff}else{s='y = x'}}}else{s='y '+ystr+' = '+my.slope+xstr}}else{if(my.slope==0){s='y = '+y1}else{s='y '+ystr+' = '+my.slope+xstr}}
document.getElementById('descr').innerHTML=s}else{pt0=new Pt(round1(this.coords.toXVal(shapes[0].x)),round1(this.coords.toYVal(shapes[0].y)))
pt1=new Pt(round1(this.coords.toXVal(shapes[1].x)),round1(this.coords.toYVal(shapes[1].y)))
let dx=pt1.x-pt0.x
let dy=pt1.y-pt0.y
slope=dy/dx
b=pt0.y-pt0.x*slope}
if(my.mode=='equn'){let s=''
if(pt0.x==pt1.x){if(pt0.y==pt1.y){s='Need 2 different points'}else{s='x = '+pt0.x}}else{s='y = '+linearPhrase([round2(slope),round2(b)])}
document.getElementById('descr').innerHTML=s}
if(my.mode=='slope'){let s=''
if(pt0.x==pt1.x){if(pt0.y==pt1.y){s='Need 2 different points'}else{s='?'}}else{s='slope = '+''+round2(dy)+''+round2(dx)+' = '+round2(slope)
g.fillStyle='blue'
g.fillStyle='blue'
g.textAlign='center'
g.fillText(round2(dx).toString(),(shapes[0].x+shapes[1].x)/2,shapes[0].y+20)
g.fillStyle='red'
g.textAlign='left'
g.fillText(round2(dy),shapes[1].x+5,(shapes[0].y+shapes[1].y)/2)}
document.getElementById('descr').innerHTML=s}
if(my.mode=='intery'){let s=''
if(pt0.x==pt1.x){if(pt0.y==pt1.y){s='Need 2 different points'}else{s='?'}}else{if(b>this.coords.yStt&&b0){s+=' − '}else{s+=' −'}
v=-v}else{if(s.length>0){s+=' + '}}
switch(k){case 0:if(v!=1){s+=v}
s+='x'
break
case 1:s+=v
break
default:if(v!=1){s+=v}
s+='('+k+')'
break}}}
if(s.length==0){s='0'}
return s}
function Pt(ix,iy){this.x=ix
this.y=iy
this.rad=9
this.color='rgb('+0+','+0+','+255+')'
angleIn=0
angleOut=0}
Pt.prototype.setxy=function(ix,iy){this.x=ix
this.y=iy}
Pt.prototype.getAngle=function(){return this.angleOut-this.angleIn}
Pt.prototype.drawMe=function(g){g.fillStyle='rgba(0, 0, 255, 0.3)'
g.beginPath()
g.arc(this.x,this.y,20,0,2*Math.PI,false)
g.closePath()
g.fill()}
Pt.prototype.getAvg=function(pts){let xSum=0
let ySum=0
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)}
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
let xLogQ=false
let yLogQ=false
let skewQ=true
this.xScale
let xLogScale
this.yScale
console.log('Coords: ',this.xStt,this.yStt,this.xEnd,this.yEnd)
this.calcScale()}
Coords.prototype.calcScale=function(){console.log('calcScale: ',this.xStt,this.yStt,this.xEnd,this.yEnd)
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(xStt))/xLogScale}else{return this.left+(val-this.xStt)/this.xScale}}
Coords.prototype.toYPix=function(val){if(this.yLogQ){return this.top+(Math.log(yEnd)-Math.log(val))/yLogScale}else{return this.top+(this.yEnd-val)/this.yScale}}
Coords.prototype.toPtVal=function(pt,useCornerQ){return new Pt(toXVal(pt.x,useCornerQ),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
let xClr=0x4444ff
let yClr=0xff4444
this.xLinesQ=true
this.yLinesQ=true
this.xArrowQ=true
this.yArrowQ=true
this.xValsQ=true
this.yValsQ=true
this.skewQ=false}
Graph.prototype.drawGraph=function(){if(coords.xLogQ){this.drawLinesLogX()}else{if(this.xLinesQ){this.drawLinesX()}}
if(coords.yLogQ){this.drawLinesLogY()}else{if(this.yLinesQ){this.drawLinesY()}}}
Graph.prototype.drawLinesX=function(){let xAxisPos=coords.toYPix(0)
let yAxisPos=coords.toXPix(0)
let numAtAxisQ=yAxisPos>=0&&yAxisPos0&&xAxisPos=0&&yAxisPos=0&&xAxisPos=0&&xAxisPos0?' onclick="'+noProp+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:'
'}
if(tag=='sel'){for(let i=0;i'+opt.descr+'\n'}
s+=''
if(lbl.length>0)s+=''}
s+='\n'
return s.trim()}
init()