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
743 lines
28 KiB
JavaScript
743 lines
28 KiB
JavaScript
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+='<div style="position:relative; width:'+w+'px; height:'+h+'px; border: none; border-radius: 9px; margin:auto; display:block; box-shadow: 0px 0px 19px 10px rgba(0,0,68,0.46); ">'
|
|
s+='<canvas id="'+canvasid+'" width="'+w+'" height="'+h+'" style="z-index:10;"></canvas>'
|
|
if(my.lineTyps.indexOf(my.mode)!=-1){s+='<form onclick="doType()" id="formtype" style="position:absolute; left:5px; top:5px; text-align: left; padding: 5px; font: bold 11pt arial; color: #6600cc; background: rgba(200,220,256,0.7); border-radius: 9px; z-index:3; ">'
|
|
for(let i=0;i<my.lineTyps.length;i++){s+='<input type="radio" id="r'+i+'" name="typ" value="'+my.lineTyps[i]+'" />'
|
|
s+='<label for="r'+i+'" style="height:18px; cursor:pointer;">'+my.lineTyps[i]+'</label><br/>'}
|
|
s+='</form>'}
|
|
s+='<div id="btns2" style="position:absolute; right:3px; top:3px;">'
|
|
s+='<button id="appBtn" onclick="winNew()" style="z-index:2;" class="btn">'+winnewSvg()+'</button>'
|
|
s+='</div>'
|
|
s+='<div id="btns2" style="position:absolute; right:3px; bottom:3px;">'
|
|
s+='<button id="coordsBtn" onclick="toggleCoords()" style="z-index:2;" class="btn lo" >Coords</button>'
|
|
s+='<button id="resetBtn" onclick="reset()" style="z-index:2;" class="btn" >Reset</button>'
|
|
s+='</div>'
|
|
s+=wrap({cls:'copyrt',pos:'abs',style:'left:5px; bottom:3px'},`© 2022 Rod Pierce v${version}`)
|
|
s+='</div>'
|
|
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+='<svg xmlns="http://www.w3.org/2000/svg" width="26" height="21" version="1.1" style="stroke-width:2; fill:none; vertical-align:middle;">'
|
|
s+='<rect style="stroke:grey;" x="1" y="6" ry="4" width="19" height="13" />'
|
|
s+='<path style="stroke:#cdf;stroke-width:3;" d="m 14,6 h 6 v 6"/>'
|
|
s+='<path style="stroke:black;" d="m 16,2 h 8 v 8"/>'
|
|
s+='<path style="stroke:black;" d="m 14,12 10,-10"/>'
|
|
s+='</svg>'
|
|
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;i<buttons.length;i++){let button=buttons[i]
|
|
if(button.checked){typeStr=button.value}}}else{typeStr=my.mode}
|
|
return typeStr}
|
|
function setType(){let buttons=document.getElementsByName('typ')
|
|
for(let i=0;i<buttons.length;i++){let button=buttons[i]
|
|
if(button.value==my.mode){button.checked=true}}}
|
|
function reset(){makeShapes()
|
|
update()}
|
|
function update(){doType()}
|
|
function toggleCoords(){my.coordsQ=!my.coordsQ
|
|
toggleBtn('coordsBtn',my.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(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.dragging){my.dragging=false
|
|
window.removeEventListener('touchmove',ontouchmove,false)}}
|
|
function domousemove(ev){document.body.style.cursor='default'
|
|
let pt=my.can.mousePos(ev)
|
|
for(let i=0;i<my.shapes.length;i++){if(hitTest(my.shapes[i],pt.x,pt.y)){my.dragNo=i
|
|
document.body.style.cursor='pointer'}}}
|
|
function mouseDownListener(ev){let i
|
|
let highestIndex=-1
|
|
let pt=my.can.mousePos(ev)
|
|
for(i=0;i<my.shapes.length;i++){if(hitTest(my.shapes[i],pt.x,pt.y)){my.dragNo=i
|
|
my.dragging=true
|
|
if(i>highestIndex){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=posX<minX?minX:posX>maxX?maxX:posX
|
|
posY=pt.y-my.dragHoldY
|
|
posY=posY<minY?minY:posY>maxY?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*dy<shape.rad*shape.rad}
|
|
function doType(){my.mode=getType()
|
|
my.can.clear()
|
|
my.graph.drawGraph()
|
|
drawPts()}
|
|
function makeShapes(){let xys=[]
|
|
switch(my.mode){case 'reflect':xys=[[320,100],[200,230],[309,309],[195,87],]
|
|
break
|
|
case 'bisect':xys=[[150,220],[350,150],[309,309],[195,87],]
|
|
break
|
|
case 'collinear':xys=[[99,151,'A'],[217.45,196.2,'B'],[300,100,'C'],[400,100,'D'],]
|
|
break
|
|
case 'equi':xys=[[150,220],[350,150],[215,87],]
|
|
break
|
|
case 'pts':xys=[[150,220],[350,150],[215,87],]
|
|
break
|
|
default:xys=[[150,220],[350,150],]}
|
|
my.shapes=[]
|
|
for(let i=0;i<xys.length;i++){let xy=xys[i]
|
|
my.shapes.push(new Pt(xy[0],xy[1]))}}
|
|
function drawPts(){let i
|
|
let g=my.can.g
|
|
g.strokeStyle='rgba(0, 0, 255, 0.5)'
|
|
g.fillStyle='rgba(5, 5, 200, 1)'
|
|
g.lineWidth=2
|
|
let pt
|
|
let ln
|
|
switch(my.mode){case 'line':ln=new Ln(my.shapes[0],my.shapes[1])
|
|
ln.setLen(1500,true)
|
|
g.beginPath()
|
|
g.moveTo(ln.a.x,ln.a.y)
|
|
g.lineTo(ln.b.x,ln.b.y)
|
|
g.stroke()
|
|
break
|
|
case 'ray':ln=new Ln(my.shapes[0],my.shapes[1])
|
|
ln.setLen(1500,false)
|
|
g.beginPath()
|
|
g.moveTo(ln.a.x,ln.a.y)
|
|
g.lineTo(ln.b.x,ln.b.y)
|
|
g.stroke()
|
|
break
|
|
case 'line segment':g.beginPath()
|
|
g.moveTo(my.shapes[0].x,my.shapes[0].y)
|
|
g.lineTo(my.shapes[1].x,my.shapes[1].y)
|
|
g.stroke()
|
|
break
|
|
case 'bisect':g.beginPath()
|
|
g.moveTo(my.shapes[0].x,my.shapes[0].y)
|
|
g.lineTo(my.shapes[1].x,my.shapes[1].y)
|
|
g.stroke()
|
|
let midPt=new Pt((my.shapes[0].x+my.shapes[1].x)/2,(my.shapes[0].y+my.shapes[1].y)/2)
|
|
g.strokeStyle='orange'
|
|
g.lineWidth=2
|
|
g.beginPath()
|
|
g.arc(midPt.x,midPt.y,3,0,Math.PI*2)
|
|
g.stroke()
|
|
g.fillStyle='orange'
|
|
g.font='bold 16px Arial'
|
|
g.fillText('Mid',midPt.x+5,midPt.y+12)
|
|
g.fill()
|
|
let fix=2
|
|
let mov=3
|
|
if(my.dragNo==3){fix=3
|
|
mov=2}
|
|
let dx=my.shapes[fix].x-midPt.x
|
|
let dy=my.shapes[fix].y-midPt.y
|
|
my.shapes[mov].x=midPt.x-dx
|
|
my.shapes[mov].y=midPt.y-dy
|
|
ln=new Ln(my.shapes[0],my.shapes[1])
|
|
let ln2=new Ln(my.shapes[2],my.shapes[3])
|
|
ln2.setLen(1200,true)
|
|
g.strokeStyle='red'
|
|
g.lineWidth=1
|
|
g.beginPath()
|
|
g.moveTo(ln2.a.x,ln2.a.y)
|
|
g.lineTo(ln2.b.x,ln2.b.y)
|
|
g.stroke()
|
|
let ang=Math.atan2(dy,dx)
|
|
let s='Bisector'
|
|
if(ln.isPerp(ln2,0.03)){s='Perpendicular Bisector'
|
|
g.strokeStyle='orange'
|
|
g.lineWidth=1
|
|
g.beginPath()
|
|
g.drawBox(midPt.x,midPt.y,25,ln2.getAngle())
|
|
g.stroke()}
|
|
g.fillStyle='red'
|
|
g.font='bold 14px Arial'
|
|
g.save()
|
|
g.translate(my.shapes[mov].x+5,my.shapes[mov].y+12)
|
|
g.rotate(ang)
|
|
g.beginPath()
|
|
g.fillText(s,0,0)
|
|
g.restore()
|
|
g.fill()
|
|
break
|
|
case 'reflect':reflect()
|
|
break
|
|
case 'collinear':let drag=my.shapes[my.dragNo]
|
|
let maxDist=-1
|
|
let maxPtNo=-1
|
|
for(let i=0;i<my.shapes.length;i++){let pt=my.shapes[i]
|
|
let d=dist(drag.x-pt.x,drag.y-pt.y)
|
|
if(d>maxDist){maxDist=d
|
|
maxPtNo=i}}
|
|
ln=new Ln(drag,my.shapes[maxPtNo])
|
|
for(i=0;i<my.shapes.length;i++){pt=my.shapes[i]
|
|
if(pt!=drag){let ptNew=ln.getClosestPoint(pt)
|
|
pt.setxy(ptNew.x,ptNew.y)}}
|
|
break
|
|
case 'equi':ln=new Ln(my.shapes[0],my.shapes[1])
|
|
ln.rotateMidMe(Math.PI/2)
|
|
ln.setLen(1200,true)
|
|
g.strokeStyle='orange'
|
|
g.lineWidth=2
|
|
g.beginPath()
|
|
g.moveTo(ln.a.x,ln.a.y)
|
|
g.lineTo(ln.b.x,ln.b.y)
|
|
g.stroke()
|
|
let pNew=ln.getClosestPoint(my.shapes[2])
|
|
my.shapes[2].x=pNew.x
|
|
my.shapes[2].y=pNew.y
|
|
g.strokeStyle='grey'
|
|
g.lineWidth=1
|
|
g.beginPath()
|
|
g.moveTo(my.shapes[0].x,my.shapes[0].y)
|
|
g.lineTo(my.shapes[2].x,my.shapes[2].y)
|
|
g.stroke()
|
|
g.beginPath()
|
|
g.moveTo(my.shapes[1].x,my.shapes[1].y)
|
|
g.lineTo(my.shapes[2].x,my.shapes[2].y)
|
|
g.stroke()
|
|
break
|
|
default:}
|
|
let dbg=''
|
|
for(i=0;i<my.shapes.length;i++){g.fillStyle='rgba(120, 120, 255, 0.5)'
|
|
g.beginPath()
|
|
g.arc(my.shapes[i].x,my.shapes[i].y,my.shapes[i].rad,0,2*Math.PI,false)
|
|
g.closePath()
|
|
g.fill()
|
|
g.fillStyle='orange'
|
|
g.beginPath()
|
|
g.arc(my.shapes[i].x,my.shapes[i].y,2,0,2*Math.PI,false)
|
|
g.closePath()
|
|
g.fill()
|
|
g.textAlign='left'
|
|
if(my.coordsQ){g.font='bold 14px Arial'
|
|
let txt='('
|
|
txt+=my.coords.toXVal(my.shapes[i].x).toFixed(1)
|
|
txt+=','
|
|
txt+=my.coords.toYVal(my.shapes[i].y).toFixed(1)
|
|
txt+=')'
|
|
g.fillText(txt,my.shapes[i].x+5,my.shapes[i].y-9)}else{g.font='14px Arial'
|
|
g.fillText(String.fromCharCode(65+i),my.shapes[i].x+5,my.shapes[i].y-9)}
|
|
dbg+='['+Math.floor(my.shapes[i].x)+','+Math.floor(my.shapes[i].y)+'],'}}
|
|
class Pt{constructor(ix,iy){this.x=ix
|
|
this.y=iy
|
|
this.rad=9
|
|
this.color='rgb('+0+','+0+','+255+')'
|
|
this.angleIn=0
|
|
this.angleOut=0}
|
|
setxy(ix,iy){this.x=ix
|
|
this.y=iy}
|
|
getAngle(){return this.angleOut-this.angleIn}
|
|
drawMe(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()}
|
|
getAvg(pts){let xSum=0
|
|
let ySum=0
|
|
for(let i=0;i<pts.length;i++){xSum+=pts[i].x
|
|
ySum+=pts[i].y}
|
|
let newPt=new Pt(xSum/pts.length,ySum/pts.length)
|
|
newPt.x=xSum/pts.length
|
|
newPt.y=ySum/pts.length
|
|
return newPt}
|
|
setAvg(pts){this.setPrevPt()
|
|
let newPt=this.getAvg(pts)
|
|
this.x=newPt.x
|
|
this.y=newPt.y}
|
|
interpolate(pt1,pt2,f){this.setPrevPt()
|
|
this.x=pt1.x*f+pt2.x*(1-f)
|
|
this.y=pt1.y*f+pt2.y*(1-f)}
|
|
translate(pt,addQ){addQ=typeof addQ!=='undefined'?addQ:true
|
|
let t=new Pt(this.x,this.y)
|
|
t.x=this.x
|
|
t.y=this.y
|
|
if(addQ){t.x+=pt.x
|
|
t.y+=pt.y}else{t.x-=pt.x
|
|
t.y-=pt.y}
|
|
return t}
|
|
translateMe(pt,addQ){addQ=typeof addQ!=='undefined'?addQ:true
|
|
if(addQ){this.x+=pt.x
|
|
this.y+=pt.y}else{this.x-=pt.x
|
|
this.y-=pt.y}}
|
|
rotate(angle){let cosa=Math.cos(angle)
|
|
let sina=Math.sin(angle)
|
|
let xPos=this.x*cosa+this.y*sina
|
|
let yPos=-this.x*sina+this.y*cosa
|
|
return new Pt(xPos,yPos)}
|
|
rotateMe(angle){let t=new Pt(this.x,this.y).rotate(angle)
|
|
this.x=t.x
|
|
this.y=t.y}
|
|
multiply(fact){return new Pt(this.x*fact,this.y*fact)}
|
|
multiplyMe(fact){this.x*=fact
|
|
this.y*=fact}}
|
|
function dist(dx,dy){return Math.sqrt(dx*dx+dy*dy)}
|
|
function loop(currNo,minNo,maxNo,incr){currNo+=incr
|
|
let range=maxNo-minNo+1
|
|
if(currNo<minNo){currNo=maxNo-((-currNo+maxNo)%range)}
|
|
if(currNo>maxNo){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<span)
|
|
inter=this.tickInterval(span/4,true)
|
|
for(let i=0;i<ticks.length;i++){let t=ticks[i][0]
|
|
if(Math.abs(Math.round(t/inter)-t/inter)<0.001){ticks[i][1]=0}}
|
|
return ticks}
|
|
Coords.prototype.tickInterval=function(span,majorQ){let pow10=Math.pow(10,Math.floor(Math.log(span)*Math.LOG10E))
|
|
let mantissa=span/pow10
|
|
if(mantissa>=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;i<ticks.length;i++){let tick=ticks[i]
|
|
let xVal=tick[0]
|
|
let tickLevel=tick[1]
|
|
if(tickLevel==0){g.strokeStyle='rgba(0,0,256,0.2)'}else{g.strokeStyle='rgba(0,0,256,0.1)'}
|
|
let xPix=this.coords.toXPix(xVal,false)
|
|
g.beginPath()
|
|
g.moveTo(xPix,this.coords.toYPix(this.coords.yStt,false))
|
|
g.lineTo(xPix,this.coords.toYPix(this.coords.yEnd,false))
|
|
g.stroke()
|
|
if(my.coordsQ&&tickLevel==0&&this.xValsQ){g.fillStyle='#0000ff'
|
|
g.font='12px Verdana'
|
|
g.textAlign='center'
|
|
g.fillText(fmt(xVal),xPix,this.hzNumsY)}}
|
|
if(this.skewQ)return
|
|
if(my.coordsQ){g.lineWidth=1.5
|
|
g.strokeStyle='#ff0000'
|
|
g.beginPath()
|
|
g.moveTo(this.vtAxisX,this.coords.toYPix(this.coords.yStt,false))
|
|
g.lineTo(this.vtAxisX,this.coords.toYPix(this.coords.yEnd,false))
|
|
g.stroke()
|
|
g.beginPath()
|
|
g.fillStyle=g.strokeStyle
|
|
g.drawArrow(this.vtAxisX,this.coords.toYPix(this.coords.yEnd),15,2,20,10,Math.PI/2,10,false)
|
|
g.stroke()
|
|
g.fill()}}
|
|
Graph.prototype.drawHzLines=function(){let g=this.g
|
|
g.lineWidth=1
|
|
let ticks=this.coords.getTicks(this.coords.yStt,this.coords.yEnd-this.coords.yStt)
|
|
for(let i=0;i<ticks.length;i++){let tick=ticks[i]
|
|
let yVal=tick[0]
|
|
let tickLevel=tick[1]
|
|
if(tickLevel==0){g.strokeStyle='rgba(0,0,256,0.2)'}else{g.strokeStyle='rgba(0,0,256,0.1)'}
|
|
let yPix=this.coords.toYPix(yVal,false)
|
|
g.beginPath()
|
|
g.moveTo(this.coords.toXPix(this.coords.xStt,false),yPix)
|
|
g.lineTo(this.coords.toXPix(this.coords.xEnd,false),yPix)
|
|
g.stroke()
|
|
if(my.coordsQ&&tickLevel==0&&this.yValsQ){g.fillStyle='#ff0000'
|
|
g.font='12px Verdana'
|
|
g.textAlign='right'
|
|
g.fillText(fmt(yVal),this.vtNumsX,yPix+5)}}
|
|
if(this.skewQ)return
|
|
if(my.coordsQ){g.lineWidth=2
|
|
g.strokeStyle='#0000ff'
|
|
g.beginPath()
|
|
g.moveTo(this.coords.toXPix(this.coords.xStt,false),this.hzAxisY)
|
|
g.lineTo(this.coords.toXPix(this.coords.xEnd,false),this.hzAxisY)
|
|
g.stroke()
|
|
g.beginPath()
|
|
g.fillStyle=g.strokeStyle
|
|
g.drawArrow(this.coords.toXPix(this.coords.xEnd,false),this.hzAxisY,15,2,20,10,0,10,false)
|
|
g.stroke()
|
|
g.fill()}}
|
|
class Ln{constructor(pt1,pt2){this.a=new Pt(pt1.x,pt1.y)
|
|
this.b=new Pt(pt2.x,pt2.y)}
|
|
get lt(){return Math.min(this.a.x,this.b.x)}
|
|
get tp(){return Math.min(this.a.y,this.b.y)}
|
|
get rt(){return Math.max(this.a.x,this.b.x)}
|
|
get bt(){return Math.max(this.a.y,this.b.y)}
|
|
get wd(){return Math.abs(this.a.x-this.b.x)}
|
|
get ht(){return Math.abs(this.a.y-this.b.y)}
|
|
get dx(){return this.b.x-this.a.x}
|
|
get dy(){return this.b.y-this.a.y}
|
|
get len(){let dx=this.b.x-this.a.x
|
|
let dy=this.b.y-this.a.y
|
|
return Math.sqrt(dx*dx+dy*dy)}
|
|
setLen(newLen,fromMidQ=true){let len=this.len
|
|
if(fromMidQ){let midPt=this.getMidPt()
|
|
let halfPt=new Pt(this.a.x-midPt.x,this.a.y-midPt.y)
|
|
halfPt.multiplyMe(newLen/len)
|
|
this.a=midPt.translate(halfPt)
|
|
this.b=midPt.translate(halfPt,false)}else{let diffPt=new Pt(this.a.x-this.b.x,this.a.y-this.b.y)
|
|
diffPt.multiplyMe(newLen/len)
|
|
this.b=this.a.translate(diffPt,false)}}
|
|
draw(g){g.beginPath()
|
|
g.moveTo(this.a.x,this.a.y)
|
|
g.lineTo(this.b.x,this.b.y)
|
|
g.stroke()}
|
|
reflect(wall){let dbgQ=false
|
|
let g=my.can.g
|
|
let iPt=this.getIntersection(wall)
|
|
if(dbgQ)iPt.drawMe(g)
|
|
let nearPt=wall.getClosestPoint(this.a)
|
|
if(dbgQ)nearPt.drawMe(g)
|
|
if(dbgQ){let farPt=new Pt(iPt.x+(iPt.x-nearPt.x),iPt.y+(iPt.y-nearPt.y))
|
|
farPt.drawMe(g)}
|
|
let reflPt=new Pt(iPt.x+(iPt.x-nearPt.x)+(this.a.x-nearPt.x),iPt.y+(iPt.y-nearPt.y)+(this.a.y-nearPt.y))
|
|
if(dbgQ)reflPt.drawMe(g)
|
|
return new Ln(iPt,reflPt)}
|
|
normal(){let A=this.a
|
|
let B=this.b
|
|
console.log('normal',A,B)
|
|
let d=1
|
|
let C=new Ln(B,new Pt(B.x+(d*(A.y-B.y))/Math.sqrt(Math.pow(A.x-B.x,2)+Math.pow(A.y-B.y,2)),B.y-(d*(A.x-B.x))/Math.sqrt(Math.pow(A.x-B.x,2)+Math.pow(A.y-B.y,2))))
|
|
return C}
|
|
dot(v2){let v1=this
|
|
let a=0
|
|
a+=v1.x*v2.x
|
|
a+=v1.y*v2.y}
|
|
getMidPt(){return new Pt((this.a.x+this.b.x)/2,(this.a.y+this.b.y)/2)}
|
|
rotateMidMe(angle){let midPt=this.getMidPt()
|
|
this.a.translateMe(midPt,false)
|
|
this.b.translateMe(midPt,false)
|
|
this.a.rotateMe(angle)
|
|
this.b.rotateMe(angle)
|
|
this.a.translateMe(midPt)
|
|
this.b.translateMe(midPt)}
|
|
getClosestPoint(toPt,inSegmentQ){let AP=toPt.translate(this.a,false)
|
|
let AB=this.b.translate(this.a,false)
|
|
let ab2=AB.x*AB.x+AB.y*AB.y
|
|
let ap_ab=AP.x*AB.x+AP.y*AB.y
|
|
let t=ap_ab/ab2
|
|
if(inSegmentQ){t=constrain(0,t,1)}
|
|
return this.a.translate(AB.multiply(t))}
|
|
perp(){let dx=this.a.x-this.b.x
|
|
let dy=this.a.y-this.b.y
|
|
return new Pt(dy,-dx)}
|
|
rectIntersectQ(ln){let r1=this
|
|
let r2=ln
|
|
if(r2.lt>r1.lt+r1.wd)return false
|
|
if(r2.lt+r2.wd<r1.lt)return false
|
|
if(r2.tp>r1.tp+r1.ht)return false
|
|
if(r2.tp+r2.ht<r1.tp)return false
|
|
return true}
|
|
getIntersection(ln,asSegmentsQ=false){let aPt=this.a
|
|
let bPt=this.b
|
|
let ePt=ln.a
|
|
let fPt=ln.b
|
|
let a1=bPt.y-aPt.y
|
|
let b1=aPt.x-bPt.x
|
|
let c1=bPt.x*aPt.y-aPt.x*bPt.y
|
|
let a2=fPt.y-ePt.y
|
|
let b2=ePt.x-fPt.x
|
|
let c2=fPt.x*ePt.y-ePt.x*fPt.y
|
|
let denom=a1*b2-a2*b1
|
|
if(denom==0){return null}
|
|
let ip=new Pt()
|
|
ip.x=(b1*c2-b2*c1)/denom
|
|
ip.y=(a2*c1-a1*c2)/denom
|
|
if(asSegmentsQ){if(Math.pow(ip.x-bPt.x,2)+Math.pow(ip.y-bPt.y,2)>Math.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(checkVal<centralVal-limitVal)return false
|
|
if(checkVal>centralVal+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;i<pts.length;i++){let cosa=Math.cos(-angle)
|
|
let sina=Math.sin(-angle)
|
|
let xPos=pts[i][0]*cosa+pts[i][1]*sina
|
|
let yPos=pts[i][0]*sina-pts[i][1]*cosa
|
|
if(i==0){g.moveTo(x0+xPos,y0+yPos)}else{g.lineTo(x0+xPos,y0+yPos)}}}
|
|
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<pts.length;i++){if(i==0){g.moveTo(midX+radius*pts[i][0],midY+radius*pts[i][1])}else{g.lineTo(midX+radius*pts[i][0],midY+radius*pts[i][1])}}
|
|
g.stroke()}
|
|
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}
|
|
my.theme=localStorage.getItem('theme')
|
|
my.lineClr=my.theme=='dark'?'white':'black'
|
|
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'}}
|
|
class Pop{constructor(id,btns=[{txt:'✔',fn:null},{txt:'✘',fn:null}]){this.id=id
|
|
this.btns=btns
|
|
this.div=document.getElementById(this.id)
|
|
this.div.classList.add('pop')
|
|
this.div.style='position:absolute; left:-450px; top:10px; width:auto; transition: all linear 0.3s; opacity:0; text-align: center; '
|
|
this.bodyDiv=document.createElement('div')
|
|
this.div.appendChild(this.bodyDiv)
|
|
for(let i=0;i<btns.length;i++){let btn=btns[i]
|
|
let btnDiv=document.createElement('button')
|
|
this.div.appendChild(btnDiv)
|
|
btnDiv.classList.add('btn')
|
|
btnDiv.innerHTML=btn.txt
|
|
btnDiv.onclick=this.btnClick.bind(this,i)}
|
|
return this}
|
|
open(){let div=this.div
|
|
div.style.transitionDuration='0.3s'
|
|
div.style.opacity=1
|
|
div.style.zIndex=12
|
|
div.style.left=(window.innerWidth-300)/2+'px'}
|
|
close(){this.div.style.opacity=0
|
|
this.div.style.zIndex=1
|
|
this.div.style.left='-999px'
|
|
my.pauseQ=false}
|
|
btnClick(n){let btn=this.btns[n]
|
|
console.log('btnClick',n,this.btns,btn)
|
|
this.close()
|
|
if(typeof btn.fn==='function')btn.fn()}
|
|
htmlSet(s){this.bodyDiv.innerHTML=s
|
|
return s}}
|
|
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.ratio=ratio
|
|
this.el=typeof id=='string'?document.getElementById(id):id
|
|
this.g=this.el.getContext('2d')
|
|
this.resize(wd,ht)
|
|
return this}
|
|
resize(wd,ht){this.wd=wd
|
|
this.ht=ht
|
|
this.el.width=wd*this.ratio
|
|
this.el.style.width=wd+'px'
|
|
this.el.height=ht*this.ratio
|
|
this.el.style.height=ht+'px'
|
|
this.g.setTransform(this.ratio,0,0,this.ratio,0,0)}
|
|
clear(){this.g.clearRect(0,0,this.wd,this.ht)}
|
|
mousePos(ev){let bRect=this.el.getBoundingClientRect()
|
|
let x=(ev.clientX-bRect.left)*(this.el.width/this.ratio/bRect.width)
|
|
let y=(ev.clientY-bRect.top)*(this.el.height/this.ratio/bRect.height)
|
|
return{x:x,y:y}}}
|
|
function wrap({id='',cls='',pos='rel',style='',txt='',tag='div',lbl='',fn='',opts=[]},...mores){let s=''
|
|
s+='\n'
|
|
txt+=mores.join('')
|
|
let tags={btn:{stt:'<button '+(fn.length>0?' onclick="'+fn+'" ':''),cls:'btn',fin:'>'+txt+'</button>'},can:{stt:'<canvas ',cls:'',fin:'></canvas>'},div:{stt:'<div '+(fn.length>0?' onclick="'+fn+'" ':''),cls:'',fin:' >'+txt+'</div>'},edit:{stt:'<textarea onkeyup="'+fn+'" onchange="'+fn+'"',cls:'',fin:' >'+txt+'</textarea>'},inp:{stt:'<input value="'+txt+'"'+(fn.length>0?' oninput="'+fn+'" onchange="'+fn+'"':''),cls:'input',fin:'>'+(lbl.length>0?'</label>':'')},out:{stt:'<span ',cls:'output',fin:' >'+txt+'</span>'+(lbl.length>0?'</label>':'')},radio:{stt:'<div ',cls:'radio',fin:'>\n'},sel:{stt:'<select '+(fn.length>0?' onchange="'+fn+'"':''),cls:'select',fin:'>\n'},sld:{stt:'<input type="range" '+txt+' oninput="'+fn+'" onchange="'+fn+'"',fin:(lbl.length>0?'</label>':'<span id="'+id+'0">0</span>')},}
|
|
let type=tags[tag]
|
|
if(lbl.length>0)s+='<label class="label">'+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<opts.length;i++){let chk=''
|
|
if(i==0)chk='checked'
|
|
let idi=id+i
|
|
let lbl=opts[i]
|
|
s+='<input id="'+idi+'" type="radio" name="'+id+'" value="'+lbl.name+'" onclick="'+fn+'('+i+');" '+chk+' >'
|
|
s+='<label for="'+idi+'">'+lbl.name+' </label>'}
|
|
s+='</div>'}
|
|
if(tag=='sel'){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>'}
|
|
s+='\n'
|
|
return s.trim()}
|
|
init() |