let my={} function init(){let version='0.83' my.wd=700 console.log('my.wd',my.wd) let s='' s+='
' s+='
' s+='' s+='
' s+='
' s+='
' s+='' s+='
' s+=wrap({id:'amBtn',tag:'btn',fn:'toggleAm()'},'AM/PM') s+=wrap({id:'secBtn',tag:'btn',fn:'toggleSec()'},'Sec') s+='
' s+='
' s+=wrap({cls:'copyrt'},`© 2022 Rod Pierce v${version}`) s+='
' docInsert(s) let ana=new Clock(my.wd*0.5,'clock1') ana.loop() this.digi=new DigiClock(my.wd*0.5,'24','clock2') this.digi.loop() let day=new Day('dayText') day.loop() my.amQ=true toggleAm() my.secQ=true toggleSec()} function toggleAm(){my.amQ=!my.amQ btn('amBtn',my.amQ) this.digi.mode=my.amQ?'am':'24'} function toggleSec(){my.secQ=!my.secQ btn('secBtn',my.secQ) this.digi.secQ=my.secQ} function btn(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')}} let Day=function(divName){this.div=document.getElementById(divName) this.months=['January','February','March','April','May','June','July','August','September','October','November','December'] this.days=['Sun','Mon','Tue','Wed','Thu','Fri','Sat'] this.dayFulls=['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'] this.strLast='' this.tmLast=performance.now() this.update()} Day.prototype.loop=function(){let tm=performance.now() if(tm>this.tmLast+1000){this.tmLast=performance.now() this.update()} requestAnimationFrame(this.loop.bind(this))} Day.prototype.update=function(){this.dt=new Date() let s='' s+='' s+=this.dayFulls[this.dt.getDay()]+'
' s+=''+this.dt.getDate()+''+'
' s+=this.months[this.dt.getMonth()]+'
' s+=this.dt.getFullYear() s+='
' if(s!=this.strLast){console.log('s',s) this.div.innerHTML=s this.strLast=s}} class Clock{constructor(diam,canName){this.radius=diam*0.41 this.ratio=2 this.can=new Can(canName,diam,diam,this.ratio) this.g=this.can.g this.center={x:(this.can.el.width*0.5)/this.ratio,y:(this.can.el.height*0.5)/this.ratio,} this.secondOpt={color:'#060',thickRatio:0.011,forwardRadiusRatio:0.75,backwardRadiusRatio:0.2,tipRadiusRatio:0.075,} this.minuteOpt={color:'#f00',thickRatio:0.03,forwardRadiusRatio:0.75,backwardRadiusRatio:0.2,} this.hourOpt={color:'#00f',thickRatio:0.04,forwardRadiusRatio:0.6,backwardRadiusRatio:0.2,} this.faceOpt={color:'#000',numDistRatio:0.28,numSizeRatio:0.28,edgeDistRatio:0.12,thickRatio:0.005,lengthRatio:0.04,keyMarkers:5,keyMarkerThicknessRatio:0.175,keyMarkerLengthRatio:0.01,} this.redrawEvery=0 this.update()} loop(){this.redrawEvery++ if(this.redrawEvery>2){this.redrawEvery=0 this.update()} requestAnimationFrame(this.loop.bind(this))} update(){this.can.clear() this.dt=new Date() this.drawFace() this.drawMarkers() this.drawHourHand() this.drawMinuteHand() this.drawSecondHand() this.drawPin()} drawFace(){let g=this.g let faceGradient=g.createRadialGradient(this.center.x,this.center.y,0,this.center.x,this.center.y,this.radius) faceGradient.addColorStop(0,'rgba(255, 231, 180, 0)') faceGradient.addColorStop(1,'rgba(182, 157, 100, 0.3)') g.fillStyle=faceGradient g.beginPath() g.arc(this.center.x,this.center.y,this.radius,0,2*Math.PI) g.fillStyle='#fff' g.fill() g.fillStyle=faceGradient g.fill() let edgeGradient=this.g.createLinearGradient(0,this.center.y-this.radius,0,this.center.y+this.radius) edgeGradient.addColorStop(0,'#999') edgeGradient.addColorStop(0.5,'#fff') edgeGradient.addColorStop(1,'#999') g.fillStyle=edgeGradient g.beginPath() g.arc(this.center.x,this.center.y,this.radius,0,2*Math.PI) g.closePath() g.arc(this.center.x,this.center.y,this.radius+this.radius*0.075,0,2*Math.PI,true) g.shadowColor='rgba(0,0,0,0.7)' g.shadowBlur=this.radius*0.3 g.shadowOffsetY=1 g.fill() g.shadowBlur=0 g.shadowOffsetY=0} drawPin(){this.g.fillStyle='#999' this.g.beginPath() this.g.arc(this.center.x,this.center.y,this.radius*0.04,0,2*Math.PI) this.g.fill()} drawMarkers(){let g=this.g g.font='bold '+this.radius*this.faceOpt.numSizeRatio+'px Arial' g.textAlign='center' let dotA=-0.4 let dotB=1-dotA let i=1 while(i<=60){let angle=Math.PI*2*(-i/60) let startX=Math.sin(angle)*(this.radius-this.radius*this.faceOpt.edgeDistRatio)+this.center.x let startY=Math.cos(angle)*(this.radius-this.radius*this.faceOpt.edgeDistRatio)+this.center.y let endX=Math.sin(angle)*(this.radius-this.radius*this.faceOpt.lengthRatio-this.radius*this.faceOpt.edgeDistRatio)+this.center.x let endY=Math.cos(angle)*(this.radius-this.radius*this.faceOpt.lengthRatio-this.radius*this.faceOpt.edgeDistRatio)+this.center.y if(i%this.faceOpt.keyMarkers){g.lineWidth=this.faceOpt.thickRatio*this.radius*2}else{g.lineWidth=this.faceOpt.thickRatio*this.radius*5} let markType='line' switch(markType){case 'line':g.beginPath() g.moveTo(startX,startY) g.lineTo(endX,endY) g.stroke() break case 'dot':g.fillStyle='#cdf' g.beginPath() let dotRad=0 if(i%this.faceOpt.keyMarkers){dotRad=this.radius*0.015}else{dotRad=this.radius*0.03} g.arc(startX*dotA+endX*dotB,startY*dotA+endY*dotB,dotRad,0,2*Math.PI) g.stroke() g.fill() break default:} i++} i=1 while(i<=60){let angle=Math.PI*2*(-i/60) if(i%this.faceOpt.keyMarkers){}else{g.fillStyle='#000' g.strokeStyle='#fff' g.miterLimit=2 g.lineWidth=1 let numRad=this.radius*(1-this.faceOpt.numDistRatio) let numX=Math.sin(angle)*numRad+this.center.x let numY=Math.cos(angle)*numRad+this.center.y+this.radius*0.09 let h=Math.floor(i/5)+6 if(h>12)h-=12 if(h==10){numX+=this.radius*0.04 numY+=this.radius*0.03} if(h==11){numX+=this.radius*0.02 numY+=this.radius*0.03} g.fillText(h.toString(),numX,numY) g.strokeText(h.toString(),numX,numY)} i++}} drawSecondHand(){let secs=this.dt.getSeconds() secs+=this.dt.getMilliseconds()/1000 let handAngle=Math.PI*2*(-secs/60) this.drawHand(handAngle,this.secondOpt)} drawMinuteHand(){let minutes=this.dt.getMinutes()+this.dt.getSeconds()/60 let handAngle=Math.PI*2*(-minutes/60) this.drawHand(handAngle,this.minuteOpt)} drawHourHand(){let h=this.dt.getHours()+this.dt.getMinutes()/60 if(h>=12)h-=12 let handAngle=Math.PI*2*(-h/12) this.drawHand(handAngle,this.hourOpt)} drawHand(angle,handOptions){let startX=Math.sin(angle)*(this.radius*handOptions.backwardRadiusRatio)+this.center.x let startY=Math.cos(angle)*(this.radius*handOptions.backwardRadiusRatio)+this.center.y let endX=Math.sin(angle-Math.PI)*(this.radius*handOptions.forwardRadiusRatio)+this.center.x let endY=Math.cos(angle-Math.PI)*(this.radius*handOptions.forwardRadiusRatio)+this.center.y let g=this.g g.shadowColor='rgba(0,0,0,0.8)' g.shadowBlur=this.radius*0.075 g.shadowOffsetY=1 g.strokeStyle=handOptions.color g.lineWidth=handOptions.thickRatio*this.radius g.beginPath() g.moveTo(startX,startY) g.lineTo(endX,endY) g.stroke() g.fillStyle=handOptions.color g.beginPath() g.arc(endX,endY,g.lineWidth/2,0,2*Math.PI) g.fill() g.shadowBlur=0 g.shadowOffsetY=0 if(handOptions.tipRadiusRatio){g.beginPath() g.moveTo(startX,startY) g.lineTo(endX,endY) g.stroke()}}} function DigiClock(wd,mode,canName){this.wd=wd this.mode=mode if(this.mode=='am'){this.ht=this.wd/2}else{this.ht=this.wd/3} if(this.mode=='am'){this.numHt=this.wd*0.3}else{this.numHt=this.wd*0.19} this.numWd=this.numHt*0.45 this.numGap=this.numHt*0.2 this.midX=this.wd/2 this.midY=this.ht/2 this.typ='led' switch(this.typ){case 'lcd':this.clr={bg:'rgb(80, 133, 255)',border:'2px solid #888',on:'rgb(25, 38, 107)',off:'rgb(80, 133, 255)',shadow:'rgb(100, 255, 0)',shadowBlur:0} break case 'led':this.clr={bg:'#222',border:'2px solid black',on:'rgb(100, 255, 0)',off:'rgb(50, 50, 0)',shadow:'rgb(100, 255, 0)',shadowBlur:33} break default:} this.el=document.getElementById(canName) this.el.style.backgroundColor=this.clr.bg this.el.style.borderRadius='10px' this.el.style.border=this.clr.border let ratio=2 this.el.width=this.wd*ratio this.el.height=this.ht*ratio this.el.style.width=this.wd+'px' this.el.style.height=this.ht+'px' this.g=this.el.getContext('2d') this.g.setTransform(ratio,0,0,ratio,0,0) this.numbers={n0:[1,1,1,0,1,1,1],n1:[0,0,1,0,0,1,0],n2:[1,0,1,1,1,0,1],n3:[1,0,1,1,0,1,1],n4:[0,1,1,1,0,1,0],n5:[1,1,0,1,0,1,1],n6:[0,1,0,1,1,1,1],n7:[1,0,1,0,0,1,0],n8:[1,1,1,1,1,1,1],n9:[1,1,1,1,0,1,1],A:[1,1,1,1,1,1,0],P:[1,1,1,1,1,0,0],} this.tmLast=performance.now() this.update} DigiClock.prototype.loop=function(){let tm=performance.now() if(tm>this.tmLast+100){this.tmLast=performance.now() this.update()} requestAnimationFrame(this.loop.bind(this))} DigiClock.prototype.update=function(){this.g.clearRect(0,0,this.wd,this.ht) let time=new Date() let hours=time.getHours().toString() if(this.mode=='am'){if(hours>12)hours-=12 if(hours==0){hours='12'}else if(hours<10){hours='0'+hours}else{hours=''+hours}}else{if(hours<10){hours='0'+hours}} let minutes=time.getMinutes().toString() if(minutes.length==1){minutes='0'+minutes} let seconds=time.getSeconds().toString() if(seconds.length==1){seconds='0'+seconds} let timeStr if(this.mode=='am'){timeStr=hours+minutes}else{if(my.secQ){timeStr=hours+minutes+seconds}else{timeStr=hours+minutes}} for(let i=0;i0?' onclick="'+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:'0?'':'0')},} let type=tags[tag] if(lbl.length>0)s+='
'} s+=''} if(tag=='sel'){for(let i=0;i'+opt.descr+'\n'} s+='' if(lbl.length>0)s+=''} s+='\n' return s.trim()} init()