let el,g,ratio,shapes,my={}
function dopplerMain(mode,rel){let version='0.61';this.mode=typeof mode!=='undefined'?mode:'asc';rel=typeof rel!=='undefined'?rel:'../';my.w=500;my.h=300;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.listenHt=50
my.frame=0
my.avgFreq=0
my.hist=[]
my.listenPos={x:250,y:170}
my.everyN=12
my.speed=0.8
my.dirn=1
my.playQ=true
my.drag={type:'block',q:false,n:0,hold:{x:0,y:0}}
my.moves=[]
let s="";s+='
';s+='
';my.playQ=false
s+=playHTML(40);s+=' '
s+='';s+=' '
my.soundQ=true
s+=soundBtnHTML()
s+='
';s+='
YO!
'
s+='
';s+=`
3
`
s+='
© 2021 MathsIsFun.com v'+version+'
';s+='
';document.write(s);el=document.getElementById('canvasId');my.ratio=1
el.width=my.w*my.ratio;el.height=my.h*my.ratio;el.style.width=my.w+"px";el.style.height=my.h+"px";g=el.getContext("2d");g.setTransform(my.ratio,0,0,my.ratio,0,0);shapes=[];my.disks=[]
my.spec=new Spectrum(0)
gameNew();el.addEventListener("mousedown",mouseDown,false);el.addEventListener('touchstart',touchStart,false);el.addEventListener("mousemove",doPointer,false);}
function gameNew(){g.clearRect(0,0,g.canvas.width,g.canvas.height)
var div=document.getElementById('disks')
while(div.firstChild){div.removeChild(div.firstChild);}
var disk=new Disk(50,100,1)
div.appendChild(disk.div)
my.disks.push(disk);my.waveLast=performance.now()
listenSet(my.listenPos.x,my.listenPos.y,'')
anim()}
function anim(){my.frame++
loop();if(my.playQ)requestAnimationFrame(anim);}
function loop(){let disk=my.disks[0]
disk.x+=my.speed*my.dirn
if(disk.x>my.w-30)my.dirn=-1
if(disk.x<30)my.dirn=1
disk.moveMe()
g.clearRect(0,0,g.canvas.width,g.canvas.height)
if(parseInt(my.frame/my.everyN)==my.frame/my.everyN){my.frame=0
my.hist.push({x:disk.x+my.diskHt/2,y:disk.y+my.diskHt/2,dist:0})
my.hist=my.hist.filter(function(elem){return elem.dist<450})}
for(let i=0;i40){hit=1
my.waveLast=now
let freq=parseInt(my.avgFreq*6000)
listenSet(my.listenPos.x,my.listenPos.y,freq)
my.spec.fChg(freq)}}
let avgN=15
my.avgFreq=(my.avgFreq*(avgN-1)+hit)/avgN}
function listenSet(x,y,str){let freqDiv=document.getElementById('freq')
freqDiv.style.left=(x-my.listenHt/2)+'px'
freqDiv.style.top=(y-my.listenHt/2)+'px'
freqDiv.innerHTML=str}
function touchStart(evt){let touch=evt.targetTouches[0];evt.clientX=touch.clientX;evt.clientY=touch.clientY;evt.touchQ=true;mouseDown(evt)}
function touchMove(evt){let 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;my.drag.n=-1;window.removeEventListener("touchmove",touchMove,false);}}
function doPointer(e){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);let inQ=false;for(let i=0;i(shape.x+shape.wd))return false;if(my>(shape.y+shape.ht))return false;return true;}
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);let 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){let 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(){let 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);let 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");let 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=my.diskHt
this.ht=my.diskHt
this.pad=4
this.pole=0
this.hiliteQ=false;let 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);let canWd=(this.wd+this.pad*2);let 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);let 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()}}
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;};function Spectrum(id){this.id=id
this.audioContext=null
this.ht=120
this.audioQ=false
this.freq=40}
Spectrum.prototype.init=function(){console.log('init',this.id)
this.el=document.getElementById('canvas'+this.id);ratio=2;this.el.width=w*ratio;this.el.height=this.ht*ratio;this.el.style.width=w+"px";this.el.style.height=this.ht+"px";this.g=this.el.getContext("2d");this.g.setTransform(ratio,0,0,ratio,0,0);document.getElementById('freqr'+this.id).value=0.09;document.getElementById('freqi'+this.id).value=this.freq;}
Spectrum.prototype.on=function(){if(this.audioContext==null){this.audioContext=new window.AudioContext();this.oscillator=this.audioContext.createOscillator();this.oscillator.frequency.value=this.freq
this.oscillator.start(0);}
this.oscillator.connect(this.audioContext.destination);}
Spectrum.prototype.off=function(){if(this.oscillator)
this.oscillator.disconnect(this.audioContext.destination);}
Spectrum.prototype.setFreq=function(f){this.freq=f
if(this.audioContext!=null){this.oscillator.frequency.value=f;}}
Spectrum.prototype.toggleAudio=function(){this.audioQ=!this.audioQ;if(this.audioQ){document.getElementById('audioBtn'+this.id).innerHTML=' Mute ';this.on()}else{document.getElementById('audioBtn'+this.id).innerHTML='Listen';this.off()}}
Spectrum.prototype.html=function(){s=''
s+='';s+='
';s+='
';s+='
';s+='
';s+='Frequency: ';s+='';s+='';s+='';s+=' Hertz';s+='
';s+='
';return s}
Spectrum.prototype.fChg=function(freq){freq=Number(freq);if(freq<20)freq=20;if(freq>20000)freq=20000;if(!isNaN(freq))this.setFreq(freq)}
Spectrum.prototype.draw=function(){var sttY=20;var sttX=70;var endX=520;var gap=1.01*(endX-sttX)/10;var g=this.g
g.lineWidth=2;g.strokeStyle='black';g.textAlign='center';g.fillStyle='lightblue';var rects=[5,10,20,40,80,160,320,640,1280,2500,5000,10000,20000,40000,80000];var f=5;for(var i=-2;i<=11;i++){f=rects[i+2];var xp=sttX+i*gap;g.fillStyle='cornsilk';if(i<0)
g.fillStyle='lightblue';if(i>=10)
g.fillStyle='pink';g.beginPath();g.rect(xp,sttY,gap,40);g.stroke();g.fill();if(i>=0&&i<=10){g.fillStyle='blue';g.fillText(f.toString(),xp,sttY+50);}}
g.fillStyle='black';g.font='14px Arial';g.textAlign='right';g.fillText('Infrasound',sttX-2,15);g.textAlign='center';g.fillText('Sound',(sttX+endX)/2,15);g.textAlign='left';g.fillText('Ultrasound',endX+8,15);}
function onSpeedChg(n,v){console.log("onSpeedChg="+n,v);my.speed=v*1.4}
function playHTML(w){var s='';s+='';s+='';return s;}
function playToggle(){var btn='playBtn';if(my.playQ){my.playQ=false;my.spec.off()
document.getElementById(btn).classList.add("play");document.getElementById(btn).classList.remove("pause");}else{my.playQ=true;if(my.soundQ)my.spec.on()
document.getElementById(btn).classList.add("pause");document.getElementById(btn).classList.remove("play");anim();}}
function soundBtnHTML(){let s=''
s+=''
s+='
'
return s}
function soundToggle(){var btn='sound'
if(my.soundQ){my.soundQ=false
my.spec.off()
document.getElementById(btn).classList.add("mute")}else{my.soundQ=true
my.spec.on()
document.getElementById(btn).classList.remove("mute")}}