@@ -147,8 +147,17 @@ <h2>Five Data Layers</h2>
147147 <!-- STATEWIDE LINEAR SUMMARY -->
148148 < section class ="statewide-summary-section " id ="statewide-summary ">
149149 < div class ="rpc-explorer-inner ">
150- < h2 > Linear Feature Length by System Type — Vermont Statewide</ h2 >
151- < p > Total length of mapped linear infrastructure across all of Vermont. This data provides a overview of the state's wastewater and stormwater infrastructure but does not include all private infrastructure nor some towns may be missing data.</ p >
150+ < h2 > Wastewater & Combined Sewer Coverage by Town — Vermont Statewide</ h2 >
151+ < p > Number of Vermont's 256 towns with at least some mapped wastewater or combined sewer linear features in this dataset.</ p >
152+ < div id ="town-coverage-chart-wrap ">
153+ < div class ="rpc-loading-row " id ="town-coverage-loading ">
154+ < span class ="spinner "> </ span > Loading statewide data…
155+ </ div >
156+ < div id ="town-coverage-chart "> </ div >
157+ </ div >
158+
159+ < h3 class ="statewide-subheading "> Linear Feature Length by System Type — Vermont Statewide</ h3 >
160+ < p > Total length of mapped linear infrastructure across all of Vermont. This data provides an overview of the state's wastewater and stormwater infrastructure but does not include all private infrastructure and some towns may be missing data.</ p >
152161 < div id ="statewide-chart-wrap ">
153162 < div class ="rpc-loading-row " id ="statewide-loading ">
154163 < span class ="spinner "> </ span > Loading statewide data…
@@ -583,6 +592,65 @@ <h4>GitHub Repository</h4>
583592
584593 document . getElementById ( 'linear-loading' ) . style . display = 'none' ;
585594
595+ // ── Town coverage chart ───────────────────────────────────────────
596+ const townsWithData = new Set ( ) ;
597+ datasets . forEach ( data => {
598+ data . features . forEach ( feat => {
599+ const st = feat . properties . SystemType ;
600+ if ( st === 'Wastewater' || st === 'Combined' ) {
601+ const geoid = feat . properties . GEOIDTXT ;
602+ if ( geoid ) townsWithData . add ( geoid ) ;
603+ }
604+ } ) ;
605+ } ) ;
606+ const totalTowns = rawData . towns ? rawData . towns . features . length : 256 ;
607+ const townsHas = townsWithData . size ;
608+ const townsNone = totalTowns - townsHas ;
609+ const slices = [
610+ { label : 'Has mapped wastewater or combined sewer' , count : townsHas , color : '#1a7a9a' } ,
611+ { label : 'No mapped wastewater or combined sewer' , count : townsNone , color : '#bdc3c7' }
612+ ] ;
613+ // Build SVG donut chart
614+ const cx = 110 , cy = 110 , r = 90 , hole = 52 ;
615+ function arc ( cx , cy , r , startDeg , endDeg ) {
616+ const s = ( startDeg - 90 ) * Math . PI / 180 ;
617+ const e = ( endDeg - 90 ) * Math . PI / 180 ;
618+ const large = endDeg - startDeg > 180 ? 1 : 0 ;
619+ const si = ( startDeg - 90 ) * Math . PI / 180 ;
620+ const ei = ( endDeg - 90 ) * Math . PI / 180 ;
621+ return [
622+ `M ${ cx + r * Math . cos ( s ) } ${ cy + r * Math . sin ( s ) } ` ,
623+ `A ${ r } ${ r } 0 ${ large } 1 ${ cx + r * Math . cos ( e ) } ${ cy + r * Math . sin ( e ) } ` ,
624+ `L ${ cx + hole * Math . cos ( ei ) } ${ cy + hole * Math . sin ( ei ) } ` ,
625+ `A ${ hole } ${ hole } 0 ${ large } 0 ${ cx + hole * Math . cos ( si ) } ${ cy + hole * Math . sin ( si ) } ` ,
626+ 'Z'
627+ ] . join ( ' ' ) ;
628+ }
629+ let deg = 0 ;
630+ const paths = slices . map ( ( { count, color } ) => {
631+ const sweep = count / totalTowns * 360 ;
632+ const path = `<path d="${ arc ( cx , cy , r , deg , deg + sweep ) } " fill="${ color } " stroke="#fff" stroke-width="2"/>` ;
633+ deg += sweep ;
634+ return path ;
635+ } ) . join ( '' ) ;
636+ const legendItems = slices . map ( ( { label, count, color } ) =>
637+ `<div class="pie-legend-item">
638+ <span class="pie-legend-swatch" style="background:${ color } ;"></span>
639+ <span>${ label } — <strong>${ count } </strong> towns (${ ( count / totalTowns * 100 ) . toFixed ( 1 ) } %)</span>
640+ </div>`
641+ ) . join ( '' ) ;
642+ document . getElementById ( 'town-coverage-chart' ) . innerHTML = `
643+ <div class="pie-chart-wrap">
644+ <svg viewBox="0 0 220 220" width="220" height="220">
645+ ${ paths }
646+ <text x="${ cx } " y="${ cy - 10 } " text-anchor="middle" font-size="22" font-weight="700" fill="#1a3a4a">${ ( townsHas / totalTowns * 100 ) . toFixed ( 0 ) } %</text>
647+ <text x="${ cx } " y="${ cy + 10 } " text-anchor="middle" font-size="11" fill="#666">of towns</text>
648+ <text x="${ cx } " y="${ cy + 26 } " text-anchor="middle" font-size="11" fill="#666">have data</text>
649+ </svg>
650+ <div class="pie-legend">${ legendItems } </div>
651+ </div>` ;
652+ document . getElementById ( 'town-coverage-loading' ) . style . display = 'none' ;
653+
586654 // ── Statewide length chart ────────────────────────────────────────
587655 const statewideLen = { Wastewater : 0 , Stormwater : 0 , Water : 0 , Combined : 0 } ;
588656 datasets . forEach ( data => {
@@ -618,6 +686,7 @@ <h4>GitHub Repository</h4>
618686 ` ;
619687 } ) . catch ( ( ) => {
620688 document . getElementById ( 'linear-loading' ) . style . display = 'none' ;
689+ document . getElementById ( 'town-coverage-loading' ) . style . display = 'none' ;
621690 document . getElementById ( 'statewide-loading' ) . style . display = 'none' ;
622691 } ) ;
623692
0 commit comments