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:''+(lbl.length>0?'':'')+'0'},} let type=tags[tag] if(lbl.length>0)s+='
'} if(tag=='sel'){for(let i=0;i'+opt.descr+'\n'} s+='' if(lbl.length>0)s+=''} s+='\n' return s.trim()} init()