@@ -327,7 +327,7 @@ <h3>Drill-down plots</h3>
327327 try {
328328 const geo = await d3 . json ( href ) ;
329329 if ( ! geo || ! geo . features ) return null ;
330- const features = geo . features . map ( f => ( {
330+ const features = geo . features . map ( f => rewindFeatureForSvg ( {
331331 ...f ,
332332 properties : { ...f . properties , loc : String ( f . properties . loc ?? "" ) } ,
333333 } ) ) ;
@@ -339,6 +339,48 @@ <h3>Drill-down plots</h3>
339339 }
340340 }
341341
342+ // Mapbox geojson-rewind (RFC 7946): outer rings CCW for D3/SVG fills.
343+ function rewindRing ( ring , clockwise ) {
344+ let area = 0 ;
345+ for ( let i = 0 , j = ring . length - 1 ; i < ring . length ; j = i ++ ) {
346+ const p0 = ring [ i ] ;
347+ const p1 = ring [ j ] ;
348+ area += ( p1 [ 0 ] - p0 [ 0 ] ) * ( p1 [ 1 ] + p0 [ 1 ] ) ;
349+ }
350+ if ( ( area < 0 ) === clockwise ) ring . reverse ( ) ;
351+ return ring ;
352+ }
353+
354+ function rewindGeometry ( geometry , outerClockwise ) {
355+ if ( ! geometry ) return geometry ;
356+ if ( geometry . type === "Polygon" ) {
357+ return {
358+ ...geometry ,
359+ coordinates : geometry . coordinates . map ( ( ring , i ) =>
360+ rewindRing ( ring . slice ( ) , i === 0 ? outerClockwise : ! outerClockwise ) ,
361+ ) ,
362+ } ;
363+ }
364+ if ( geometry . type === "MultiPolygon" ) {
365+ return {
366+ ...geometry ,
367+ coordinates : geometry . coordinates . map ( poly =>
368+ poly . map ( ( ring , i ) =>
369+ rewindRing ( ring . slice ( ) , i === 0 ? outerClockwise : ! outerClockwise ) ,
370+ ) ,
371+ ) ,
372+ } ;
373+ }
374+ return geometry ;
375+ }
376+
377+ function rewindFeatureForSvg ( feature ) {
378+ return {
379+ ...feature ,
380+ geometry : rewindGeometry ( feature . geometry , false ) ,
381+ } ;
382+ }
383+
342384 function yieldColor ( value , extent ) {
343385 if ( value == null || ! extent ) return REGION_FILL_MISSING ;
344386 const [ lo , hi ] = extent ;
@@ -412,19 +454,24 @@ <h3>Drill-down plots</h3>
412454 { type : "FeatureCollection" , features : fitFeatures } ,
413455 ) ;
414456 const path = d3 . geoPath ( projection ) ;
457+ svg . append ( "rect" )
458+ . attr ( "x" , 0 )
459+ . attr ( "y" , 0 )
460+ . attr ( "width" , REGION_MAP_WIDTH )
461+ . attr ( "height" , REGION_MAP_HEIGHT )
462+ . attr ( "fill" , "#f8f9fa" ) ;
415463 svg . selectAll ( "path.region" )
416464 . data ( plotFeatures )
417465 . join ( "path" )
418466 . attr ( "class" , "region" )
419- . attr ( "fill-rule" , "evenodd" )
420467 . attr ( "d" , path )
421468 . attr ( "fill" , d => {
422469 const loc = d . properties . loc ;
423470 const v = valueByLoc ? valueByLoc [ loc ] : null ;
424471 return yieldColor ( v , extent ) ;
425472 } )
426- . attr ( "stroke" , "#333 " )
427- . attr ( "stroke-width" , 0.35 )
473+ . attr ( "stroke" , "#fff " )
474+ . attr ( "stroke-width" , 0.5 )
428475 . selectAll ( "title" )
429476 . data ( d => [ d ] )
430477 . join ( "title" )
0 commit comments