2026-10-07 12:21:45 -07:00
const RADIUS_KM = 80.4672 ;
const KM_PER_MI = 1.609344 ;
const COLORS = { strand : "#0A8F99" , jacket : "#F0B400" , ink : "#17212B" , contract : "#A23B72" };
const STATUS = {
open : "Open for bids" ,
proposed : "Proposed" ,
awarded : "Awarded" ,
construction : "Under construction" ,
complete : "Built" ,
defaulted : "Defaulted"
};
const S = {
manifest : null ,
map : null ,
layers : {},
fine : new Map (),
coarse : new Map (),
contracts : new Map ()
};
const $ = id => document . getElementById ( id );
function el ( tag , cls , text ) {
const n = document . createElement ( tag );
if ( cls ) n . className = cls ;
if ( text != null ) n . textContent = text ;
return n ;
}
function esc ( s ) {
return String ( s ). replace ( /[&<>"']/g , c => ({ "&" : "&" , "<" : "<" , ">" : ">" , "\"" : """ , "'" : "'" })[ c ]);
}
async function getJSON ( url ) {
try {
const r = await fetch ( url , { cache : "no-cache" });
return r . ok ? await r . json () : null ;
} catch {
return null ;
}
}
function fmtSpeed ( mbps ) {
if ( ! mbps ) return "speed not listed" ;
if ( mbps >= 1000 ) {
const g = mbps / 1000 ;
return ` ${ Number . isInteger ( g ) ? g : g . toFixed ( 1 ) } Gig` ;
}
return ` ${ mbps } Mbps` ;
}
const fmtInt = n => Math . round ( n ). toLocaleString ( "en-US" );
const fmtMoney = n => "$" + Math . round ( n ). toLocaleString ( "en-US" );
function haversineKm ( a , b ) {
const R = 6371.0088 ;
const rad = Math . PI / 180 ;
const dLat = ( b [ 0 ] - a [ 0 ]) * rad ;
const dLng = ( b [ 1 ] - a [ 1 ]) * rad ;
const s = Math . sin ( dLat / 2 ) ** 2 + Math . cos ( a [ 0 ] * rad ) * Math . cos ( b [ 0 ] * rad ) * Math . sin ( dLng / 2 ) ** 2 ;
return 2 * R * Math . asin ( Math . sqrt ( s ));
}
function inRing ( pt , ring ) {
let inside = false ;
for ( let i = 0 , j = ring . length - 1 ; i < ring . length ; j = i ++ ) {
const [ xi , yi ] = ring [ i ];
const [ xj , yj ] = ring [ j ];
if (( yi > pt [ 1 ]) !== ( yj > pt [ 1 ]) && pt [ 0 ] < (( xj - xi ) * ( pt [ 1 ] - yi )) / ( yj - yi ) + xi ) inside = ! inside ;
}
return inside ;
}
function geomDistanceKm ( geom , latlng ) {
const pt = [ latlng [ 1 ], latlng [ 0 ]];
const polys = geom . type === "Polygon" ? [ geom . coordinates ] : geom . type === "MultiPolygon" ? geom . coordinates : [];
if ( polys . some ( p => inRing ( pt , p [ 0 ]) && ! p . slice ( 1 ). some ( h => inRing ( pt , h )))) return 0 ;
let best = Infinity ;
const visit = c => {
if ( typeof c [ 0 ] === "number" ) best = Math . min ( best , haversineKm ( latlng , [ c [ 1 ], c [ 0 ]]));
else c . forEach ( visit );
};
visit ( geom . coordinates );
return best ;
}
function initMap () {
const map = L . map ( "map" , { preferCanvas : true }). setView ([ 34.3 , - 111.7 ], 6 );
2026-10-07 12:39:00 -07:00
const esri = "https://server.arcgisonline.com/ArcGIS/rest/services/Canvas/" ;
L . tileLayer ( esri + "World_Light_Gray_Base/MapServer/tile/{z}/{y}/{x}" , {
maxZoom : 16 ,
attribution : "Tiles © Esri, HERE, Garmin, © OpenStreetMap contributors"
2026-10-07 12:21:45 -07:00
}). addTo ( map );
2026-10-07 12:39:00 -07:00
const labels = map . createPane ( "labels" );
labels . style . zIndex = 450 ;
labels . style . pointerEvents = "none" ;
L . tileLayer ( esri + "World_Light_Gray_Reference/MapServer/tile/{z}/{y}/{x}" , { maxZoom : 16 , pane : "labels" }). addTo ( map );
2026-10-07 12:21:45 -07:00
S . layers . fiber = L . layerGroup (). addTo ( map );
S . layers . contracts = L . layerGroup (). addTo ( map );
S . layers . focus = L . layerGroup (). addTo ( map );
const legend = L . control ({ position : "bottomright" });
legend . onAdd = () => {
const d = L . DomUtil . create ( "div" , "legend" );
d . innerHTML =
`<div><i style="background: ${ COLORS . strand } ;opacity:.55"></i>Fiber reported</div>` +
`<div><i style="background: ${ COLORS . contract } ;opacity:.55"></i>Contract or bid area</div>` +
`<div><i style="border:2px dashed ${ COLORS . ink } "></i>50 miles</div>` ;
return d ;
};
legend . addTo ( map );
S . map = map ;
}
2026-10-07 12:39:00 -07:00
async function geocodeEsri ( q ) {
const url = "https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/findAddressCandidates?" + new URLSearchParams ({
SingleLine : q ,
f : "json" ,
outFields : "Match_addr,RegionAbbr,Subregion" ,
sourceCountry : "USA" ,
maxLocations : "1" ,
outSR : "4326"
});
try {
const r = await fetch ( url );
if ( ! r . ok ) return null ;
const d = await r . json ();
const c = ( d . candidates || [])[ 0 ];
if ( ! c || c . score < 80 ) return null ;
const a = c . attributes || {};
return {
lat : c . location . y ,
lng : c . location . x ,
label : a . Match_addr || c . address ,
state : a . RegionAbbr || null ,
county : ( a . Subregion || "" ). replace ( /\s+County$/i , "" ). trim ()
};
} catch {
return null ;
}
}
async function geocodeOsm ( q ) {
2026-10-07 12:21:45 -07:00
const url = "https://nominatim.openstreetmap.org/search?" + new URLSearchParams ({
q ,
format : "jsonv2" ,
addressdetails : "1" ,
limit : "1" ,
countrycodes : "us"
});
2026-10-07 12:39:00 -07:00
try {
const r = await fetch ( url , { headers : { "Accept-Language" : "en" } });
if ( ! r . ok ) return null ;
const list = await r . json ();
if ( ! list . length ) return null ;
const hit = list [ 0 ];
const a = hit . address || {};
const iso = a [ "ISO3166-2-lvl4" ] || "" ;
return {
lat : Number ( hit . lat ),
lng : Number ( hit . lon ),
label : hit . display_name . split ( "," ). slice ( 0 , 4 ). join ( "," ). trim (),
state : iso . startsWith ( "US-" ) ? iso . slice ( 3 ) : null ,
county : ( a . county || "" ). replace ( /\s+County$/i , "" ). trim ()
};
} catch {
return null ;
}
}
async function geocode ( q ) {
return ( await geocodeEsri ( q )) || ( await geocodeOsm ( q ));
2026-10-07 12:21:45 -07:00
}
function shard ( cache , dir , id ) {
if ( ! cache . has ( id )) cache . set ( id , getJSON ( `data/fiber/ ${ dir } / ${ id } .json` ));
return cache . get ( id );
}
async function fiberAt ( lat , lng ) {
const m = S . manifest ;
const cell = h3 . latLngToCell ( lat , lng , m . fineRes );
const ring = h3 . gridDisk ( cell , 1 );
const ids = [... new Set ( ring . map ( c => h3 . cellToParent ( c , m . fineShardRes )))];
const docs = new Map ( await Promise . all ( ids . map ( async id => [ id , await shard ( S . fine , "r8" , id )])));
const read = c => {
const d = docs . get ( h3 . cellToParent ( c , m . fineShardRes ));
const v = d && d . c [ c ];
if ( ! v ) return null ;
return { cell : c , count : v [ 0 ], providers : v [ 1 ]. map (([ i , down , up ]) => ({ name : d . p [ i ], down , up })) };
};
return { cell , own : read ( cell ), near : ring . filter ( c => c !== cell ). map ( read ). filter ( Boolean ) };
}
async function fiberRegion ( lat , lng ) {
const m = S . manifest ;
const ids = h3 . gridDisk ( h3 . latLngToCell ( lat , lng , m . coarseShardRes ), 2 );
const docs = await Promise . all ( ids . map ( id => shard ( S . coarse , "r6" , id )));
const cells = [];
const totals = new Map ();
for ( const d of docs ) {
if ( ! d ) continue ;
for ( const [ c , v ] of Object . entries ( d . c )) {
if ( haversineKm ([ lat , lng ], h3 . cellToLatLng ( c )) > RADIUS_KM ) continue ;
const names = v [ 1 ]. map ( i => d . p [ i ]);
cells . push ({ cell : c , count : v [ 0 ], names });
for ( const n of names ) totals . set ( n , ( totals . get ( n ) || 0 ) + 1 );
}
}
return { cells , providers : [... totals . entries ()]. sort (( a , b ) => b [ 1 ] - a [ 1 ]) };
}
async function contractsNear ( place ) {
const states = S . manifest . contractStates || [];
const docs = await Promise . all ( states . map ( async st => {
if ( ! S . contracts . has ( st )) S . contracts . set ( st , getJSON ( `data/contracts/ ${ st } .json` ));
return [ st , await S . contracts . get ( st )];
}));
const items = [];
const programs = [];
const county = place . county . toLowerCase ();
for ( const [ st , d ] of docs ) {
if ( ! d ) continue ;
const home = st === place . state ;
if ( home ) programs . push (...( d . programs || []));
for ( const it of d . items || []) {
let where = null ;
let distance = null ;
if ( it . geometry ) {
const km = geomDistanceKm ( it . geometry , [ place . lat , place . lng ]);
if ( km <= RADIUS_KM ) {
distance = km ;
where = km === 0 ? "Covers this address" : ` ${ Math . max ( 1 , Math . round ( km / KM_PER_MI )) } mi away` ;
}
}
if ( ! where && home && county && ( it . counties || []). some ( c => c . toLowerCase () === county )) where = ` ${ place . county } County` ;
if ( ! where && home && it . scope === "statewide" ) where = "Statewide" ;
if ( where ) items . push ({ ... it , state : st , where , distance });
}
}
const rank = it => ( it . distance != null ? it . distance : it . where === "Statewide" ? 1e6 : 1e5 );
items . sort (( a , b ) => ( a . status === "open" ? 0 : 1 ) - ( b . status === "open" ? 0 : 1 ) || rank ( a ) - rank ( b ));
return { items , programs };
}
function drawFocus ( place , at ) {
const g = S . layers . focus ;
g . clearLayers ();
L . circle ([ place . lat , place . lng ], {
radius : RADIUS_KM * 1000 ,
color : COLORS . ink ,
weight : 1.5 ,
dashArray : "6 6" ,
fill : false ,
interactive : false
}). addTo ( g );
if ( at ) {
L . polygon ( h3 . cellToBoundary ( at . cell ), { color : COLORS . jacket , weight : 2 , fill : false , interactive : false }). addTo ( g );
}
L . marker ([ place . lat , place . lng ], {
icon : L . divIcon ({ className : "" , html : "<div class=\"pin\"></div>" , iconSize : [ 18 , 18 ], iconAnchor : [ 9 , 9 ] }),
title : place . label ,
keyboard : false
}). addTo ( g );
}
function drawRegion ( region ) {
const g = S . layers . fiber ;
g . clearLayers ();
if ( ! region ) return ;
const max = region . cells . reduce (( m , c ) => Math . max ( m , c . count ), 1 );
for ( const c of region . cells ) {
const t = Math . log1p ( c . count ) / Math . log1p ( max );
const names = c . names . slice ( 0 , 4 ). map ( esc ). join ( ", " ) + ( c . names . length > 4 ? `, + ${ c . names . length - 4 } more` : "" );
L . polygon ( h3 . cellToBoundary ( c . cell ), {
color : COLORS . strand ,
weight : 0.5 ,
opacity : 0.4 ,
fillColor : COLORS . strand ,
fillOpacity : 0.12 + 0.5 * t
}). bindTooltip ( `<strong> ${ fmtInt ( c . count ) } fiber locations</strong><br> ${ names } ` , { sticky : true }). addTo ( g );
}
}
function drawContracts ( items ) {
const g = S . layers . contracts ;
g . clearLayers ();
for ( const it of items ) {
if ( ! it . geometry ) continue ;
const color = it . status === "open" ? COLORS . jacket : COLORS . contract ;
L . geoJSON ( it . geometry , {
style : { color , weight : 2 , fillColor : color , fillOpacity : 0.12 },
pointToLayer : ( f , ll ) => L . circleMarker ( ll , { radius : 7 , color , weight : 2 , fillColor : color , fillOpacity : 0.5 })
}). bindTooltip ( `<strong> ${ esc ( it . awardee || "Open bid" ) } </strong><br> ${ esc ( it . program || "" ) } ` , { sticky : true }). addTo ( g );
}
}
function verdictFor ( place , covered , at , region ) {
if ( ! covered ) {
const list = S . manifest . states . length ? S . manifest . states . join ( ", " ) : "no states yet" ;
return {
kind : "unknown" ,
title : "No fiber data for this state yet" ,
text : `Fiber data currently covers ${ list } . Add ${ place . state || "this state" } to the data build to check this address.`
};
}
if ( at . own ) {
return {
kind : "yes" ,
title : "Fiber is available here" ,
text : `Reported at ${ fmtInt ( at . own . count ) } ${ at . own . count === 1 ? "location" : "locations" } in the quarter square mile around this address.`
};
}
if ( at . near . length ) {
const n = at . near . reduce (( s , c ) => s + c . count , 0 );
return {
kind : "near" ,
title : "Fiber is close by" ,
text : `Not reported on this block, but reported at ${ fmtInt ( n ) } ${ n === 1 ? "location" : "locations" } within about half a mile.`
};
}
return {
kind : "no" ,
title : "No fiber reported here" ,
text : region && region . cells . length ? "Fiber is reported elsewhere within 50 miles. See the map." : "No fiber is reported within 50 miles of this address."
};
}
function mergeProviders ( cells ) {
const m = new Map ();
for ( const c of cells ) {
for ( const p of c . providers ) {
const e = m . get ( p . name );
if ( ! e ) m . set ( p . name , { ... p });
else {
e . down = Math . max ( e . down , p . down );
e . up = Math . max ( e . up , p . up );
}
}
}
return [... m . values ()]. sort (( a , b ) => b . down - a . down || a . name . localeCompare ( b . name ));
}
function providerList ( providers ) {
const ul = el ( "ul" , "list" );
for ( const p of providers ) {
const li = el ( "li" );
li . append ( el ( "span" , null , p . name ), el ( "span" , "sub" , ` ${ fmtSpeed ( p . down ) } down, ${ fmtSpeed ( p . up ) } up` ));
ul . append ( li );
}
return ul ;
}
function contractCard ( it ) {
const card = el ( "article" , "contract" + ( it . status === "open" ? " open" : "" ));
card . append ( el ( "h4" , null , it . awardee || it . title || "Open bid" ));
const facts = el ( "div" , "facts" );
const badge = el ( "span" , "badge" + ( it . status === "open" ? " open" : "" ), STATUS [ it . status ] || it . status || "Listed" );
facts . append ( badge , el ( "span" , null , it . where ));
if ( it . program ) facts . append ( el ( "span" , null , it . program ));
if ( it . technology ) facts . append ( el ( "span" , null , it . technology ));
if ( it . amount != null ) facts . append ( el ( "span" , null , fmtMoney ( it . amount )));
if ( it . locations != null ) facts . append ( el ( "span" , null , ` ${ fmtInt ( it . locations ) } locations` ));
if ( it . deadline ) facts . append ( el ( "span" , null , `Bids due ${ it . deadline } ` ));
card . append ( facts );
if ( it . notes ) card . append ( el ( "p" , null , it . notes ));
if ( it . source ) {
const p = el ( "p" );
const a = el ( "a" , null , "Source" );
a . href = it . source ;
a . target = "_blank" ;
a . rel = "noopener" ;
p . append ( a );
if ( it . updated ) p . append ( ` (as of ${ it . updated } )` );
card . append ( p );
}
return card ;
}
function render ( place , covered , at , region , deals ) {
const root = $ ( "result" );
root . replaceChildren ();
const v = verdictFor ( place , covered , at , region );
const vb = el ( "section" , `verdict ${ v . kind } ` );
vb . append ( el ( "p" , "address" , place . label ), el ( "h2" , null , v . title ), el ( "p" , null , v . text ), el ( "div" , "strand" ));
root . append ( vb );
if ( covered && ( at . own || at . near . length )) {
const b = el ( "section" , "block" );
b . append ( el ( "h3" , null , at . own ? "Providers at this address" : "Providers close by" ));
b . append ( providerList ( mergeProviders ( at . own ? [ at . own ] : at . near )));
root . append ( b );
}
if ( covered ) {
const b = el ( "section" , "block" );
b . append ( el ( "h3" , null , "Fiber within 50 miles" ));
if ( region . cells . length ) {
b . append ( el ( "p" , "note" , `Fiber is reported in ${ fmtInt ( region . cells . length ) } of the map areas within 50 miles.` ));
const ul = el ( "ul" , "list" );
for ( const [ name , n ] of region . providers . slice ( 0 , 8 )) {
const li = el ( "li" );
li . append ( el ( "span" , null , name ), el ( "span" , "sub" , ` ${ fmtInt ( n ) } ${ n === 1 ? "area" : "areas" } ` ));
ul . append ( li );
}
b . append ( ul );
if ( region . providers . length > 8 ) b . append ( el ( "p" , "note" , `Plus ${ region . providers . length - 8 } more providers. Hover the map for details.` ));
} else {
b . append ( el ( "p" , "note" , "No fiber reported within 50 miles." ));
}
root . append ( b );
}
const cb = el ( "section" , "block" );
cb . append ( el ( "h3" , null , "Contracts and bids" ));
if ( deals . items . length ) deals . items . forEach ( it => cb . append ( contractCard ( it )));
else cb . append ( el ( "p" , "note" , "No broadband contracts or open bids are listed near this address." ));
for ( const p of deals . programs ) {
const n = el ( "p" , "note" );
n . append ( ` ${ p . name } : ${ p . summary } ` );
if ( p . url ) {
const a = el ( "a" , null , p . office || "Program page" );
a . href = p . url ;
a . target = "_blank" ;
a . rel = "noopener" ;
n . append ( a );
}
cb . append ( n );
}
root . append ( cb );
}
function renderError ( msg ) {
const root = $ ( "result" );
root . replaceChildren ( el ( "p" , "error" , msg ));
}
function renderMeta () {
const m = S . manifest ;
const f = $ ( "meta" );
f . replaceChildren ();
const p1 = el ( "p" );
if ( m . asOf ) {
p1 . append ( `Fiber data: FCC National Broadband Map, as of ${ m . asOf } . Providers report their own coverage, so confirm with the provider before you sign up. ` );
} else {
p1 . append ( "Fiber data has not been built yet. Run the Update fiber data workflow. " );
}
const a = el ( "a" , null , "Check the FCC map" );
a . href = "https://broadbandmap.fcc.gov/" ;
a . target = "_blank" ;
a . rel = "noopener" ;
p1 . append ( a );
f . append ( p1 );
2026-10-07 12:39:00 -07:00
f . append ( el ( "p" , null , "Address search by Esri, with OpenStreetMap Nominatim as backup." ));
2026-10-07 12:21:45 -07:00
}
async function check ( q ) {
const btn = $ ( "go" );
btn . disabled = true ;
btn . textContent = "Checking..." ;
try {
const place = await geocode ( q );
if ( ! place ) {
renderError ( "No match for that address. Add the city and state, then try again." );
return ;
}
const covered = S . manifest . states . includes ( place . state );
const [ at , region , deals ] = await Promise . all ([
covered ? fiberAt ( place . lat , place . lng ) : null ,
covered ? fiberRegion ( place . lat , place . lng ) : null ,
contractsNear ( place )
]);
drawRegion ( region );
drawContracts ( deals . items );
drawFocus ( place , at );
S . map . fitBounds ( L . latLng ( place . lat , place . lng ). toBounds ( RADIUS_KM * 2000 ), { padding : [ 10 , 10 ] });
render ( place , covered , at , region , deals );
const url = new URL ( location . href );
url . searchParams . set ( "q" , q );
history . replaceState ( null , "" , url );
} catch ( e ) {
renderError ( e . message || "Something went wrong loading the data. Reload the page and try again." );
} finally {
btn . disabled = false ;
btn . textContent = "Check address" ;
}
}
async function main () {
initMap ();
S . manifest = ( await getJSON ( "data/manifest.json" )) || { states : [], contractStates : [], fineRes : 8 , fineShardRes : 5 , coarseRes : 6 , coarseShardRes : 3 };
renderMeta ();
$ ( "search" ). addEventListener ( "submit" , e => {
e . preventDefault ();
const q = $ ( "address" ). value . trim ();
if ( q ) check ( q );
});
const q = new URLSearchParams ( location . search ). get ( "q" );
if ( q ) {
$ ( "address" ). value = q ;
check ( q );
}
}
main ();