From 46652b1c61f183df60eaa2c9fc2028dd58e0b68c Mon Sep 17 00:00:00 2001 From: Jakob Cornell Date: Sun, 24 May 2026 12:28:19 -0500 Subject: [PATCH] Switch from overlay to status bar and add progress indicator --- main.js | 27 ++++++++++++++++++--------- parcels.html | 38 ++++++++++++++++++-------------------- 2 files changed, 36 insertions(+), 29 deletions(-) diff --git a/main.js b/main.js index a7e9c47..e2b06e7 100644 --- a/main.js +++ b/main.js @@ -21,9 +21,10 @@ function transposeCoordinates(coordList) { ))); } -async function asyncMain() { - const overlay = document.getElementById("loading-overlay"); +const statusSpan = document.querySelector("#status > span"); +const progressBar = document.querySelector("#status > progress"); +async function asyncMain() { const onVersionUpdate = async (db) => { const parcelStore = db.createObjectStore("features", {keyPath: "properties.OBJECTID"}); }; @@ -31,15 +32,17 @@ async function asyncMain() { await db.open(); if (!(PARCEL_LOAD_KEY in localStorage)) { - overlay.innerText = "downloading parcel data"; + statusSpan.innerText = "downloading parcel data"; const geoJsonResponse = await fetch(PARCEL_JSON_PATH); if (geoJsonResponse.ok) { - overlay.innerText = "parsing dataset"; + statusSpan.innerText = "parsing dataset"; const geoJson = await geoJsonResponse.json(); - overlay.innerText = "saving parcels to persistent storage"; - for (const feature of geoJson.features) { + statusSpan.innerText = "saving parcels to persistent storage"; + for (const [i, feature] of geoJson.features.entries()) { + progressBar.value = i / geoJson.features.length; await db.query("features").put(feature); } + progressBar.value = 1; localStorage[PARCEL_LOAD_KEY] = "1"; } else { console.error(geoJsonResponse); @@ -47,13 +50,17 @@ async function asyncMain() { } } + statusSpan.innerText = "filtering parcels"; + progressBar.value = 0; const store = db.query("features", "readonly"); - overlay.innerText = "filtering parcels"; + const featureCount = await store.count(); const matches = []; + let index = 0; let noZoningCount = 0; let noLotSizeCount = 0; // store.getAll doesn't work for some reason. for await (const {value: feature} of await store.openCursor()) { + progressBar.value = index / featureCount; if (feature.geometry.type == "MultiPolygon") { const zoningParts = (feature.properties.ZoningAll ?? "").split(", "); const zoningMatch = zoningParts.length && new Set(zoningParts).intersection(PICK_ZONINGS).size; @@ -71,10 +78,12 @@ async function asyncMain() { else { console.warn("Skipping %s feature geometry", feature.geometry.type); } + index += 1; } + progressBar.value = 1; console.log( "Searched %d parcels: %d matches, %d with no zoning, %d with no size", - await store.count(), + featureCount, matches.length, noZoningCount, noLotSizeCount, @@ -107,10 +116,10 @@ async function asyncMain() { } console.log(flyBounds); - overlay.style["display"] = "none"; if (flyBounds !== null) { map.flyToBounds(flyBounds); } + statusSpan.innerText = "ready"; } document.getElementById("picked-zones").innerText = [...PICK_ZONINGS].join(", "); diff --git a/parcels.html b/parcels.html index 69e8c3c..c79e8fc 100644 --- a/parcels.html +++ b/parcels.html @@ -15,22 +15,15 @@ flex-grow: 1; z-index: 0; } - #controls { + #sidebar { + display: flex; flex-basis: 25rem; + flex-direction: column; padding: 1rem; } - #loading-overlay { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - z-index: 1; - background: rgba(0, 0, 0, 0.7); - color: white; - font-size: 2rem; - text-align: center; - padding-top: 3rem; + #controls { + flex-grow: 1; + overflow: auto; } @@ -39,15 +32,20 @@ integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin="">
-
-
-

Zoning

-

-

Lot size

-

+
+
-
loading
-- 2.39.5