diff --git a/TODO.adoc b/TODO.adoc index a13c552..e5efb45 100644 --- a/TODO.adoc +++ b/TODO.adoc @@ -26,7 +26,7 @@ independence from connectivity. * [ ] Custom vector style (MVT/MapLibre) using the NPS color palette — muted natural tones for forests, water, and contours — so POIs and routes stand out at high zoom ** [ ] Landuse & protections: distinct styling for national parks, nature reserves (translucent green/gray-green), military zones, and private land (important for wild camping) ** [ ] Elevation-tinted terrain combined with offline hillshade for a characteristic relief look -** [ ] Road hierarchy: clearly distinguish paved roads from unpaved/gravel/track — critical for knowing if the camper can get there +** [x] Road hierarchy: clearly distinguish paved roads from unpaved/gravel/track — critical for knowing if the camper can get there == Main menu reorganization (4 modules) diff --git a/public/js/map.js b/public/js/map.js index 3db20c0..d5a4a1d 100644 --- a/public/js/map.js +++ b/public/js/map.js @@ -104,6 +104,32 @@ function patchOnlineStyle(style) { const patch = ONLINE_STYLE_PATCH[layer.id]; if (patch) Object.assign((layer.paint ??= {}), patch); } + return insertTrackOnlyLayer(style); +} + +// Liberty's own "road_service_track" layer paints service roads (paved +// driveways/parking aisles) and actual unpaved tracks the same color — +// fine for a general-purpose map, not for this app's "can the camper get +// there" use case. The underlying OpenMapTiles data does carry `class: +// "track"` separately from `"service"` (see the filter below), so rather +// than recoloring the merged layer (which would mislabel paved driveways +// as unpaved), this clones it into a second layer scoped to `class == +// "track"` only, dashed and dirt-brown — matching how the offline theme +// already renders protomaps' own separate "other"/"path" road kind. +// Surface-level only (excludes tunnel_/bridge_ variants): an unpaved track +// in a tunnel or on a bridge is rare enough not to be worth a third layer. +function insertTrackOnlyLayer(style) { + const index = style.layers.findIndex((layer) => layer.id === "road_service_track"); + if (index === -1) return style; + + const base = style.layers[index]; + const trackOnly = { + ...base, + id: "road_track_only", + filter: ["all", base.filter, ["==", ["get", "class"], "track"]], + paint: { ...base.paint, "line-color": "#c9a66b", "line-dasharray": [2, 2] }, + }; + style.layers.splice(index + 1, 0, trackOnly); return style; } @@ -181,8 +207,21 @@ const OFFLINE_THEME = { pedestrian: "#e9e2d8", highway: "#fdefbe", // real: Park Tiles' primary/highway road color major: "#fef7dd", // real: Park Tiles' secondary road color - minor: "#fffdf8", + // "minor" (singular) is never actually read by protomaps' own paint + // expressions — only the zoom-interpolated minor_a/minor_b pair is, so a + // plain "minor" key here was dead: ordinary streets were silently + // falling back to the base theme's default pale yellow instead of this + // app's cream. + minor_a: "#fffdf8", + minor_b: "#fffdf8", link: "#fef7dd", + // Distinct brown, not cream: protomaps' "other"/"path" kind is what a + // camper actually needs called out — unpaved tracks and footpaths, + // separate from paved minor_road/service (minor_service, left at the + // base theme's default since it's real driveways/parking aisles, not + // unpaved). Already rendered dashed by the theme itself; this just picks + // a real "dirt" tone instead of unstyled white. + other: "#c9a66b", boundaries: "#546619", // real: Park Tiles' park-boundary line color };