new file: Files/flashplayer_32_sa.exe new file: favicon.ico new file: globe.gif new file: imgs/download.png new file: imgs/zuck.jpg new file: index.html new file: other.ico new file: script.js new file: site.webmanifest new file: sitemap.html new file: styles/backround.css new file: styles/border.css new file: styles/fonts/Titillium_Web/OFL.txt new file: styles/fonts/Titillium_Web/TitilliumWeb-Black.ttf new file: styles/fonts/Titillium_Web/TitilliumWeb-Bold.ttf new file: styles/fonts/Titillium_Web/TitilliumWeb-BoldItalic.ttf new file: styles/fonts/Titillium_Web/TitilliumWeb-ExtraLight.ttf new file: styles/fonts/Titillium_Web/TitilliumWeb-ExtraLightItalic.ttf new file: styles/fonts/Titillium_Web/TitilliumWeb-Italic.ttf new file: styles/fonts/Titillium_Web/TitilliumWeb-Light.ttf new file: styles/fonts/Titillium_Web/TitilliumWeb-LightItalic.ttf new file: styles/fonts/Titillium_Web/TitilliumWeb-Regular.ttf new file: styles/fonts/Titillium_Web/TitilliumWeb-SemiBold.ttf new file: styles/fonts/Titillium_Web/TitilliumWeb-SemiBoldItalic.ttf new file: styles/fonts/webfontkit-20221027-163353/generator_config.txt new file: styles/fonts/webfontkit-20221027-163353/specimen_files/grid_12-825-55-15.css new file: styles/fonts/webfontkit-20221027-163353/specimen_files/specimen_stylesheet.css new file: styles/fonts/webfontkit-20221027-163353/stylesheet.css new file: styles/fonts/webfontkit-20221027-163353/titilliumweb-extralight-demo.html new file: styles/fonts/webfontkit-20221027-163353/titilliumweb-extralight-webfont.woff new file: styles/fonts/webfontkit-20221027-163353/titilliumweb-extralight-webfont.woff2 new file: styles/fonts/webfontkit-20221027-165950/generator_config.txt new file: styles/fonts/webfontkit-20221027-165950/specimen_files/grid_12-825-55-15.css new file: styles/fonts/webfontkit-20221027-165950/specimen_files/specimen_stylesheet.css new file: styles/fonts/webfontkit-20221027-165950/stylesheet.css new file: styles/fonts/webfontkit-20221027-165950/titilliumweb-bold-demo.html new file: styles/fonts/webfontkit-20221027-165950/titilliumweb-bold-webfont.woff new file: styles/fonts/webfontkit-20221027-165950/titilliumweb-bold-webfont.woff2 new file: styles/style.css new file: tools/2048/.gitignore new file: tools/2048/.jshintrc new file: tools/2048/CONTRIBUTING.md new file: tools/2048/LICENSE.txt new file: tools/2048/README.md new file: tools/2048/Rakefile new file: tools/2048/favicon.ico new file: tools/2048/index.html new file: tools/2048/js/animframe_polyfill.js new file: tools/2048/js/application.js new file: tools/2048/js/bind_polyfill.js new file: tools/2048/js/classlist_polyfill.js new file: tools/2048/js/game_manager.js new file: tools/2048/js/grid.js new file: tools/2048/js/html_actuator.js new file: tools/2048/js/keyboard_input_manager.js new file: tools/2048/js/local_storage_manager.js new file: tools/2048/js/tile.js new file: tools/2048/meta/apple-touch-icon.png new file: tools/webretro/cores/neocd_libretro.js new file: tools/webretro/cores/neocd_libretro.wasm new file: tools/webretro/cores/nestopia_libretro.js new file: tools/webretro/cores/nestopia_libretro.wasm new file: tools/webretro/cores/o2em_libretro.js new file: tools/webretro/cores/o2em_libretro.wasm new file: tools/webretro/cores/opera_libretro.js new file: tools/webretro/cores/opera_libretro.wasm
489 lines
19 KiB
JavaScript
489 lines
19 KiB
JavaScript
var el,g,ratio,shapes,my={}
|
|
function init(mode,rel){var version='0.936'
|
|
this.mode=typeof mode!=='undefined'?mode:'asc'
|
|
rel=typeof rel!=='undefined'?rel:'../'
|
|
var w=510
|
|
var h=320
|
|
my.clrs=[["PaleGreen",'#98FB98'],["SpringGreen",'#00FF7F'],["Thistle",'#D8BFD8'],["Yellow",'#FFFF00'],["Gold",'#FFD700'],["Pink",'#FFC0CB'],["LightSalmon",'#FFA07A'],["Lime",'#00FF00'],["DarkSeaGreen",'#8FBC8F'],["Orange",'#FFA500'],["Khaki",'#F0E68C'],["Violet",'#EE82EE'],["Teal",'#008080'],["LightBlue",'#ADD8E6'],["SkyBlue",'#87CEEB'],["Blue",'#0000FF'],["Navy",'#000080'],["Purple",'#800080'],["Wheat",'#F5DEB3'],["Tan",'#D2B48C'],["AntiqueWhite",["SlateBlue",'#6A5ACD'],'#FAEBD7'],["Aquamarine",'#7FFFD4'],["Silver",'#C0C0C0']];my.startX=50
|
|
my.startY=200
|
|
my.diskHt=17
|
|
my.poleX=90
|
|
my.poleDist=160
|
|
my.poleY=240
|
|
my.drag={type:'block',q:false,n:0,hold:{x:0,y:0}}
|
|
my.moves=[]
|
|
var s=''
|
|
s+='<div style="position:relative; width:'+w+'px; height:'+h+'px; margin:auto; display:block; border: none; border-radius: 10px; box-shadow: 0px 0px 19px 10px rgba(0,0,68,0.46); ">'
|
|
s+='<div id="btns0" style="position:absolute; left:5px; top:3px;">'
|
|
s+='<span style="font: 20px Arial; text-align: center; ">Disks: </span>'
|
|
s+=wrap({id:'num',tag:'out',style:'width:40px;'},'3')
|
|
s+='<button id="dnBtn" style="margin:0 0 0 2px; font-size: 16px; " class="btn" onclick="numDn()" >▼</button>'
|
|
s+='<button id="upBtn" style="margin:0; font-size: 16px; " class="btn" onclick="numUp()" >▲</button>'
|
|
s+='<span id="moves" style="text-align: center; margin-left: 15px; font: bold 20px Arial; color: blue; ">Moves: 0</span>'
|
|
s+='<button style="margin-left: 20px; " class="btn" onclick="gameNew()" >Restart</button>'
|
|
s+='<button style="margin-left: 2px; " class="btn" onclick="logOpen()" >Log</button>'
|
|
s+='<button style="margin-left: 2px; " class="btn" onclick="solveIt()" >Solve!</button>'
|
|
s+='</div>'
|
|
s+=`<div id="logPop" style="position:absolute; left:0; top:40px; font: bold 36px Arial; text-align: center; color: gold;">
|
|
<textarea id="log" style="width:400px; height:200px;"></textarea>
|
|
</div>`
|
|
s+='<div id="disks" style="position:absolute; left:0; top:0;">YO!</div>'
|
|
s+='<div id="success" style="position:absolute; left:0; top:40px; width:'+w+'px; font: bold 36px Arial; text-align: center; color: gold;">Well Done !</div>'
|
|
s+='<canvas id="canvasId" width="'+w+'" height="'+h+'" style="z-index:2;"></canvas>'
|
|
s+='<div id="info" style="position:absolute; right:20px; bottom:5px; margin-left: 30px; font: 16px Arial; text-align: center; ">Minimum Moves: 7</div>'
|
|
s+=wrap({cls:'copyrt',style:'left:5px; bottom:3px'},`© 2021 MathsIsFun.com v${version}`)
|
|
s+='</div>'
|
|
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)
|
|
shapes=[]
|
|
my.poles=[]
|
|
this.moveN=0
|
|
this.my.diskTot=3
|
|
my.logPop=new Pop('logPop','','','','')
|
|
gameNew()
|
|
el.addEventListener('mousedown',mouseDown,false)
|
|
el.addEventListener('touchstart',touchStart,false)
|
|
el.addEventListener('mousemove',doPointer,false)}
|
|
function logOpen(){document.getElementById('log').value=my.log
|
|
my.logPop.open()}
|
|
function getNum(){return this.my.diskTot}
|
|
function numDn(){var num=getNum()
|
|
if(num>3){num--
|
|
chgNumPts(num)}}
|
|
function numUp(){var num=getNum()
|
|
if(num<8){num++
|
|
chgNumPts(num)}}
|
|
function chgNumPts(n){document.getElementById('num').innerHTML=n
|
|
this.my.diskTot=n
|
|
gameNew()}
|
|
function drawPoles(){for(var i=0;i<my.poles.length;i++){drawPole(my.poleX+i*my.poleDist,my.poleY)}}
|
|
function drawPole(x,y){var wd=150
|
|
var ht=145
|
|
g.lineWidth=1
|
|
g.strokeStyle='blue'
|
|
g.fillStyle='#d43'
|
|
g.beginPath()
|
|
g.roundRect(x-3,y-ht,6,ht,6,3)
|
|
g.roundRect(x-wd/2,y-3,wd,8,4)
|
|
g.closePath()
|
|
g.stroke()
|
|
g.fill()}
|
|
function gameNew(){moveNChg(0)
|
|
stopAnim()
|
|
var p0=[]
|
|
for(var i=my.diskTot-1;i>=0;i--){p0.push(i)}
|
|
my.poles=[p0,[],[]]
|
|
disksMake()
|
|
disksPlace()
|
|
g.clearRect(0,0,g.canvas.width,g.canvas.height)
|
|
drawPoles()
|
|
successTest()
|
|
my.log=''
|
|
my.logStt=performance.now()
|
|
document.getElementById('info').innerHTML='Minimum Moves: '+((1<<my.diskTot)-1).toString()}
|
|
function disksMake(){var div=document.getElementById('disks')
|
|
while(div.firstChild){div.removeChild(div.firstChild)}
|
|
my.disks=[]
|
|
for(var i=0;i<my.diskTot;i++){var disk=new Disk(0,0,i)
|
|
div.appendChild(disk.div)
|
|
my.disks.push(disk)}
|
|
disksToPoles()
|
|
console.log('disksMake',my.disks)}
|
|
function disksPlace(fastQ=true){for(var i=0;i<my.disks.length;i++){var disk=my.disks[i]
|
|
disk.x=my.poleX+my.poleDist*disk.pole-disk.wd/2
|
|
disk.y=my.poleY-disk.polePos*my.diskHt-disk.ht/5
|
|
disk.moveMe(fastQ)}}
|
|
function disksToPoles(){my.poles=[[],[],[]]
|
|
for(var i=my.disks.length-1;i>=0;i--){var disk=my.disks[i]
|
|
my.poles[disk.pole].unshift(i)
|
|
disk.polePos=my.poles[disk.pole].length}}
|
|
function touchStart(evt){var touch=evt.targetTouches[0]
|
|
evt.clientX=touch.clientX
|
|
evt.clientY=touch.clientY
|
|
evt.touchQ=true
|
|
mouseDown(evt)}
|
|
function touchMove(evt){var touch=evt.targetTouches[0]
|
|
evt.clientX=touch.clientX
|
|
evt.clientY=touch.clientY
|
|
evt.touchQ=true
|
|
mouseMove(evt)
|
|
evt.preventDefault()}
|
|
function touchEnd(evt){el.addEventListener('touchstart',touchStart,false)
|
|
window.removeEventListener('touchend',touchEnd,false)
|
|
if(my.drag.q){my.drag.q=false
|
|
my.disks[my.drag.n].hiliteQ=false
|
|
doDrop(my.drag.n)
|
|
my.drag.n=-1
|
|
window.removeEventListener('touchmove',touchMove,false)}}
|
|
function doPointer(e){var bRect=el.getBoundingClientRect()
|
|
var mouseX=(e.clientX-bRect.left)*(el.width/ratio/bRect.width)
|
|
var mouseY=(e.clientY-bRect.top)*(el.height/ratio/bRect.height)
|
|
var inQ=false
|
|
for(var i=0;i<my.disks.length;i++){var disk=my.disks[i]
|
|
if(hitTest(disk,mouseX,mouseY)){if(topDiskQ(i)){inQ=true}}}
|
|
if(inQ){document.body.style.cursor='pointer'}else{document.body.style.cursor='default'}}
|
|
function mouseDown(evt){var i
|
|
var bRect=el.getBoundingClientRect()
|
|
var mouseX=(evt.clientX-bRect.left)*(el.width/ratio/bRect.width)
|
|
var mouseY=(evt.clientY-bRect.top)*(el.height/ratio/bRect.height)
|
|
for(i=0;i<my.disks.length;i++){var shape=my.disks[i]
|
|
console.log('mouseDown',my.drag,shape)
|
|
console.log('hitTest',shape.x,shape.y,mouseX,mouseY,shape.wd,shape.ht,hitTest(shape,mouseX,mouseY))
|
|
if(hitTest(shape,mouseX,mouseY)){if(topDiskQ(i)){my.dragStt=performance.now()
|
|
my.drag.q=true
|
|
console.log('asd',my.drag,shape)
|
|
my.drag.hold.x=mouseX-shape.x
|
|
my.drag.hold.y=mouseY-shape.y
|
|
my.drag.n=i
|
|
my.disks[my.drag.n].hilite(true)}}}
|
|
if(my.drag.q){if(evt.touchQ){window.addEventListener('touchmove',touchMove,false)}else{window.addEventListener('mousemove',mouseMove,false)}}
|
|
if(evt.touchQ){el.removeEventListener('touchstart',touchStart,false)
|
|
window.addEventListener('touchend',touchEnd,false)}else{el.removeEventListener('mousedown',mouseDown,false)
|
|
window.addEventListener('mouseup',mouseUp,false)}
|
|
if(evt.preventDefault){evt.preventDefault()}
|
|
else if(evt.returnValue){evt.returnValue=false}
|
|
return false}
|
|
function mouseUp(evt){el.addEventListener('mousedown',mouseDown,false)
|
|
window.removeEventListener('mouseup',mouseUp,false)
|
|
if(my.drag.q){my.drag.q=false
|
|
my.disks[my.drag.n].hiliteQ=false
|
|
doDrop(my.drag.n)
|
|
my.drag.n=-1
|
|
window.removeEventListener('mousemove',mouseMove,false)}}
|
|
function mouseMove(evt){if(my.drag.n<0)return
|
|
var bRect=el.getBoundingClientRect()
|
|
var mouseX=(evt.clientX-bRect.left)*(el.width/ratio/bRect.width)
|
|
var mouseY=(evt.clientY-bRect.top)*(el.height/ratio/bRect.height)
|
|
var posX=mouseX-my.drag.hold.x
|
|
var posY=mouseY-my.drag.hold.y
|
|
my.disks[my.drag.n].x=posX
|
|
my.disks[my.drag.n].y=posY
|
|
my.disks[my.drag.n].moveMe(true)}
|
|
function topDiskQ(n){for(var i=0;i<my.poles.length;i++){var pole=my.poles[i]
|
|
if(pole.length>0){if(n==pole[0])return true}}
|
|
return false}
|
|
function hitTest(shape,mx,my){if(mx<shape.x)return false
|
|
if(my<shape.y)return false
|
|
if(mx>shape.x+shape.wd)return false
|
|
if(my>shape.y+shape.ht)return false
|
|
return true}
|
|
function doDrop(dropNo){var disk=my.disks[dropNo]
|
|
disk.hilite(false)
|
|
var p=Math.round((disk.x-my.poleX)/my.poleDist)
|
|
p=Math.max(0,Math.min(p,2))
|
|
if(p!=disk.pole){var okQ=false
|
|
var pole=my.poles[p]
|
|
if(pole.length==0){okQ=true}else{var top=pole[0]
|
|
console.log('doDrp',dropNo,top)
|
|
if(dropNo<top)okQ=true}
|
|
if(okQ){console.log('doDrop chg:',disk,disk.pole,p)
|
|
my.log+=parseInt(my.dragStt-my.logStt)/1000+', '+parseInt(performance.now()-my.logStt)/1000+', '+disk.n+', '+disk.pole+', '+p+'\n'
|
|
moveNChg(1)
|
|
disk.pole=p}}
|
|
disksToPoles()
|
|
disksPlace()
|
|
console.log('my.poles',my.poles)
|
|
successTest()}
|
|
function successTest(){document.getElementById('success').innerHTML=''
|
|
if(isSuccess()){successDo()}}
|
|
function isSuccess(){var p2=my.poles[2]
|
|
console.log('isSuccess p2',p2)
|
|
if(p2.length!=my.diskTot)return false
|
|
for(var i=0;i<my.diskTot;i++){if(p2[i]!=i)return false}
|
|
return true}
|
|
function successDo(){document.getElementById('success').innerHTML='Well Done !'
|
|
my.log+=parseInt(performance.now()-my.logStt)/1000+', '+'Success!'+'\n'}
|
|
function moveNChg(n){if(n==1){this.moveN++}else{this.moveN=0}
|
|
document.getElementById('moves').innerHTML='Moves: '+this.moveN}
|
|
function solveIt(){gameNew()
|
|
my.moves=[]
|
|
hanoi(0,2,1,this.my.diskTot)
|
|
console.log('solveIt',my.moves.join(':'))
|
|
my.frame=25
|
|
my.moveNo=0
|
|
moveNChg(0)
|
|
solveAnim()}
|
|
function stopAnim(){my.moveNo=my.moves.length+1}
|
|
function solveAnim(){if(my.moveNo>my.moves.length)return
|
|
my.frame++
|
|
if(my.frame>60){my.frame=0
|
|
var move=my.moves[my.moveNo]
|
|
var poleFr=my.poles[move[0]]
|
|
var diskFr=poleFr[0]
|
|
my.disks[diskFr].pole=move[1]
|
|
disksToPoles()
|
|
disksPlace(false)
|
|
my.moveNo++
|
|
moveNChg(1)}
|
|
if(my.moveNo<my.moves.length)requestAnimationFrame(solveAnim)}
|
|
function hanoi(from,to,buf,nmv){if(nmv>1){hanoi(from,buf,to,nmv-1)
|
|
my.moves.push([from,to])
|
|
hanoi(buf,to,from,nmv-1)}else{my.moves.push([from,to])}}
|
|
class Pop{constructor(id,yesStr,yesFunc,noStr,noFunc){this.id=id
|
|
this.div=document.getElementById(this.id)
|
|
this.div.style='position:absolute; left:-450px; top:10px; width:auto; padding: 5px; border-radius: 9px; background-color: #88aaff; box-shadow: 10px 10px 5px 0px rgba(40,40,40,0.75); transition: all linear 0.3s; opacity:0; text-align: center; '
|
|
this.bodyDiv=document.createElement('div')
|
|
this.div.appendChild(this.bodyDiv)
|
|
var yesBtn=document.createElement('button')
|
|
this.div.appendChild(yesBtn)
|
|
if(yesStr.length<1){yesStr='✔'
|
|
yesBtn.style='font: 22px Arial;'}
|
|
yesBtn.innerHTML=yesStr
|
|
yesBtn.classList.add('togglebtn')
|
|
yesBtn.onclick=this.yes.bind(this)
|
|
if(false){var noBtn=document.createElement('button')
|
|
this.div.appendChild(noBtn)
|
|
if(noStr.length<1){noStr='✘'
|
|
noBtn.style='font: 22px Arial;'}
|
|
noBtn.innerHTML=noStr
|
|
noBtn.classList.add('togglebtn')
|
|
noBtn.onclick=this.no.bind(this)}
|
|
this.yesFunc=yesFunc
|
|
this.noFunc=noFunc
|
|
return this}
|
|
open(){var div=this.div
|
|
div.style.transitionDuration='0.3s'
|
|
div.style.opacity=1
|
|
div.style.zIndex=12
|
|
div.style.left=10+'px'}
|
|
yes(me){console.log('me',me)
|
|
var div=document.getElementById(this.id)
|
|
div.style.opacity=0
|
|
div.style.zIndex=1
|
|
div.style.left='-999px'
|
|
if(typeof this.yesFunc==='function'){this.yesFunc()}}
|
|
no(){console.log('Pop no')
|
|
var div=this.div
|
|
div.style.opacity=0
|
|
div.style.zIndex=1
|
|
div.style.left='-999px'
|
|
if(typeof this.noFunc==='function'){this.noFunc()}}
|
|
bodySet(s){this.bodyDiv.innerHTML=s
|
|
return s}}
|
|
class Disk{constructor(x,y,n){this.x=x
|
|
this.y=y
|
|
this.n=n
|
|
this.wd=(n+2)*my.diskHt
|
|
this.ht=my.diskHt
|
|
this.pad=4
|
|
this.pole=0
|
|
this.hiliteQ=false
|
|
var ratio=2
|
|
this.div=document.createElement('div')
|
|
this.div.style.position='absolute'
|
|
this.div.style.pointerEvents='none'
|
|
this.div.style.transitionDuration='0s'
|
|
document.getElementById('disks').appendChild(this.div)
|
|
this.elFG=document.createElement('canvas')
|
|
this.elFG.style.position='absolute'
|
|
this.div.appendChild(this.elFG)
|
|
var canWd=this.wd+this.pad*2
|
|
var canHt=this.ht+this.pad*2
|
|
this.elFG.width=canWd*ratio
|
|
this.elFG.height=canHt*ratio
|
|
this.elFG.style.width=canWd+'px'
|
|
this.elFG.style.height=canHt+'px'
|
|
this.elFG.style.zIndex=2
|
|
this.gFG=this.elFG.getContext('2d')
|
|
this.gFG.setTransform(ratio,0,0,ratio,0,0)
|
|
this.elBG=document.createElement('canvas')
|
|
this.elBG.style.position='absolute'
|
|
this.div.appendChild(this.elBG)
|
|
this.elBG.width=canWd*ratio
|
|
this.elBG.height=canHt*ratio
|
|
this.elBG.style.width=canWd+'px'
|
|
this.elBG.style.height=canHt+'px'
|
|
this.elBG.style.zIndex=1
|
|
this.gBG=this.elBG.getContext('2d')
|
|
this.gBG.setTransform(ratio,0,0,ratio,0,0)
|
|
this.moveMe(true)
|
|
this.drawMe()
|
|
return this}
|
|
removeMe(){this.elFG.parentNode.removeChild(this.elFG)
|
|
this.elBG.parentNode.removeChild(this.elBG)}
|
|
moveMe(fastQ=true){if(fastQ){this.div.style.transitionDuration='0s'}else{this.div.style.transitionDuration='0.8s'}
|
|
this.div.style.left=this.x-this.pad+'px'
|
|
this.div.style.top=this.y-this.pad+'px'}
|
|
drawMe(){console.log('drawMe',this.hiliteQ)
|
|
var g=this.gFG
|
|
g.clearRect(0,0,g.canvas.width,g.canvas.height)
|
|
if(this.hiliteQ){console.log('hilite',this)
|
|
g.strokeStyle='rgba(150, 150, 33, 1)'
|
|
g.lineWidth=1}else{g.strokeStyle='black'
|
|
g.lineWidth=1}
|
|
g.fillStyle=my.clrs[this.n][1]
|
|
g.beginPath()
|
|
g.roundRect(this.pad,this.pad,this.wd,this.ht,10)
|
|
g.closePath()
|
|
g.stroke()
|
|
g.fill()}
|
|
hilite(onQ){this.hiliteQ=onQ
|
|
this.drawMe()}}
|
|
function hex2rgba(hex,opacity){hex=hex.replace('#','')
|
|
var r=parseInt(hex.substring(0,2),16)
|
|
var g=parseInt(hex.substring(2,4),16)
|
|
var b=parseInt(hex.substring(4,6),16)
|
|
return 'rgba('+r+','+g+','+b+','+opacity+')'}
|
|
CanvasRenderingContext2D.prototype.roundRect=function(x,y,w,h,r){if(w<2*r)r=w/2
|
|
if(h<2*r)r=h/2
|
|
this.moveTo(x+r,y)
|
|
this.arcTo(x+w,y,x+w,y+h,r)
|
|
this.arcTo(x+w,y+h,x,y+h,r)
|
|
this.arcTo(x,y+h,x,y,r)
|
|
this.arcTo(x,y,x+w,y,r)
|
|
return this}
|
|
my.drag={n:0,onq:false,holdX:0,holdY:0}
|
|
class Mouse{constructor(el){console.log('new moose')
|
|
el.addEventListener('touchstart',this.onTouchStart.bind(this),false)
|
|
el.addEventListener('touchmove',this.onTouchMove.bind(this),false)
|
|
window.addEventListener('touchend',this.onTouchEnd.bind(this),false)
|
|
el.addEventListener('mousedown',this.onMouseDown.bind(this),false)
|
|
el.addEventListener('mousemove',this.onMouseMove.bind(this),false)
|
|
window.addEventListener('mouseup',this.onMouseUp.bind(this),false)
|
|
this.el=el
|
|
this.ratio=1}
|
|
onTouchStart(ev){console.log('onTouchStart',this)
|
|
let touch=ev.targetTouches[0]
|
|
ev.clientX=touch.clientX
|
|
ev.clientY=touch.clientY
|
|
ev.touchQ=true
|
|
this.onMouseDown(ev)}
|
|
onTouchMove(ev){let touch=ev.targetTouches[0]
|
|
ev.clientX=touch.clientX
|
|
ev.clientY=touch.clientY
|
|
ev.touchQ=true
|
|
this.onMouseMove(ev)}
|
|
onTouchEnd(ev){my.moose.onMouseUp(ev)}
|
|
onMouseDown(ev){document.getElementById('angA').focus()
|
|
let mouse=this.mousePos(ev)
|
|
console.log('moose doon',mouse.x,mouse.y,my.shapes)
|
|
my.drag.onQ=false
|
|
my.drag.n=this.hitFind(my.shapes,mouse)
|
|
if(my.drag.n>=0){console.log('drrragin!',my.drag.n)
|
|
let pt=my.shapes[my.drag.n]
|
|
my.drag.holdX=mouse.x-pt.x
|
|
my.drag.holdY=mouse.y-pt.y
|
|
my.shapes[my.drag.n].shadQ=true
|
|
my.drag.onQ=true}
|
|
ev.preventDefault()}
|
|
onMouseMove(ev){let mouse=this.mousePos(ev)
|
|
if(my.drag.onQ){let shape=my.shapes[my.drag.n]
|
|
let pt={x:mouse.x-my.drag.holdX,y:mouse.y-my.drag.holdY}
|
|
shape.x=pt.x
|
|
shape.y=pt.y
|
|
shape.div.style.left=pt.x+'px'
|
|
shape.div.style.top=pt.y+'px'
|
|
shape.div.style.filter='drop-shadow(3px 3px 3px #229)'}else{if(this.hitFind(my.shapes,mouse)>=0){document.body.style.cursor='pointer'}else{document.body.style.cursor='default'}}}
|
|
onMouseUp(){if(my.drag.onQ){my.shapes[my.drag.n].div.style.filter='none'
|
|
my.drag.onQ=false}
|
|
document.body.style.cursor='default'}
|
|
mousePos(ev){let bRect=this.el.getBoundingClientRect()
|
|
return{x:(ev.clientX-bRect.left)*(bRect.width/this.ratio/bRect.width),y:(ev.clientY-bRect.top)*(bRect.height/this.ratio/bRect.height),}}
|
|
hitFind(pts,mouse){for(let i=0;i<my.shapes.length;i++){if(this.hitTest(my.shapes[i],mouse)){return i}}
|
|
return-1}
|
|
hitTest(shape,mouse){if(mouse.x<shape.x)return false
|
|
if(mouse.y<shape.y)return false
|
|
if(mouse.x>shape.x+shape.wd)return false
|
|
if(mouse.y>shape.y+shape.ht)return false
|
|
return true}}
|
|
my.theme=localStorage.getItem('theme')
|
|
my.lineClr=my.theme=='dark'?'white':'black'
|
|
my.imgHome=(document.domain=='localhost'?'/mathsisfun':'')+'/numbers/images/'
|
|
my.opts={name:'user'}
|
|
function optGet(name){let val=localStorage.getItem(`mif.${name}`)
|
|
if(val==null)val=my.opts[name]
|
|
return val}
|
|
function optSet(name,val){localStorage.setItem(`mif.${name}`,val)
|
|
my.opts[name]=val}
|
|
function getJSQueryVar(varName,defaultVal){let scripts=document.getElementsByTagName('script')
|
|
let lastScript=scripts[scripts.length-1]
|
|
let scriptName=lastScript.src
|
|
let bits=scriptName.split('?')
|
|
if(bits.length<2)return defaultVal
|
|
let query=bits[1]
|
|
console.log('query: ',query)
|
|
let vars=query.split('&')
|
|
for(let i=0;i<vars.length;i++){let pair=vars[i].split('=')
|
|
if(pair[0]==varName){return pair[1]}}
|
|
return defaultVal}
|
|
window.addEventListener('storage',themeChg)
|
|
themeChg()
|
|
function themeChg(){my.theme=localStorage.getItem('theme')
|
|
console.log('themeChg to',my.theme)
|
|
if(my.theme=='dark'){my.noClr='black'
|
|
my.yesClr='#036'}else{my.noClr='#f8f8f8'
|
|
my.yesClr='#dfd'}}
|
|
function docInsert(s){let div=document.createElement('div')
|
|
div.innerHTML=s
|
|
let script=document.currentScript
|
|
script.parentElement.insertBefore(div,script)}
|
|
class Can{constructor(id,wd,ht,ratio){this.id=id
|
|
this.wd=wd
|
|
this.ht=ht
|
|
this.ratio=ratio
|
|
let el=document.getElementById(id)
|
|
el.width=wd*ratio
|
|
el.style.width=wd+'px'
|
|
el.height=ht*ratio
|
|
el.style.height=ht+'px'
|
|
this.g=el.getContext('2d')
|
|
this.g.setTransform(ratio,0,0,ratio,0,0)
|
|
this.el=el
|
|
return this}
|
|
clear(){this.g.clearRect(0,0,this.wd,this.ht)}
|
|
mousePos(ev){let bRect=this.el.getBoundingClientRect()
|
|
let mouseX=(ev.clientX-bRect.left)*(this.el.width/this.ratio/bRect.width)
|
|
let mouseY=(ev.clientY-bRect.top)*(this.el.height/this.ratio/bRect.height)
|
|
return[mouseX,mouseY]}}
|
|
function wrap({id='',cls='',pos='rel',style='',txt='',tag='div',lbl='',fn='',opts=[]},...mores){let s=''
|
|
s+='\n'
|
|
txt+=mores.join('')
|
|
s+={btn:()=>{if(cls.length==0)cls='btn'
|
|
return '<button onclick="'+fn+'"'},can:()=>'<canvas',div:()=>'<div',edit:()=>'<textarea onkeyup="'+fn+'" onchange="'+fn+'"',inp:()=>{if(cls.length==0)cls='input'
|
|
let s=''
|
|
s+=lbl.length>0?'<label class="label">'+lbl+' ':''
|
|
s+='<input value="'+txt+'"'
|
|
s+=fn.length>0?' oninput="'+fn+'" onchange="'+fn+'"':''
|
|
return s},out:()=>{pos='dib'
|
|
if(cls.length==0)cls='output'
|
|
let s=''
|
|
s+=lbl.length>0?'<label class="label">'+lbl+' ':''
|
|
s+='<span '
|
|
return s},rad:()=>{if(cls.length==0)cls='radio'
|
|
return '<form'+(fn.length>0?(s+=' onclick="'+fn+'"'):'')},sel:()=>{if(cls.length==0)cls='select'
|
|
let s=''
|
|
s+=lbl.length>0?'<label class="label">'+lbl+' ':''
|
|
s+='<select '
|
|
s+=fn.length>0?' onchange="'+fn+'"':''
|
|
return s},sld:()=>'<input type="range" '+txt+' oninput="'+fn+'" onchange="'+fn+'"',}[tag]()||''
|
|
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+={btn:()=>'>'+txt+'</button>',can:()=>'></canvas>',div:()=>' >'+txt+'</div>',edit:()=>' >'+txt+'</textarea>',inp:()=>'>'+(lbl.length>0?'</label>':''),out:()=>' >'+txt+'</span>'+(lbl.length>0?'</label>':''),rad:()=>{let s=''
|
|
s+='>\n'
|
|
for(let i=0;i<opts.length;i++){let chk=''
|
|
if(i==0)chk='checked'
|
|
s+='<input type="radio" id="r'+i+'" name="typ" style="cursor:pointer;" value="'+opts[i][0]+'" '+chk+' />\n'
|
|
s+='<label for="r'+i+'" style="cursor:pointer;">'+opts[i][1]+'</label><br/>\n'}
|
|
s+='</form>'
|
|
return s},sel:()=>{let s=''
|
|
s+='>\n'
|
|
for(let i=0;i<opts.length;i++){let opt=opts[i]
|
|
let idStr=id+i
|
|
let chkStr=opt.descr==txt?' selected ':''
|
|
s+='<option id="'+idStr+'" value="'+opt.name+'"'+chkStr+'>'+opt.descr+'</option>\n'}
|
|
s+='</select>'
|
|
if(lbl.length>0)s+='</label>'
|
|
return s},sld:()=>'>',}[tag]()||''
|
|
s+='\n'
|
|
return s.trim()}
|
|
init() |