[object Object]

← back to Nationalrealestate

USRE Map: export matching counties to CSV (parity w/ grid) + fix on-map bar z-collision with geo-search pill (v0.16.0)

1499f0fb153b6ec5800d4b9d905fec3dd3d7060d · 2026-07-26 22:08:43 -0700 · Steve

Files touched

Diff

commit 1499f0fb153b6ec5800d4b9d905fec3dd3d7060d
Author: Steve <steve@designerwallcoverings.com>
Date:   Sun Jul 26 22:08:43 2026 -0700

    USRE Map: export matching counties to CSV (parity w/ grid) + fix on-map bar z-collision with geo-search pill (v0.16.0)
---
 package-lock.json |  4 ++--
 package.json      |  2 +-
 public/index.html | 27 +++++++++++++++++++++++----
 3 files changed, 26 insertions(+), 7 deletions(-)

diff --git a/package-lock.json b/package-lock.json
index 4dfdf6f..291b012 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
 {
   "name": "nationalrealestate",
-  "version": "0.15.0",
+  "version": "0.16.0",
   "lockfileVersion": 3,
   "requires": true,
   "packages": {
     "": {
       "name": "nationalrealestate",
-      "version": "0.15.0",
+      "version": "0.16.0",
       "dependencies": {
         "better-sqlite3": "^13.0.1",
         "dotenv": "^16.4.5",
diff --git a/package.json b/package.json
index c43e81d..37671d5 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "nationalrealestate",
-  "version": "0.15.0",
+  "version": "0.16.0",
   "private": true,
   "type": "module",
   "description": "USRealEstate — national U.S. residential market explorer. Free-data v1 (Redfin Data Center, Zillow Research, Census ACS, FHFA). Internal analyst tool behind basic auth.",
diff --git a/public/index.html b/public/index.html
index 19befef..87f2d3f 100644
--- a/public/index.html
+++ b/public/index.html
@@ -60,13 +60,13 @@
   #mapfilters #mf-count{font-size:12px;color:var(--fg);margin-top:8px;font-variant-numeric:tabular-nums;}
   #mapfilters #mf-count b{color:var(--gold);}
   /* on-map active-filter indicator (top-center; shown only when Map filters are active) */
-  #mapfbar{position:fixed;top:14px;left:50%;transform:translateX(-50%);z-index:1000;align-items:center;gap:12px;
+  #mapfbar{position:fixed;top:64px;left:50%;transform:translateX(-50%);z-index:1000;align-items:center;gap:12px;
     background:rgba(17,21,29,.94);border:1px solid var(--gold);border-radius:20px;padding:6px 8px 6px 16px;
     font-size:12px;color:var(--muted);white-space:nowrap;backdrop-filter:blur(6px);box-shadow:0 2px 12px rgba(0,0,0,.5);}
   #mapfbar b{color:var(--gold);font-variant-numeric:tabular-nums;}
-  #mapfbar #mapfbar-copy{background:none;color:var(--muted);border:1px solid var(--line);border-radius:14px;
+  #mapfbar #mapfbar-copy,#mapfbar #mapfbar-csv{background:none;color:var(--muted);border:1px solid var(--line);border-radius:14px;
     font-size:11px;padding:4px 10px;cursor:pointer;}
-  #mapfbar #mapfbar-copy:hover{color:var(--gold);border-color:var(--gold);}
+  #mapfbar #mapfbar-copy:hover,#mapfbar #mapfbar-csv:hover{color:var(--gold);border-color:var(--gold);}
   #mapfbar #mapfbar-reset{background:var(--gold);color:var(--bg);border:0;border-radius:14px;
     font-size:11px;font-weight:700;padding:4px 12px;cursor:pointer;}
   #mapfbar #mapfbar-reset:hover{filter:brightness(1.08);}
@@ -89,7 +89,7 @@
   <div id="metrics"></div>
 </div>
 <div id="map"></div>
-<div id="mapfbar" style="display:none"><span id="mapfbar-txt"></span><button id="mapfbar-copy" type="button">🔗 link</button><button id="mapfbar-reset" type="button">reset</button></div>
+<div id="mapfbar" style="display:none"><span id="mapfbar-txt"></span><button id="mapfbar-csv" type="button">⭳ CSV</button><button id="mapfbar-copy" type="button">🔗 link</button><button id="mapfbar-reset" type="button">reset</button></div>
 <div id="legend"><div class="t">Loading…</div></div>
 <div id="status">loading county data…</div>
 <div id="natstrip" style="position:fixed;left:50%;transform:translateX(-50%);bottom:18px;z-index:1000;
@@ -219,6 +219,23 @@ function resetMapFilters(){
   if (wrap) wrap.querySelectorAll('input').forEach(i => i.value = '');
   saveMapFilters(); applyFilters();
 }
+function exportMapCSV(){
+  if (!geojson) return;
+  const csvEsc = v => { if (v == null || v === '') return ''; v = String(v); return /[",\n]/.test(v) ? '"' + v.replace(/"/g, '""') + '"' : v; };
+  const header = ['FIPS', 'County'].concat(METRICS.map(m => m.label));
+  const lines = [header.map(csvEsc).join(',')];
+  (geojson.features || []).forEach(f => {
+    if (!filterPass(f.id)) return; // only the matching set
+    const name = (f.properties.NAME || '') + ' ' + (f.properties.LSAD || 'County');
+    const row = [f.id, name.trim()].concat(METRICS.map(m => { const v = (metricVals[m.key] || {})[f.id]; return v == null ? '' : v; }));
+    lines.push(row.map(csvEsc).join(','));
+  });
+  const blob = new Blob([lines.join('\n')], { type: 'text/csv;charset=utf-8' });
+  const url = URL.createObjectURL(blob);
+  const a = document.createElement('a'); a.href = url; a.download = 'usre-map-counties.csv';
+  document.body.appendChild(a); a.click(); a.remove();
+  setTimeout(() => URL.revokeObjectURL(url), 1000);
+}
 function applyFilters(){
   if (geoLayer) geoLayer.setStyle(styleFeature);
   syncMapURL(); // keep the query string in sync so filtered map views are shareable
@@ -265,6 +282,8 @@ function buildMapFilters(){
       if (navigator.clipboard) navigator.clipboard.writeText(location.href);
       cpy.textContent = '✓ copied'; setTimeout(() => cpy.textContent = t, 1200);
     });
+    const csv = bar.querySelector('#mapfbar-csv');
+    if (csv) csv.addEventListener('click', exportMapCSV);
   }
   // active-filter chips: click ✕ to clear that metric's range
   wrap.querySelector('#mf-chips').addEventListener('click', e => {

← 9ab361e USRE geo-search: recent searches (localStorage) shown on emp  ·  back to Nationalrealestate  ·  parcels: add Klamath County OR (41035) free priced-deed feed 180998f →