@@ -195,7 +195,7 @@ function layoutSky() {
195195 phase : rand ( ) * Math . PI * 2 ,
196196 speed : 0.4 + rand ( ) * 1.1 ,
197197 color,
198- name : m . name , group : label , chamber,
198+ name : m . name , group : label , chamber, url : m . url || "" ,
199199 } ;
200200 sky . stars . push ( star ) ;
201201 return star ;
@@ -284,27 +284,38 @@ function skyLoop(time) {
284284 requestAnimationFrame ( skyLoop ) ;
285285}
286286
287- /* tooltip: stella più vicina al puntatore */
287+ /* tooltip + click: stella più vicina al puntatore */
288+ function nearestStar ( e ) {
289+ const rect = sky . canvas . getBoundingClientRect ( ) ;
290+ const mx = e . clientX - rect . left , my = e . clientY - rect . top ;
291+ let best = null , bd = 14 * 14 ;
292+ for ( const s of sky . stars ) {
293+ const d = ( s . x - mx ) ** 2 + ( s . y - my ) ** 2 ;
294+ if ( d < bd ) { bd = d ; best = s ; }
295+ }
296+ return best ;
297+ }
298+
288299function initSkyTooltip ( ) {
289300 const tip = document . getElementById ( "sky-tooltip" ) ;
290301 sky . canvas . addEventListener ( "pointermove" , ( e ) => {
291- const rect = sky . canvas . getBoundingClientRect ( ) ;
292- const mx = e . clientX - rect . left , my = e . clientY - rect . top ;
293- let best = null , bd = 14 * 14 ;
294- for ( const s of sky . stars ) {
295- const d = ( s . x - mx ) ** 2 + ( s . y - my ) ** 2 ;
296- if ( d < bd ) { bd = d ; best = s ; }
297- }
302+ const best = nearestStar ( e ) ;
303+ sky . canvas . style . cursor = best && best . url ? "pointer" : "crosshair" ;
298304 if ( best ) {
299305 tip . hidden = false ;
300- tip . innerHTML = `<span class="tt-chamber">${ best . chamber } </span><br>${ best . name } <br><span class="tt-group">${ best . group } </span>` ;
306+ tip . innerHTML = `<span class="tt-chamber">${ best . chamber } </span><br>${ best . name } <br><span class="tt-group">${ best . group } </span>`
307+ + ( best . url ? `<br><span class="tt-open">clic → scheda ufficiale ↗</span>` : "" ) ;
301308 tip . style . left = Math . min ( e . clientX + 14 , innerWidth - 280 ) + "px" ;
302309 tip . style . top = e . clientY + 14 + "px" ;
303310 } else {
304311 tip . hidden = true ;
305312 }
306313 } ) ;
307314 sky . canvas . addEventListener ( "pointerleave" , ( ) => ( tip . hidden = true ) ) ;
315+ sky . canvas . addEventListener ( "click" , ( e ) => {
316+ const best = nearestStar ( e ) ;
317+ if ( best && best . url ) window . open ( best . url , "_blank" , "noopener" ) ;
318+ } ) ;
308319}
309320
310321/* ---------------- caricamento cielo + contatori ---------------- */
@@ -338,10 +349,10 @@ async function loadSky() {
338349
339350 const deputies = latestMembership ( cam , "deputy_uri" )
340351 . filter ( ( r ) => ! r . end_date )
341- . map ( ( r ) => ( { name : r . deputy_name , group : r . group_label } ) ) ;
352+ . map ( ( r ) => ( { name : r . deputy_name , group : r . group_label , url : r . html_url } ) ) ;
342353 const senators = latestMembership ( sen , "senator_uri" )
343354 . filter ( ( r ) => ! r . end_date )
344- . map ( ( r ) => ( { name : r . senator_name , group : r . group_label } ) ) ;
355+ . map ( ( r ) => ( { name : r . senator_name , group : r . group_label , url : r . html_url } ) ) ;
345356
346357 sky . raw = { camera : deputies , senato : senators } ;
347358 layoutSky ( ) ;
0 commit comments