diff options
Diffstat (limited to 'docs/prototypes/panel-widget-gallery.html')
| -rw-r--r-- | docs/prototypes/panel-widget-gallery.html | 50 |
1 files changed, 50 insertions, 0 deletions
diff --git a/docs/prototypes/panel-widget-gallery.html b/docs/prototypes/panel-widget-gallery.html index ab69855..f8330bb 100644 --- a/docs/prototypes/panel-widget-gallery.html +++ b/docs/prototypes/panel-widget-gallery.html @@ -894,6 +894,9 @@ card(I,'R26','Response graph', card(I,'R30','Telegraph indicator', `<svg id="telind" class="rsvg press" viewBox="0 0 110 110" width="110" height="110"></svg>`, '<b>state on a pie of sectors.</b> The pointer and its little flag name the active state, engine-telegraph style. Click to step the state. After an electric indicator dial.'); +card(I,'R31','Radar sweep', + `<svg id="radar" class="rsvg press" viewBox="0 0 130 130" width="130" height="130"></svg>`, + '<b>the rotating scan.</b> A sweep beam circles the bearing ring, contacts bloom as it passes and fade after. Click to mark the current bearing. After a radar PPI scope.'); /* ============ CONTROL WIRING ============ */ /* 01 toggle */ @@ -2006,6 +2009,53 @@ function setTelind(i){telI=i;const N=TELIND_STATES.length; setRd('R30',TELIND_STATES[i]);} setTelind(0); +/* R31 radar sweep: rotating beam, blooming contacts, click to mark */ +let radarA=210,radarSweep=null,radarBlips=[],radarMark=null; +const RADAR_CONTACTS=[[60,.55],[205,.7],[318,.4]]; +(function(){const s=$('radar'),cx=65,cy=65; + const defs=svgEl(s,'defs',{}); + const clip=svgEl(defs,'clipPath',{id:'radarClip'}); + svgEl(clip,'circle',{cx,cy,r:46}); + svgEl(s,'circle',{cx,cy,r:62,fill:'#1a1714',stroke:'#060505','stroke-width':2}); + svgEl(s,'circle',{cx,cy,r:52,fill:'#120b05',stroke:'#3a2a12','stroke-width':1}); + for(let d=0;d<360;d+=30){const a=d; + const [x1,y1]=polar(cx,cy,51,a),[x2,y2]=polar(cx,cy,47,a); + svgEl(s,'line',{x1,y1,x2,y2,stroke:'var(--gold)','stroke-width':1,opacity:.8}); + const g=svgEl(s,'g',{transform:`rotate(${a},${cx},${cy})`}); + svgEl(g,'text',{x:cx,y:cy-47.5,'text-anchor':'middle','font-size':4.6,'font-family':'var(--mono)', + fill:'var(--gold)',opacity:.9}).textContent=String(d).padStart(3,'0');} + for(let d=0;d<360;d+=10){if(d%30===0)continue; + const [x1,y1]=polar(cx,cy,51,d),[x2,y2]=polar(cx,cy,49,d); + svgEl(s,'line',{x1,y1,x2,y2,stroke:'var(--gold)','stroke-width':.6,opacity:.5});} + const g=svgEl(s,'g',{'clip-path':'url(#radarClip)'}); + svgEl(g,'circle',{cx,cy,r:46,fill:'#0d0803'}); + for(const r of [15,30,45]) + svgEl(g,'circle',{cx,cy,r,fill:'none',stroke:'rgba(226,160,56,.18)','stroke-width':.7}); + radarSweep=svgEl(g,'g',{}); + for(let t=0;t<5;t++){const a0=-14+t*2.8,a1=a0+2.8; + const [x1,y1]=polar(cx,cy,46,a0),[x2,y2]=polar(cx,cy,46,a1); + svgEl(radarSweep,'path',{d:`M ${cx} ${cy} L ${x1} ${y1} A 46 46 0 0 1 ${x2} ${y2} Z`, + fill:`rgba(226,160,56,${(0.04+t*0.045).toFixed(3)})`});} + svgEl(radarSweep,'line',{x1:cx,y1:cy,x2:cx,y2:cy-46,stroke:'var(--gold-hi)','stroke-width':1.4, + transform:`rotate(0,${cx},${cy})`,opacity:.95}); + RADAR_CONTACTS.forEach(([bd,rf])=>{const [x,y]=polar(cx,cy,46*rf,bd); + radarBlips.push(svgEl(g,'circle',{cx:x,cy:y,r:2.2,fill:'var(--gold-hi)',opacity:0}));}); + svgEl(s,'circle',{cx,cy,r:3,fill:'var(--gold)',opacity:.8}); + radarMark=svgEl(s,'text',{x:cx,y:124,'text-anchor':'middle','font-size':6,'letter-spacing':'.12em', + 'font-family':'var(--mono)',fill:'var(--steel)'}); + radarMark.textContent='BEARING —'; + $('radar').onclick=()=>{radarMark.textContent='MARK '+String(Math.round(radarA)%360).padStart(3,'0'); + setRd('R31','mark '+String(Math.round(radarA)%360).padStart(3,'0'));};})(); +function tickRadar(){radarA=(radarA+2.6)%360; + radarSweep.setAttribute('transform',`rotate(${radarA},65,65)`); + RADAR_CONTACTS.forEach(([bd],i)=>{ + let d=(radarA-bd+360)%360; // degrees since beam passed + radarBlips[i].setAttribute('opacity',d<200?Math.max(0,.95-d/200):0);}); + radarMark.textContent=radarMark.textContent.startsWith('MARK')?radarMark.textContent: + 'BEARING '+String(Math.round(radarA)%360).padStart(3,'0');} +tickRadar();setRd('R31','sweeping'); +if(!matchMedia('(prefers-reduced-motion: reduce)').matches)setInterval(tickRadar,50); + /* R25 fourteen-segment display: the starburst that spells */ const SEG14_WORDS=['ZOOM','ECHO','TAPE','MOOD','HALL','COMP']; const SEG14_MAP={A:['a','b','c','e','f','g1','g2'],C:['a','d','e','f'], |
