From 052b0a3e265bca773c14914aa4ee19c190998d4a Mon Sep 17 00:00:00 2001 From: Emi Griffith Date: Sat, 11 Jul 2026 01:35:43 -0700 Subject: [PATCH] =?UTF-8?q?Picker=20map:=20smaller=20labels,=20darker=20ro?= =?UTF-8?q?ads;=20location=20label=20coords=E2=86=92place=20(#27)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Picker map: smaller city labels, darker/bolder roads (split tile layers) Split the CARTO Voyager basemap into two raster layers so label size and road weight are independent: a labels-free base upscaled via tileSize 512 + zoomOffset -1 (bold, prominent roads) plus a labels-only layer at natural size on top (small, crisp city names). The darken/saturate filter now targets the base layer only (.mp-base: brightness .92, contrast 1.12), deepening the roads while leaving label text at full contrast. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01B3Q2EkHHnTUX2BfhV5q1Zc * Location label: show coordinates immediately, then resolve to place name On selecting a location, write the raw coordinates to the location label right away, so the user sees the picked spot instantly instead of a stale/blank label. The existing post-fetch render already overwrites it with the reverse-geocoded "neighborhood, city, region" string (data.place), so the label now reads coords → place name live. - app.js / calendar.js / day.js: set coords in the selection handler before the fetch; the render/initOnce overwrite is unchanged. - compare.js: show coordinates through the pending + loading states (instead of "Locating…") so each chip's coords are replaced live by the place name once scored. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01B3Q2EkHHnTUX2BfhV5q1Zc --------- Co-authored-by: Claude Opus 4.8 --- static/app.js | 4 ++++ static/calendar.js | 4 ++++ static/compare.js | 8 ++++++-- static/day.js | 9 ++++++++- static/mappicker.js | 23 +++++++++++++++-------- static/style.css | 5 +++-- 6 files changed, 40 insertions(+), 13 deletions(-) diff --git a/static/app.js b/static/app.js index db39ab3..72105f3 100644 --- a/static/app.js +++ b/static/app.js @@ -25,6 +25,10 @@ todayBtn.addEventListener("click", () => { function selectLocation(lat, lon) { selected = { lat, lon }; + // Show the raw coordinates immediately; render() replaces them with the resolved + // neighborhood + city name once the grade fetch returns. + locLabel.textContent = `${lat.toFixed(3)}, ${lon.toFixed(3)}`; + locLabel.hidden = false; runGrade(); } diff --git a/static/calendar.js b/static/calendar.js index 9e8eaa4..f16f391 100644 --- a/static/calendar.js +++ b/static/calendar.js @@ -438,6 +438,10 @@ function selectLocation(lat, lon) { selected = { lat, lon }; history.replaceState(null, "", `#lat=${lat.toFixed(5)}&lon=${lon.toFixed(5)}`); window.Thermograph.saveLastLocation(lat, lon); // keep date for the other views + // Show the raw coordinates immediately; they're replaced with the resolved + // neighborhood + city name once the first calendar chunk lands. + locLabel.textContent = `${lat.toFixed(3)}, ${lon.toFixed(3)}`; + locLabel.hidden = false; fetchCalendar(); } diff --git a/static/compare.js b/static/compare.js index 4540077..001d627 100644 --- a/static/compare.js +++ b/static/compare.js @@ -250,9 +250,13 @@ const deg = (v) => `${Math.round(v)}°`; function renderLocList() { locList.innerHTML = locations.map((l, i) => { let label, cls = "cmp-chip"; - if (l.loading) { label = "Locating…"; cls += " loading"; } + // Show the raw coordinates while pending/loading (with the loading class still + // driving the spinner); once scored, l.name holds the resolved neighborhood + + // city, so the coordinates are replaced live by the place name. + const coords = `${l.lat.toFixed(2)}, ${l.lon.toFixed(2)}`; + if (l.loading) { label = l.name || coords; cls += " loading"; } else if (l.error) { label = "Couldn't load"; cls += " error"; } - else if (!l.series) { label = l.name || `${l.lat.toFixed(2)}, ${l.lon.toFixed(2)}`; cls += " pending"; } + else if (!l.series) { label = l.name || coords; cls += " pending"; } else { label = l.name; } return `
  • ${label}` + `
  • `; diff --git a/static/day.js b/static/day.js index 5dc4320..004e7f5 100644 --- a/static/day.js +++ b/static/day.js @@ -75,7 +75,14 @@ const findBtn = document.getElementById("find-btn"); const locLabel = document.getElementById("loc-label"); findBtn.innerHTML = `${window.LocationPicker.PIN_ICON} Find a location`; findBtn.addEventListener("click", () => { - window.LocationPicker.open(selected, (lat, lon) => { selected = { lat, lon }; fetchDay(); }); + window.LocationPicker.open(selected, (lat, lon) => { + selected = { lat, lon }; + // Show the raw coordinates immediately; render() replaces them with the + // resolved neighborhood + city name once the day fetch returns. + locLabel.textContent = `${lat.toFixed(3)}, ${lon.toFixed(3)}`; + locLabel.hidden = false; + fetchDay(); + }); }); // ---- date navigation ---- diff --git a/static/mappicker.js b/static/mappicker.js index 78ff00b..bea750a 100644 --- a/static/mappicker.js +++ b/static/mappicker.js @@ -118,15 +118,22 @@ if (!map) { map = L.map(mapEl, { worldCopyJump: true, zoomControl: true }).setView([44.5, -95], 4); - // Colorful CARTO "Voyager" basemap (no key needed) instead of the plain gray - // OSM raster — used in both themes for its richer road/land/water colors. - // Requesting tiles one zoom level lower and rendering them at 512px - // (tileSize 512 + zoomOffset -1) makes roads and city labels noticeably - // larger; @2x keeps them crisp while enlarged. A saturation boost (style.css) - // pushes the colors further. - L.tileLayer("https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}@2x.png", { + // Colorful CARTO "Voyager" basemap (no key needed), split into two raster + // layers so road weight and label size can be tuned independently: + // • the label-free base is requested one zoom lower and drawn at 512px + // (tileSize 512 + zoomOffset -1) so roads read bold and prominent; + // • the labels-only layer is drawn on top at its natural size, keeping city + // names small and crisp rather than scaled up with the roads. + // @2x keeps both sharp; a darken/saturate filter (style.css, .mp-base only) + // deepens the roads while leaving the label text at full contrast. + const CARTO = "https://{s}.basemaps.cartocdn.com/rastertiles"; + const ATTRIB = '© OpenStreetMap © CARTO'; + L.tileLayer(`${CARTO}/voyager_nolabels/{z}/{x}/{y}@2x.png`, { subdomains: "abcd", maxZoom: 20, tileSize: 512, zoomOffset: -1, - attribution: '© OpenStreetMap © CARTO', + className: "mp-base", attribution: ATTRIB, + }).addTo(map); + L.tileLayer(`${CARTO}/voyager_only_labels/{z}/{x}/{y}@2x.png`, { + subdomains: "abcd", maxZoom: 20, className: "mp-labels", }).addTo(map); // Branded accent teardrop pin (the same glyph the Find button uses), styled // in style.css — replaces Leaflet's default blue raster marker. diff --git a/static/style.css b/static/style.css index 09e3018..a81d4a6 100644 --- a/static/style.css +++ b/static/style.css @@ -706,8 +706,9 @@ main { max-width: 1200px; margin: 0 auto; padding: 20px 24px 60px; } box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .25), 0 6px 18px rgba(0, 0, 0, .25); } .mp-map .leaflet-container { background: var(--surface-2); } -/* Push the CARTO Voyager colors further — bolder roads, greener parks, bluer water. */ -.mp-map .leaflet-tile-pane { filter: saturate(1.35) contrast(1.05); } +/* Base map only (roads/land/water): deepen the roads and push saturation. The + labels layer (.mp-labels) is left unfiltered so city names keep full contrast. */ +.mp-map .mp-base { filter: saturate(1.3) contrast(1.12) brightness(0.92); } /* Branded accent teardrop pin (an L.divIcon wrapping the Find-button glyph), replacing Leaflet's default blue raster marker. */ .mp-pin { background: none; border: none; filter: drop-shadow(0 3px 4px rgba(0, 0, 0, .45)); }