Gospel x Internet uses the library's whiteboard map instead of its own copy
boardEngine.js was createWhiteboardMap under another name: the bodies are identical line for line, and every import it made already came from library. It is deleted and the four components import @map/maps/whiteboard-map.js. The copies were NOT interchangeable, which is the part worth recording. Their DEFAULTS are opposites, because the library file was extracted for the whiteboard case and boardEngine served both map kinds: boardEngine whiteboard:false boundaries:true centre [60,20] zoom 1.4 library whiteboard:true boundaries:false centre [0,0] zoom 1 Three of the four callers pass all four options explicitly, so they were never at risk. GiMap — the geographic map — passed only a token and took every default. Swapping its import alone would have set whiteboard:true, hiding every basemap layer, dropping boundary attribution and moving the camera: a blank map in production, from a change that reads like pure de-duplication. So GiMap now states its four options. Every effective option is unchanged from today's values, verified field by field, and the call reads the same against either module.
This commit is contained in:
parent
5095d798b8
commit
c00b0b4b5d
5 changed files with 21 additions and 79 deletions
|
|
@ -1,67 +0,0 @@
|
|||
/**
|
||||
* boardEngine.js — build one map on whichever engine the embed asked for, the way this board builds all
|
||||
* of its maps: engine from resolveMapProvider, script + CSS ensured, RTL shaping installed before `new
|
||||
* Map`, the style from the registry ('paper' = Mapbox light / OpenFreeMap positron), labels in the
|
||||
* reader's language, attribution added. Used by the geographic map AND the language-tree whiteboard, so
|
||||
* the two can never drift apart on an engine detail.
|
||||
*
|
||||
* whiteboard:true hides every basemap layer except the background once the style loads. The style is
|
||||
* still loaded because it is what declares the GLYPH server: a hand-typed glyph URL is how labels
|
||||
* silently vanished on one engine before (library/maps/label-font.js).
|
||||
*/
|
||||
import { resolveMapProvider } from '@map/composables/useMapProvider.js'
|
||||
import { ensureEngineScript, engineGlobal, ensureEngineCSS, engineStylesheetUrl, engineUiLocale } from '@map/composables/useMapInstance.js'
|
||||
import { resolveNamedStyle } from '@map/styles/registry.js'
|
||||
import { installRtlTextPlugin } from '@map/maps/rtl-text.js'
|
||||
import { localizeBasemapLabels } from '@map/maps/localize-labels.js'
|
||||
import { addMapAttribution } from '@map/composables/useMapAttribution'
|
||||
|
||||
export function readerLang(profileConfig) {
|
||||
const pc = profileConfig || {}
|
||||
if (pc.locale || pc.lang) return String(pc.locale || pc.lang)
|
||||
try { return new URLSearchParams(location.search).get('lang') || document.documentElement.lang || 'en' } catch { return 'en' }
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Promise<{ map, provider } | { error: string, provider }>} resolves once the style has loaded
|
||||
*/
|
||||
export async function createBoardMap(el, profileConfig, { center = [60, 20], zoom = 1.4, whiteboard = false, boundaries = true, background = '#f3f3f1', token = '' } = {}) {
|
||||
const provider = resolveMapProvider(profileConfig)
|
||||
try { await ensureEngineScript(provider) } catch (_) { /* reported below */ }
|
||||
const gl = engineGlobal(provider)
|
||||
if (!gl) return { provider, error: provider === 'maplibre' ? 'MapLibre' : 'Mapbox' }
|
||||
installRtlTextPlugin(gl)
|
||||
const css = engineStylesheetUrl(provider)
|
||||
if (css) await ensureEngineCSS(el, css)
|
||||
const lang = readerLang(profileConfig)
|
||||
// The host's token by the same ladder the production maps use: profile-config tk, then the token
|
||||
// ProfileLoader provides (a tokenUrl token-service answer, or the page's shared token), then the page global.
|
||||
const tk = profileConfig?.tk || token || (typeof window !== 'undefined' && window.MAP_TOKEN) || ''
|
||||
const map = new gl.Map({
|
||||
container: el,
|
||||
style: resolveNamedStyle('paper', provider).style || 'mapbox://styles/mapbox/light-v11',
|
||||
accessToken: tk,
|
||||
locale: engineUiLocale(lang, provider),
|
||||
center, zoom, projection: 'mercator', attributionControl: false,
|
||||
// a whiteboard is not a world: no wrap-around copies of the tapestry at low zoom
|
||||
renderWorldCopies: !whiteboard,
|
||||
})
|
||||
addMapAttribution(map, { boundaries, basemap: !whiteboard })
|
||||
await new Promise((res) => map.once('load', res))
|
||||
if (whiteboard) {
|
||||
for (const l of map.getStyle().layers || []) {
|
||||
try {
|
||||
if (l.type === 'background') map.setPaintProperty(l.id, 'background-color', background)
|
||||
else map.setLayoutProperty(l.id, 'visibility', 'none')
|
||||
} catch (_) { /* a layer the engine will not touch is left as it is */ }
|
||||
}
|
||||
} else {
|
||||
try { localizeBasemapLabels(map, lang) } catch (_) { /* a nicety, never a broken map */ }
|
||||
}
|
||||
return { map, provider }
|
||||
}
|
||||
|
||||
/** Reduced motion, read LIVE (never cached): under it every camera change is a jump. */
|
||||
export function reducedMotion() {
|
||||
try { return window.matchMedia('(prefers-reduced-motion: reduce)').matches } catch (_) { return false }
|
||||
}
|
||||
|
|
@ -22,7 +22,7 @@ import { useShadowStyles } from '@map/composables/useShadowStyles.js'
|
|||
import { labelFont } from '@map/maps/label-font.js'
|
||||
import { whiteboardProjection } from '@map/maps/whiteboard-projection.js'
|
||||
import { addTieredPointLayers } from '@map/charts/whiteboard/tiered-points.js'
|
||||
import { createBoardMap, reducedMotion } from '../boardEngine.js'
|
||||
import { createWhiteboardMap, reducedMotion } from '@map/maps/whiteboard-map.js'
|
||||
import { useBoardState } from '../useBoard.js'
|
||||
import { useGiT } from '../useGiT.js'
|
||||
import { layoutBoundedSet } from '@map/components/charts/boundedSet.js'
|
||||
|
|
@ -83,11 +83,11 @@ function openAndFrame(slug, feature) {
|
|||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
const made = await createBoardMap(el.value, board.profileConfig?.value || {},
|
||||
const made = await createWhiteboardMap(el.value, board.profileConfig?.value || {},
|
||||
{ whiteboard: true, boundaries: false, center: [0, 0], zoom: 1 })
|
||||
const map = markRaw(made.map || made)
|
||||
mapRef.value = map
|
||||
// ★ createBoardMap ALREADY AWAITS LOAD. boardEngine resolves only after
|
||||
// ★ createWhiteboardMap ALREADY AWAITS LOAD. The library helper resolves only after
|
||||
// `await new Promise(res => map.once('load', res))`, so by the time this runs the event has
|
||||
// fired and will not fire again — a second `map.on('load', …)` never runs and the layers are
|
||||
// never added. The chart then draws a basemap-less whiteboard with no source on it: empty,
|
||||
|
|
@ -141,7 +141,7 @@ onMounted(async () => {
|
|||
} catch (_) { /* no ResizeObserver: the initial fit stands */ }
|
||||
}
|
||||
// ★ CALLED UNCONDITIONALLY, AND THE GUARD THAT USED TO BE HERE IS WHY THIS WAS BROKEN TWICE.
|
||||
// createBoardMap only resolves after `await map.once('load')`, so by here the event HAS fired.
|
||||
// createWhiteboardMap only resolves after `await map.once('load')`, so by here the event HAS fired.
|
||||
// The previous line read `map.loaded() ? setup() : map.once('load', setup)` — but loaded()
|
||||
// does not mean "the load event fired", it means "the style AND every tile are loaded", and
|
||||
// the basemap tiles were still arriving. So it returned false, took the else branch, and
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import { useShadowStyles } from '@map/composables/useShadowStyles.js'
|
|||
import { labelFont } from '@map/maps/label-font.js'
|
||||
import { whiteboardProjection } from '@map/maps/whiteboard-projection.js'
|
||||
import { addTieredPointLayers } from '@map/charts/whiteboard/tiered-points.js'
|
||||
import { createBoardMap, reducedMotion } from '../boardEngine.js'
|
||||
import { createWhiteboardMap, reducedMotion } from '@map/maps/whiteboard-map.js'
|
||||
import { useBoardState } from '../useBoard.js'
|
||||
import { useGiT } from '../useGiT.js'
|
||||
import { ringInfo, CENTRE_COLOR } from '../ringInfo.js'
|
||||
|
|
@ -147,11 +147,11 @@ function openAndFrame(slug, feature) {
|
|||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
const made = await createBoardMap(el.value, board.profileConfig?.value || {},
|
||||
const made = await createWhiteboardMap(el.value, board.profileConfig?.value || {},
|
||||
{ whiteboard: true, boundaries: false, center: [0, 0], zoom: 1 })
|
||||
const map = markRaw(made.map || made)
|
||||
mapRef.value = map
|
||||
// ★ createBoardMap ALREADY AWAITS LOAD. boardEngine resolves only after
|
||||
// ★ createWhiteboardMap ALREADY AWAITS LOAD. The library helper resolves only after
|
||||
// `await new Promise(res => map.once('load', res))`, so by the time this runs the event has
|
||||
// fired and will not fire again — a second `map.on('load', …)` never runs and the layers are
|
||||
// never added. The chart then draws a basemap-less whiteboard with no source on it: empty,
|
||||
|
|
@ -209,7 +209,7 @@ onMounted(async () => {
|
|||
ready.value = true
|
||||
}
|
||||
// ★ CALLED UNCONDITIONALLY, AND THE GUARD THAT USED TO BE HERE IS WHY THIS WAS BROKEN TWICE.
|
||||
// createBoardMap only resolves after `await map.once('load')`, so by here the event HAS fired.
|
||||
// createWhiteboardMap only resolves after `await map.once('load')`, so by here the event HAS fired.
|
||||
// The previous line read `map.loaded() ? setup() : map.once('load', setup)` — but loaded()
|
||||
// does not mean "the load event fired", it means "the style AND every tile are loaded", and
|
||||
// the basemap tiles were still arriving. So it returned false, took the else branch, and
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ import ShareButton from '@map/components/map-controls/ShareButton.vue'
|
|||
import HelpButton from '@map/components/map-controls/HelpButton.vue'
|
||||
import { useBoardState, EMBED_PATH } from '../useBoard.js'
|
||||
import { useGiT } from '../useGiT.js'
|
||||
import { createBoardMap, reducedMotion } from '../boardEngine.js'
|
||||
import { createWhiteboardMap, reducedMotion } from '@map/maps/whiteboard-map.js'
|
||||
import { ACCESS_DETAILS, BANDS, DETAIL_FILL, DETAIL_RIM, BAND_COLOR, label } from '../model.js'
|
||||
|
||||
const T = useGiT()
|
||||
|
|
@ -285,7 +285,16 @@ onMounted(async () => {
|
|||
}).catch(() => { adm1Table = null })
|
||||
try {
|
||||
if (!mapEl.value) return
|
||||
const made = await createBoardMap(mapEl.value, board.profileConfig.value, { token: injectedToken?.value || '' })
|
||||
// ★ THE FOUR OPTIONS ARE STATED, NEVER DEFAULTED. This is the ONE geographic caller — the three
|
||||
// whiteboard callers all pass whiteboard:true — and the library's defaults are the inverse of what
|
||||
// a real map needs (whiteboard:true, boundaries:false, centre [0,0], zoom 1), because it was
|
||||
// extracted for the whiteboard case. Leaning on defaults here meant a blank basemap and no
|
||||
// boundary attribution the moment the import moved. Stating them makes this call read the same
|
||||
// against either module.
|
||||
const made = await createWhiteboardMap(mapEl.value, board.profileConfig.value, {
|
||||
whiteboard: false, boundaries: true, center: [60, 20], zoom: 1.4,
|
||||
token: injectedToken?.value || '',
|
||||
})
|
||||
if (made.error) { err.value = T('messages.engineMissing', `The ${made.error} map engine did not load.`, { engine: made.error }); return }
|
||||
const map = made.map
|
||||
if (unmounted) { try { map.remove() } catch (_) {} return }
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ import ZoomOutButton from '@map/components/map-controls/ZoomOutButton.vue'
|
|||
import HelpButton from '@map/components/map-controls/HelpButton.vue'
|
||||
import { useBoardState } from '../useBoard.js'
|
||||
import { useGiT } from '../useGiT.js'
|
||||
import { createBoardMap, reducedMotion } from '../boardEngine.js'
|
||||
import { createWhiteboardMap, reducedMotion } from '@map/maps/whiteboard-map.js'
|
||||
import { treeScope, TREE_COLOR } from '../model.js'
|
||||
import { buildTreePoster, posterPrintHtml } from '../treePoster.js'
|
||||
import { openPrintFrame } from '@map/composables/printInPlace.js'
|
||||
|
|
@ -225,7 +225,7 @@ function frame(coords) {
|
|||
async function build() {
|
||||
const t = await board.loadTree()
|
||||
if (unmounted || !el.value || mapRef.value) return
|
||||
const made = await createBoardMap(el.value, board.profileConfig.value, { whiteboard: true, boundaries: false, center: [0, 0], zoom: 1, token: injectedToken?.value || '' })
|
||||
const made = await createWhiteboardMap(el.value, board.profileConfig.value, { whiteboard: true, boundaries: false, center: [0, 0], zoom: 1, token: injectedToken?.value || '' })
|
||||
if (made.error) { err.value = T('messages.engineMissing', `The ${made.error} map engine did not load.`, { engine: made.error }); return }
|
||||
if (unmounted) { try { made.map.remove() } catch (_) {} return }
|
||||
const map = made.map
|
||||
|
|
|
|||
Loading…
Reference in a new issue