'
return s}
function chgPat(n){console.log('chgPat='+n)
my.pat=n
setPat(my.pat)
drawCircs()}
function setPat(n){console.log('setPat',my.pats[n],my.pats[n].style)
document.getElementById('r1').value=my.pats[n].thk
document.getElementById('thk').innerHTML=document.getElementById('r1').value
document.getElementById('r2').value=my.pats[n].spc
document.getElementById('spc').innerHTML=document.getElementById('r2').value
document.getElementById('r3').value=my.pats[n].alpha
document.getElementById('alp').innerHTML=document.getElementById('r3').value
let styleNo=my.styles.indexOf(my.pats[n].style)
document.getElementById('style'+styleNo).checked=true
let clrNo=my.clrs.map(function(e){return e[1]}).indexOf(my.pats[n].clr)
console.log('clrNo',clrNo)
radioPress(my.clrs,'clr',clrNo)}
function chgStyle(n){console.log('chgStyle='+n)
my.pats[my.pat].style=my.styles[n]}
function onSizeChg(n,v){console.log('onSizeChg='+n,v,my.pat,my.pats)
v=Number(v)
if(v<0.1)v=0.1
my.pats[my.pat].thk=v
drawCircs()
document.getElementById('thk').innerHTML=v}
function onSpcChg(n,v){console.log('onSpcChg='+n,v,my.pat)
v=Number(v)
if(v<0.1)v=0.1
my.pats[my.pat].spc=v
drawCircs()
document.getElementById('spc').innerHTML=v}
function onAlpChg(n,v){console.log('onAlpChg='+n,v,my.pat)
v=Number(v)
my.pats[my.pat].alp=v
drawCircs()
document.getElementById('alp').innerHTML=v}
function onSpeedChg(n,v){console.log('onSpeedChg='+n,v,my.pat)
v=Number(v)
my.speed=v
drawCircs()
document.getElementById('speed').innerHTML=v}
function anim(){if(my.playQ){drawCircs()
requestAnimationFrame(anim)}}
function drawCircs(){my.can.clear()
my.can2.clear()
let m0=my.pats[0]
let m1=my.pats[1]
m0.ang+=my.speed*0.0005
m1.ang-=my.speed*0.0005
drawWheel(my.can.g,m0)
drawWheel(my.can2.g,m1)}
function drawWheel(g,moire){let style=moire.style
let thick=moire.thk
let space=moire.spc
let rot=moire.ang
g.strokeStyle=moire.clr
g.lineWidth=thick
let both=thick+space
if(both<0.2)return
let lineCount=my.sz/both
switch(style){case 'circles':drawCircles(g,moire.x,moire.y,both,lineCount/2)
break
case 'lines':drawParaLines(g,moire.x,moire.y,my.sz,rot,both,lineCount)
break
case 'grid':drawParaLines(g,moire.x,moire.y,my.sz,rot,both,lineCount)
drawParaLines(g,moire.x,moire.y,my.sz,-Math.PI/2+rot,both,lineCount)
break
case 'radials':drawRadials(g,moire.x,moire.y,rot,both)
break
default:}}
function drawCircles(g,x,y,space,lineCount){for(let i=0;i'
for(let i=0;i'+clr[0]+''}
s+='
'
return s}
function getDropdownHTML(opts,funcName,id){let s=''
s+=''
return s}
function getPlayHTML(w){let s=''
s+=''
s+=''
return s}
function togglePlay(){let btn='playBtn'
if(my.playQ){my.playQ=false
document.getElementById(btn).classList.add('play')
document.getElementById(btn).classList.remove('pause')}else{my.playQ=true
document.getElementById(btn).classList.add('pause')
document.getElementById(btn).classList.remove('play')
anim()}
if(my.colNo")
win.document.location='#'}
function canvasPrint(){let can=canvasAdd(document.getElementById('gfx1'),document.getElementById('gfx2'))
let dataUrl=can.toDataURL('image/png')
let win=window.open()
win.document.write("")
win.document.location='#'
win.setTimeout(function(){win.focus()
win.print()},500)}
function Clr(rr,gg,bb){this.clrs=[rr<<0,gg<<0,bb<<0]
this.dirs=[1,1,1]}
Clr.prototype.rand=function(){for(let i=0;i<3;i++){this.clrs[i]=(Math.random()*256)<<0}}
Clr.prototype.getHex=function(){let s='#'+hex2(this.clrs[0])+hex2(this.clrs[1])+hex2(this.clrs[2])
return s}
Clr.prototype.setHex=function(clr){let result=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(clr)
this.clrs=result?[parseInt(result[1],16),parseInt(result[2],16),parseInt(result[3],16)]:null}
Clr.prototype.randChg=function(){for(let i=0;i<3;i++){if(Math.random()<0.01)this.dirs[i]*=-1
if(this.clrs[i]>=255)this.dirs[i]=-1
if(this.clrs[i]<=0)this.dirs[i]=1
this.clrs[i]+=this.dirs[i]}}
function hex2(n){let s=n.toString(16)
if(s.length==1)s='0'+s
return s}
function Pt(ix,iy){this.x=ix
this.y=iy
this.rad=9
this.color='lightblue'}
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.ratio=ratio
this.el=document.getElementById(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 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 '