Merge branch 'main' of https://git.nuxtbase.app/doxa-life/doxa-maps into bundler-1/work
This commit is contained in:
commit
b0cd3140bd
11 changed files with 70 additions and 35 deletions
|
|
@ -63,6 +63,29 @@ export function ensureGeocoder(provider = 'mapbox') {
|
||||||
// `new mapboxgl.Popup` throws on the first pin click. Now the library's engineFor (one copy).
|
// `new mapboxgl.Popup` throws on the first pin click. Now the library's engineFor (one copy).
|
||||||
export { engineFor as glFor } from '@map/composables/useMapProvider.js'
|
export { engineFor as glFor } from '@map/composables/useMapProvider.js'
|
||||||
|
|
||||||
|
// Resolves once every GeoJSON source on the map has LOADED and a frame has RENDERED after that,
|
||||||
|
// or after `timeoutMs` (a safety net, never a hang). The views flipped `dataReady` (which hides the
|
||||||
|
// LoadingGlobe) right after addSource(); the engine then still tiles tens of thousands of points in
|
||||||
|
// its worker, so the globe disappeared and the map sat EMPTY. Measured on the DX-life gallery: 0
|
||||||
|
// dots for 20 s, then 19,376 features from 30 s. Not 'idle': an animating map may never go idle.
|
||||||
|
export function whenGeojsonDrawn(map, timeoutMs = 45000) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
if (!map) return resolve(false)
|
||||||
|
let done = false
|
||||||
|
const finish = (drawn) => { if (done) return; done = true; clearTimeout(timer); map.off('sourcedata', check); resolve(drawn) }
|
||||||
|
const timer = setTimeout(() => finish(false), timeoutMs)
|
||||||
|
const check = () => {
|
||||||
|
try {
|
||||||
|
const srcs = (map.getStyle() || {}).sources || {}
|
||||||
|
const ids = Object.keys(srcs).filter((k) => srcs[k].type === 'geojson')
|
||||||
|
if (ids.every((id) => map.isSourceLoaded(id))) { map.once('render', () => finish(true)); map.triggerRepaint() }
|
||||||
|
} catch (_) { /* style mid-swap: wait for the next sourcedata */ }
|
||||||
|
}
|
||||||
|
map.on('sourcedata', check)
|
||||||
|
check()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// Verification handle (the gospel-resources __grState contract): what the ACTIVE view's map
|
// Verification handle (the gospel-resources __grState contract): what the ACTIVE view's map
|
||||||
// actually did, so a check can assert "loaded" rather than inferring it from missing requests.
|
// actually did, so a check can assert "loaded" rather than inferring it from missing requests.
|
||||||
// window.__pplrMap() -> { engine, loaded, styleLayers, pplrLayers }
|
// window.__pplrMap() -> { engine, loaded, styleLayers, pplrLayers }
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { dataUrl, glFor, exposeMap } from '../utils/pplrData.js'
|
import { dataUrl, glFor, exposeMap, whenGeojsonDrawn } from '../utils/pplrData.js'
|
||||||
/**
|
/**
|
||||||
* pplr-coverage.vue — Country choropleth: avg # of locales filled per PG in that country.
|
* pplr-coverage.vue — Country choropleth: avg # of locales filled per PG in that country.
|
||||||
*
|
*
|
||||||
|
|
@ -118,6 +118,8 @@ onMounted(async () => {
|
||||||
.setLngLat(f.geometry.coordinates).setHTML(popupForPG(f.properties)).addTo(map.value)
|
.setLngLat(f.geometry.coordinates).setHTML(popupForPG(f.properties)).addTo(map.value)
|
||||||
})
|
})
|
||||||
status.value = `Ready · ${countryStats.size} countries colored by avg translation locales / 17 (all ${[...countryStats.values()].reduce((n, c) => n + c.pgCount, 0).toLocaleString('en-US')} PG-in-country rows)`
|
status.value = `Ready · ${countryStats.size} countries colored by avg translation locales / 17 (all ${[...countryStats.values()].reduce((n, c) => n + c.pgCount, 0).toLocaleString('en-US')} PG-in-country rows)`
|
||||||
|
// keep the LoadingGlobe up until the pins are actually drawn, not merely added
|
||||||
|
await whenGeojsonDrawn(map.value)
|
||||||
dataReady.value = true
|
dataReady.value = true
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
status.value = `Error: ${e.message}`
|
status.value = `Error: ${e.message}`
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { dataUrl, glFor, exposeMap } from '../utils/pplrData.js'
|
import { dataUrl, glFor, exposeMap, whenGeojsonDrawn } from '../utils/pplrData.js'
|
||||||
/**
|
/**
|
||||||
* pplr-language-families.vue — PG pins colored by PPLR ethnolinguistic family.
|
* pplr-language-families.vue — PG pins colored by PPLR ethnolinguistic family.
|
||||||
*
|
*
|
||||||
|
|
@ -490,6 +490,8 @@ onMounted(async () => {
|
||||||
|
|
||||||
const coverage = Math.round(100 * matched / fc.features.length)
|
const coverage = Math.round(100 * matched / fc.features.length)
|
||||||
status.value = `Ready · ${fc.features.length.toLocaleString()} pins · ${coverage}% family coverage · top-25 = ${Math.round(100 * inTop25 / fc.features.length)}%`
|
status.value = `Ready · ${fc.features.length.toLocaleString()} pins · ${coverage}% family coverage · top-25 = ${Math.round(100 * inTop25 / fc.features.length)}%`
|
||||||
|
// keep the LoadingGlobe up until the pins are actually drawn, not merely added
|
||||||
|
await whenGeojsonDrawn(map.value)
|
||||||
dataReady.value = true
|
dataReady.value = true
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
status.value = `Error: ${err.message}`
|
status.value = `Error: ${err.message}`
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
* Individual pins at all zoom levels; click pin for full Rosetta popup; hover country for highlight.
|
* Individual pins at all zoom levels; click pin for full Rosetta popup; hover country for highlight.
|
||||||
*/
|
*/
|
||||||
import { inject, onMounted, onBeforeUnmount, ref } from 'vue'
|
import { inject, onMounted, onBeforeUnmount, ref } from 'vue'
|
||||||
import { glFor, exposeMap } from '../utils/pplrData.js'
|
import { glFor, exposeMap, whenGeojsonDrawn } from '../utils/pplrData.js'
|
||||||
import { useMapInstance } from '@map/composables/useMapInstance.js'
|
import { useMapInstance } from '@map/composables/useMapInstance.js'
|
||||||
import { addCountryPolygons, addPGPoints, popupForPG, POPUP_CSS } from '../utils/pplrMap.js'
|
import { addCountryPolygons, addPGPoints, popupForPG, POPUP_CSS } from '../utils/pplrMap.js'
|
||||||
import LoadingGlobe from '../components/LoadingGlobe.vue'
|
import LoadingGlobe from '../components/LoadingGlobe.vue'
|
||||||
|
|
@ -50,6 +50,8 @@ onMounted(async () => {
|
||||||
.addTo(map.value)
|
.addTo(map.value)
|
||||||
})
|
})
|
||||||
status.value = `Ready · ${fc.features.length.toLocaleString('en-US')} PG-in-country pins · click any pin`
|
status.value = `Ready · ${fc.features.length.toLocaleString('en-US')} PG-in-country pins · click any pin`
|
||||||
|
// keep the LoadingGlobe up until the pins are actually drawn, not merely added
|
||||||
|
await whenGeojsonDrawn(map.value)
|
||||||
dataReady.value = true
|
dataReady.value = true
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
status.value = `Error: ${e.message}`
|
status.value = `Error: ${e.message}`
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { dataUrl, glFor, exposeMap } from '../utils/pplrData.js'
|
import { dataUrl, glFor, exposeMap, whenGeojsonDrawn } from '../utils/pplrData.js'
|
||||||
/**
|
/**
|
||||||
* pplr-religion.vue — PG pins colored by primary religion.
|
* pplr-religion.vue — PG pins colored by primary religion.
|
||||||
*
|
*
|
||||||
|
|
@ -267,6 +267,8 @@ onMounted(async () => {
|
||||||
const dominant = RELIGION_GROUPS.reduce((a, b) => (counts[a.key] || 0) > (counts[b.key] || 0) ? a : b)
|
const dominant = RELIGION_GROUPS.reduce((a, b) => (counts[a.key] || 0) > (counts[b.key] || 0) ? a : b)
|
||||||
// Per user 2026-05-02: drop the "Ready" prefix — it was unclear and chewed up width.
|
// Per user 2026-05-02: drop the "Ready" prefix — it was unclear and chewed up width.
|
||||||
status.value = `${pgData.value.features.length.toLocaleString()} pins · ${dominant.label} most common (${(counts[dominant.key]||0).toLocaleString()})`
|
status.value = `${pgData.value.features.length.toLocaleString()} pins · ${dominant.label} most common (${(counts[dominant.key]||0).toLocaleString()})`
|
||||||
|
// keep the LoadingGlobe up until the pins are actually drawn, not merely added
|
||||||
|
await whenGeojsonDrawn(map.value)
|
||||||
dataReady.value = true
|
dataReady.value = true
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
status.value = `Error: ${err.message}`
|
status.value = `Error: ${err.message}`
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
* Click any pin → popup with full Rosetta table.
|
* Click any pin → popup with full Rosetta table.
|
||||||
*/
|
*/
|
||||||
import { inject, onMounted, onBeforeUnmount, ref } from 'vue'
|
import { inject, onMounted, onBeforeUnmount, ref } from 'vue'
|
||||||
import { glFor, exposeMap } from '../utils/pplrData.js'
|
import { glFor, exposeMap, whenGeojsonDrawn } from '../utils/pplrData.js'
|
||||||
import { useMapInstance } from '@map/composables/useMapInstance.js'
|
import { useMapInstance } from '@map/composables/useMapInstance.js'
|
||||||
import { addCountryPolygons, loadOnce, popupForPG, POPUP_CSS } from '../utils/pplrMap.js'
|
import { addCountryPolygons, loadOnce, popupForPG, POPUP_CSS } from '../utils/pplrMap.js'
|
||||||
import LoadingGlobe from '../components/LoadingGlobe.vue'
|
import LoadingGlobe from '../components/LoadingGlobe.vue'
|
||||||
|
|
@ -141,6 +141,8 @@ onMounted(async () => {
|
||||||
map.value.on('mouseleave', 'rosetta-pin', () => map.value.getCanvas().style.cursor = '')
|
map.value.on('mouseleave', 'rosetta-pin', () => map.value.getCanvas().style.cursor = '')
|
||||||
|
|
||||||
status.value = `Ready · ${pgFc.features.length} pins · ${rosKeys.size} Rosetta samples (gold ★)`
|
status.value = `Ready · ${pgFc.features.length} pins · ${rosKeys.size} Rosetta samples (gold ★)`
|
||||||
|
// keep the LoadingGlobe up until the pins are actually drawn, not merely added
|
||||||
|
await whenGeojsonDrawn(map.value)
|
||||||
dataReady.value = true
|
dataReady.value = true
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
status.value = `Error: ${e.message}`
|
status.value = `Error: ${e.message}`
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { dataUrl, glFor, exposeMap } from '../utils/pplrData.js'
|
import { dataUrl, glFor, exposeMap, whenGeojsonDrawn } from '../utils/pplrData.js'
|
||||||
/**
|
/**
|
||||||
* pplr-translations.vue — PG name in all 17 locales.
|
* pplr-translations.vue — PG name in all 17 locales.
|
||||||
*
|
*
|
||||||
|
|
@ -92,6 +92,8 @@ onMounted(async () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
status.value = `${fc.features.length.toLocaleString()} pins · click any pin to see all 17 locale names`
|
status.value = `${fc.features.length.toLocaleString()} pins · click any pin to see all 17 locale names`
|
||||||
|
// keep the LoadingGlobe up until the pins are actually drawn, not merely added
|
||||||
|
await whenGeojsonDrawn(map.value)
|
||||||
dataReady.value = true
|
dataReady.value = true
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
status.value = `Error: ${err.message}`
|
status.value = `Error: ${err.message}`
|
||||||
|
|
|
||||||
|
|
@ -837,7 +837,7 @@
|
||||||
"bundle": "pplr-data-maps",
|
"bundle": "pplr-data-maps",
|
||||||
"scriptUrl": "./pplr-data-maps/pplr-data-maps.js",
|
"scriptUrl": "./pplr-data-maps/pplr-data-maps.js",
|
||||||
"output": "dx-maps/pplr-data-maps/pplr-data-maps.js",
|
"output": "dx-maps/pplr-data-maps/pplr-data-maps.js",
|
||||||
"integrity": "sha384-nMEYoH17y92xbERsRYP3x9sroR//lz8NvipOQvUfV8zV40pJ7DmW0avOm7sARD82",
|
"integrity": "sha384-e6wVt+dC86mFb8TgX2jBn7wh/R9gA6rGxNgS6umNBeNrir3TstupaJKf4XElRP2T",
|
||||||
"elements": [
|
"elements": [
|
||||||
"pplr-data-maps"
|
"pplr-data-maps"
|
||||||
],
|
],
|
||||||
|
|
@ -853,7 +853,7 @@
|
||||||
"scriptUrl": "./pplr-data-maps/pplr-data-maps.js",
|
"scriptUrl": "./pplr-data-maps/pplr-data-maps.js",
|
||||||
"embed": {
|
"embed": {
|
||||||
"iframe": "<iframe src=\"./pplr-data-maps/pplr-data-maps/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
|
"iframe": "<iframe src=\"./pplr-data-maps/pplr-data-maps/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
|
||||||
"script": "<!-- Mapbox engine, fetched early; remove this line if you set \"provider\":\"maplibre\" -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./pplr-data-maps/pplr-data-maps.js\" integrity=\"sha384-nMEYoH17y92xbERsRYP3x9sroR//lz8NvipOQvUfV8zV40pJ7DmW0avOm7sARD82\" crossorigin=\"anonymous\"></script>\n<pplr-data-maps profile-config='{\"profile\":\"pplr-data-maps\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></pplr-data-maps>"
|
"script": "<!-- Mapbox engine, fetched early; remove this line if you set \"provider\":\"maplibre\" -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./pplr-data-maps/pplr-data-maps.js\" integrity=\"sha384-e6wVt+dC86mFb8TgX2jBn7wh/R9gA6rGxNgS6umNBeNrir3TstupaJKf4XElRP2T\" crossorigin=\"anonymous\"></script>\n<pplr-data-maps profile-config='{\"profile\":\"pplr-data-maps\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></pplr-data-maps>"
|
||||||
},
|
},
|
||||||
"bundle": "pplr-data-maps"
|
"bundle": "pplr-data-maps"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -837,7 +837,7 @@
|
||||||
"bundle": "pplr-data-maps",
|
"bundle": "pplr-data-maps",
|
||||||
"scriptUrl": "./pplr-data-maps/pplr-data-maps.js",
|
"scriptUrl": "./pplr-data-maps/pplr-data-maps.js",
|
||||||
"output": "dx-maps/pplr-data-maps/pplr-data-maps.js",
|
"output": "dx-maps/pplr-data-maps/pplr-data-maps.js",
|
||||||
"integrity": "sha384-nMEYoH17y92xbERsRYP3x9sroR//lz8NvipOQvUfV8zV40pJ7DmW0avOm7sARD82",
|
"integrity": "sha384-e6wVt+dC86mFb8TgX2jBn7wh/R9gA6rGxNgS6umNBeNrir3TstupaJKf4XElRP2T",
|
||||||
"elements": [
|
"elements": [
|
||||||
"pplr-data-maps"
|
"pplr-data-maps"
|
||||||
],
|
],
|
||||||
|
|
@ -853,7 +853,7 @@
|
||||||
"scriptUrl": "./pplr-data-maps/pplr-data-maps.js",
|
"scriptUrl": "./pplr-data-maps/pplr-data-maps.js",
|
||||||
"embed": {
|
"embed": {
|
||||||
"iframe": "<iframe src=\"./pplr-data-maps/pplr-data-maps/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
|
"iframe": "<iframe src=\"./pplr-data-maps/pplr-data-maps/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
|
||||||
"script": "<!-- Mapbox engine, fetched early; remove this line if you set \"provider\":\"maplibre\" -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./pplr-data-maps/pplr-data-maps.js\" integrity=\"sha384-nMEYoH17y92xbERsRYP3x9sroR//lz8NvipOQvUfV8zV40pJ7DmW0avOm7sARD82\" crossorigin=\"anonymous\"></script>\n<pplr-data-maps profile-config='{\"profile\":\"pplr-data-maps\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></pplr-data-maps>"
|
"script": "<!-- Mapbox engine, fetched early; remove this line if you set \"provider\":\"maplibre\" -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./pplr-data-maps/pplr-data-maps.js\" integrity=\"sha384-e6wVt+dC86mFb8TgX2jBn7wh/R9gA6rGxNgS6umNBeNrir3TstupaJKf4XElRP2T\" crossorigin=\"anonymous\"></script>\n<pplr-data-maps profile-config='{\"profile\":\"pplr-data-maps\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></pplr-data-maps>"
|
||||||
},
|
},
|
||||||
"bundle": "pplr-data-maps"
|
"bundle": "pplr-data-maps"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -30,7 +30,7 @@
|
||||||
|
|
||||||
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
|
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
|
||||||
<!-- Bundle IIFE — registers the <pplr-data-maps> custom element. -->
|
<!-- Bundle IIFE — registers the <pplr-data-maps> custom element. -->
|
||||||
<script src="../pplr-data-maps.js" integrity="sha384-nMEYoH17y92xbERsRYP3x9sroR//lz8NvipOQvUfV8zV40pJ7DmW0avOm7sARD82" crossorigin="anonymous"></script>
|
<script src="../pplr-data-maps.js" integrity="sha384-e6wVt+dC86mFb8TgX2jBn7wh/R9gA6rGxNgS6umNBeNrir3TstupaJKf4XElRP2T" crossorigin="anonymous"></script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue