Apply the NPS-inspired palette to the online map too
ONLINE_STYLE_PATCH mirrors OFFLINE_THEME's color choices onto OpenFreeMap Liberty's OpenMapTiles layer ids (a separate hand-built table -- the two schemas share no layer names). loadOnlineStyle fetches Liberty's style.json once, patches it in place, and the result replaces the plain URL everywhere ONLINE_STYLE is used -- MapLibre accepts a style object anywhere it accepts a style URL, so applyStyle needed no change. Runs before the map (and the rest of the page) is constructed, so there's no flash of Liberty's own colors first -- but with a 3s timeout and a catch-all fallback to the plain URL, since this app is meant to keep working offline in the field and blocking startup on a remote style server would undermine that. Verified in a real browser: online map now visually matches the offline theme (cream ground, brown/khaki land cover, green parks, muted roads), no console errors, Online/Offline toggle still works.
This commit is contained in:
1 parent
24b6180c03
commit
ceaaa0bb92
3 files changed
+134
-3
No files matched your search
+107
-1
@@ -19,7 +19,113 @@ import * as maplibregl from "/vendor/maplibre-gl/maplibre-gl.mjs";
|
||||
|
||||
const CENTER = [17.1077, 48.1486];
|
||||
const ZOOM = 13;
|
||||
const ONLINE_STYLE = "https://tiles.openfreemap.org/styles/liberty";
|
||||
const ONLINE_STYLE_URL = "https://tiles.openfreemap.org/styles/liberty";
|
||||
|
||||
// Recolors OpenFreeMap Liberty to the same NPS-inspired palette as
|
||||
// OFFLINE_THEME below — warm cream ground, brown/khaki land cover, green
|
||||
// reserved for parks, muted roads/boundaries — mapped onto Liberty's
|
||||
// OpenMapTiles layer ids instead of protomaps' theme roles (the two
|
||||
// schemas don't share layer names, so this is a separate hand-built
|
||||
// table, not a shared object). Only the layers that dominate the map's
|
||||
// overall color read are touched; labels, halos, rail, and minor
|
||||
// overlays (cemetery/hospital/school/pitch/track shading, building
|
||||
// outlines) are left at Liberty's own defaults — same "not a full
|
||||
// recolor" scope as OFFLINE_THEME. Road casings have no protomaps-role
|
||||
// equivalent to reuse (offline roads don't get a separate outline), so
|
||||
// #c9a66b there is reasoned to fit the family rather than sourced from
|
||||
// anywhere real.
|
||||
const ONLINE_STYLE_PATCH = {
|
||||
background: { "background-color": "#f9f6ef" },
|
||||
landcover_wood: { "fill-color": "#c9bd9c" },
|
||||
landcover_grass: { "fill-color": "#d9cfb0" },
|
||||
landcover_sand: { "fill-color": "#f0e4c4" },
|
||||
water: { "fill-color": "#a3cedf" },
|
||||
park: { "fill-color": "#b3e378" },
|
||||
park_outline: { "line-color": "#546619" },
|
||||
building: { "fill-color": "#ded7cc" },
|
||||
boundary_2: { "line-color": "#546619" },
|
||||
boundary_3: { "line-color": "#546619" },
|
||||
|
||||
// Highway (motorway/trunk/primary), major (secondary/tertiary/link),
|
||||
// minor (residential/service/track), pedestrian — each repeated for its
|
||||
// tunnel_/bridge_ counterpart so a road doesn't change color when it
|
||||
// dips into a tunnel or crosses a bridge. Rail is left alone.
|
||||
road_motorway: { "line-color": "#fdefbe" },
|
||||
road_trunk_primary: { "line-color": "#fdefbe" },
|
||||
road_secondary_tertiary: { "line-color": "#fef7dd" },
|
||||
road_link: { "line-color": "#fef7dd" },
|
||||
road_motorway_link: { "line-color": "#fef7dd" },
|
||||
road_minor: { "line-color": "#fffdf8" },
|
||||
road_service_track: { "line-color": "#fffdf8" },
|
||||
road_path_pedestrian: { "line-color": "#e9e2d8" },
|
||||
road_motorway_casing: { "line-color": "#c9a66b" },
|
||||
road_trunk_primary_casing: { "line-color": "#c9a66b" },
|
||||
road_secondary_tertiary_casing: { "line-color": "#c9a66b" },
|
||||
road_link_casing: { "line-color": "#c9a66b" },
|
||||
road_motorway_link_casing: { "line-color": "#c9a66b" },
|
||||
road_minor_casing: { "line-color": "#c9a66b" },
|
||||
road_service_track_casing: { "line-color": "#c9a66b" },
|
||||
|
||||
tunnel_motorway: { "line-color": "#fdefbe" },
|
||||
tunnel_trunk_primary: { "line-color": "#fdefbe" },
|
||||
tunnel_secondary_tertiary: { "line-color": "#fef7dd" },
|
||||
tunnel_link: { "line-color": "#fef7dd" },
|
||||
tunnel_motorway_link: { "line-color": "#fef7dd" },
|
||||
tunnel_minor: { "line-color": "#fffdf8" },
|
||||
tunnel_service_track: { "line-color": "#fffdf8" },
|
||||
tunnel_path_pedestrian: { "line-color": "#e9e2d8" },
|
||||
tunnel_motorway_casing: { "line-color": "#c9a66b" },
|
||||
tunnel_trunk_primary_casing: { "line-color": "#c9a66b" },
|
||||
tunnel_secondary_tertiary_casing: { "line-color": "#c9a66b" },
|
||||
tunnel_link_casing: { "line-color": "#c9a66b" },
|
||||
tunnel_motorway_link_casing: { "line-color": "#c9a66b" },
|
||||
tunnel_street_casing: { "line-color": "#c9a66b" },
|
||||
|
||||
bridge_motorway: { "line-color": "#fdefbe" },
|
||||
bridge_trunk_primary: { "line-color": "#fdefbe" },
|
||||
bridge_secondary_tertiary: { "line-color": "#fef7dd" },
|
||||
bridge_link: { "line-color": "#fef7dd" },
|
||||
bridge_motorway_link: { "line-color": "#fef7dd" },
|
||||
bridge_street: { "line-color": "#fffdf8" },
|
||||
bridge_service_track: { "line-color": "#fffdf8" },
|
||||
bridge_path_pedestrian: { "line-color": "#e9e2d8" },
|
||||
bridge_motorway_casing: { "line-color": "#c9a66b" },
|
||||
bridge_trunk_primary_casing: { "line-color": "#c9a66b" },
|
||||
bridge_secondary_tertiary_casing: { "line-color": "#c9a66b" },
|
||||
bridge_link_casing: { "line-color": "#c9a66b" },
|
||||
bridge_motorway_link_casing: { "line-color": "#c9a66b" },
|
||||
bridge_street_casing: { "line-color": "#c9a66b" },
|
||||
bridge_path_pedestrian_casing: { "line-color": "#c9a66b" },
|
||||
};
|
||||
|
||||
function patchOnlineStyle(style) {
|
||||
for (const layer of style.layers) {
|
||||
const patch = ONLINE_STYLE_PATCH[layer.id];
|
||||
if (patch) Object.assign((layer.paint ??= {}), patch);
|
||||
}
|
||||
return style;
|
||||
}
|
||||
|
||||
// Fetched (not just referenced by URL) so its colors can be patched before
|
||||
// the map ever sees it — MapLibre accepts a style object anywhere it'd
|
||||
// accept a style URL, so every other use of ONLINE_STYLE (applyStyle's
|
||||
// map.setStyle) needs no change. This runs before the map — and the rest
|
||||
// of the page's setup — is constructed (see the top-level await below), so
|
||||
// it falls back to the plain URL, letting MapLibre fetch and render it
|
||||
// unpatched, both when the fetch fails outright and when it's just slow
|
||||
// (a 3s timeout): this app is meant to work offline in the field, and
|
||||
// blocking the entire page on a remote style server would undermine that
|
||||
// even though this particular fetch is only for the online map.
|
||||
async function loadOnlineStyle() {
|
||||
try {
|
||||
const response = await fetch(ONLINE_STYLE_URL, { signal: AbortSignal.timeout(3000) });
|
||||
return patchOnlineStyle(await response.json());
|
||||
} catch (err) {
|
||||
return ONLINE_STYLE_URL;
|
||||
}
|
||||
}
|
||||
|
||||
const ONLINE_STYLE = await loadOnlineStyle();
|
||||
|
||||
const protocol = new pmtiles.Protocol();
|
||||
addProtocol("pmtiles", protocol.tile);
|
||||
|
||||
Reference in new issue
Block a user