Picker map: smaller labels, darker roads; location label coords→place (#27)

* 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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B3Q2EkHHnTUX2BfhV5q1Zc

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Emi Griffith 2026-07-11 01:35:43 -07:00 committed by GitHub
parent 20a4108397
commit 052b0a3e26
6 changed files with 40 additions and 13 deletions

View file

@ -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();
}

View file

@ -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();
}

View file

@ -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 `<li class="${cls}"><span class="cmp-chip-name">${label}</span>` +
`<button type="button" class="cmp-chip-x" data-i="${i}" aria-label="Remove ${label}">&times;</button></li>`;

View file

@ -75,7 +75,14 @@ const findBtn = document.getElementById("find-btn");
const locLabel = document.getElementById("loc-label");
findBtn.innerHTML = `${window.LocationPicker.PIN_ICON} <span>Find a location</span>`;
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 ----

View file

@ -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 = '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> &copy; <a href="https://carto.com/attributions">CARTO</a>';
L.tileLayer(`${CARTO}/voyager_nolabels/{z}/{x}/{y}@2x.png`, {
subdomains: "abcd", maxZoom: 20, tileSize: 512, zoomOffset: -1,
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> &copy; <a href="https://carto.com/attributions">CARTO</a>',
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.

View file

@ -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)); }