Skip to content

build4me2/psef-network-map

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PSEF Network Map

An interactive map of the People's Solar Energy Fund and its 39 member organizations across the United States, Puerto Rico, and Hawaiʻi.

A single-page static site. No backend, no build step, no API keys at runtime — every coordinate, distance, and state polygon is bundled as static JSON / GeoJSON. Drop the folder on any static host and it works.

Table of Contents

Background

PSEF is a national loan fund for community-owned solar, founded in 2018. Its 39 member organizations are local cooperatives, community-development corporations, tribal energy authorities, and national alliances — geographically scattered from Hawaiʻi to Puerto Rico.

This map gives the network a visible shape. PSEF sits at the center as the network hub (sun); each member is a region-colored dot, connected to PSEF by a line annotated with the distance between them. Clicking any state surfaces every PSEF member that operates there; clicking a member opens its address, distance from PSEF, and a link to its site.

The map is meant to be low-maintenance: any volunteer can update the network by editing one Python coordinate table and re-running a small build pipeline. There is no CMS, no database, no service to keep alive.

Install

No dependencies to install. The frontend pulls MapLibre GL JS and the Satoshi font from public CDNs at runtime; everything else is local.

git clone <repo-url>
cd network-map

The build pipeline (used only when member data changes — see Updating member data) needs Python 3.8+ and uses only the standard library.

Usage

Run any static HTTP server from this directory and open the page:

python3 -m http.server 8000
# open http://localhost:8000

Any static server works (npx serve, caddy file-server, etc.). You must serve over HTTP — opening index.html via file:// will fail because fetch blocks file:// requests in modern browsers.

What the user can do

Interaction Result
Drag the map Pans in any direction
Scroll wheel / two-finger trackpad Pans (no accidental zoom)
Ctrl / + scroll Zooms
+ / buttons (top-left) Zoom
Click the amber sun Popup with PSEF HQ address + link
Click a colored dot Popup with member address, distance to PSEF, link to site
Click an empty area inside a state Popup listing every PSEF member in that state
Click the 39 member orgs card Opens a left panel with every member grouped by region
Click the states / founded / regions cards Opens an info modal
Click the button Resets view to fit all members

Updating member data

When the network changes (a new member, a moved HQ, a confirmed pinpoint city for an approximate row):

  1. Edit data/members_raw.md to keep the human-readable list current.
  2. Mirror the change in the MEMBERS table at the top of scripts/build_data.py.
  3. Rebuild and validate:
    python3 scripts/build_data.py    # rewrites data/members.json
    python3 scripts/validate.py       # confirms every dot is inside its declared state
  4. Reload the page. No JS changes needed.

To refresh the state polygons themselves (rare):

python3 scripts/fetch_osm_states_geojson.py    # downloads fresh polygons from OSM
python3 scripts/enrich_states_geojson.py        # idempotent — adds STUSPS / NAME
python3 scripts/patch_oahu_polygon.py           # idempotent — Wai'anae fix if needed
python3 scripts/validate.py

All scripts are idempotent.

Project structure

network-map/
├── index.html            page shell
├── app.js                map rendering + interactions (MapLibre GL JS)
├── styles.css            dark theme, marker shapes, popup styling
├── assets/               PSEF logo + favicon
├── data/
│   ├── members_raw.md    source-of-truth member list (human-readable)
│   ├── members.json      built artifact: PSEF + 39 members, geocoded, distances baked in
│   └── us-states.geojson 52 features (50 states + DC + PR), sourced from OpenStreetMap
└── scripts/              Python build pipeline (no external deps)

Architecture

The frontend is vanilla JS on MapLibre GL JS 5.24.0 — flat 2D Mercator, locked north-up, with continuous horizontal wrap so the user can drag east past the date line indefinitely. The basemap is CartoDB dark_all raster tiles. State polygons come from OpenStreetMap (matching the basemap source so the overlay borders sit on top of the tile-drawn ones).

For deep technical detail — data schema, build-pipeline internals, layer-by-layer breakdown of the map, and design-decision rationale — see ARCHITECTURE.md.

Deployment

The site is static, so any free static-hosting service can serve it as-is. DEPLOYMENT.md walks through three options PSEF can choose from — GitHub Pages, Cloudflare Pages, and Netlify — with step-by-step setup, custom-domain instructions, and a comparison table.

Maintainers

Contributing

Issues and PRs welcome. To propose a change to the network:

  • For data changes (new member, corrected address, confirmed coordinates), edit data/members_raw.md and the MEMBERS table in scripts/build_data.py, then run build_data.py + validate.py and include the regenerated data/members.json in your PR.
  • For UI / interaction changes, edit app.js / styles.css and reload — no build step.

If you find a member dot that lands in the wrong state, that's almost always a coordinate error in MEMBERSvalidate.py will tell you which row.

License

Not yet decided. Until a license is added, default copyright applies (all rights reserved); contact the maintainer before redistributing.

About

Interactive map of PSEF and its 39 member organizations

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors