Language tree: room to zoom out further
The tapestry is laid out at half its former size in the map's world square, so from the opening view the reader can zoom out two levels instead of one. Every zoom-dependent stop (dot sizes, label entry zooms, framing limits) moves up one level with it, so the opening view looks the same.
This commit is contained in:
parent
414ed9664f
commit
705a815190
15 changed files with 38 additions and 31 deletions
File diff suppressed because one or more lines are too long
|
|
@ -140,7 +140,10 @@ for (const root of [...roots].sort((a, b) => b._R - a._R || a.name.localeCompare
|
|||
// ── to lng/lat through inverse Web Mercator, uniformly scaled, so the drawing is not distorted ─────
|
||||
let ext = 1
|
||||
for (const p of placed) ext = Math.max(ext, Math.abs(p.x) + p.R, Math.abs(p.y) + p.R)
|
||||
const K = 0.34 / ext // the tapestry spans ~68% of the Mercator square
|
||||
// The tapestry spans ~34% of the Mercator square. The engines stop at zoom 0 (the whole square), so the
|
||||
// smaller the drawing, the further a reader can zoom OUT from its opening view: at 68% there was about
|
||||
// one level of room (Driver, 2026-09-27: "I need to be able to zoom out a bit more"); now there are two.
|
||||
const K = 0.17 / ext
|
||||
const toLngLat = (u, v) => {
|
||||
const X = 0.5 + u * K, Y = 0.5 - v * K
|
||||
const lng = (X - 0.5) * 360
|
||||
|
|
|
|||
|
|
@ -96,9 +96,9 @@ nodes.forEach((n, i) => {
|
|||
})
|
||||
const ext = roots.reduce((m, r) => Math.max(m, circ.get(r.id).R), 0)
|
||||
if (minD === Infinity) console.log('NOT MEASURED: no two nodes within 1 px at z0; the spacing measure found nothing to compare')
|
||||
console.log(`info closest two nodes: ${minD.toFixed(4)} px at z0 = ${(minD * 64).toFixed(1)} px at z6 (${pair ? nodes[pair[0]].n + ' / ' + nodes[pair[1]].n : ''}); largest family radius ${ext.toFixed(1)} px at z0`)
|
||||
// Dialect dots first show at z6; two dots closer than 4 px there print as one.
|
||||
ok(minD * 2 ** 6 >= 4, 'no two nodes print on one another at zoom 6 (>= 4 px apart)')
|
||||
console.log(`info closest two nodes: ${minD.toFixed(4)} px at z0 = ${(minD * 128).toFixed(1)} px at z7 (${pair ? nodes[pair[0]].n + ' / ' + nodes[pair[1]].n : ''}); largest family radius ${ext.toFixed(1)} px at z0`)
|
||||
// Dialect labels first show at z5.6 (dots at every zoom); two dots closer than 4 px by z7 print as one.
|
||||
ok(minD * 2 ** 7 >= 4, 'no two nodes print on one another at zoom 7 (>= 4 px apart)')
|
||||
|
||||
if (PNG) {
|
||||
// a tiny RGBA rasteriser: links, then dots, then family rings. No dependency.
|
||||
|
|
|
|||
|
|
@ -79,14 +79,18 @@ function linkFC() {
|
|||
// level: a top-level exponential interpolate with a data-driven stop value is valid on both engines.
|
||||
const dishRadius = ['interpolate', ['exponential', 2], ['zoom'], 0, ['*', ['get', 'R'], 512], 22, ['*', ['get', 'R'], 512 * 2 ** 22]]
|
||||
const colorExpr = ['match', ['get', 'col'], 'g', TREE_COLOR.g, 'y', TREE_COLOR.y, 'r', TREE_COLOR.r, '#9aa2ad']
|
||||
// Zoom stops are in the tree's own scale (build-language-tree.mjs K): the drawing is half the size it
|
||||
// was, so every threshold sits one level higher than before and the opening view looks the same.
|
||||
const nodeRadius = ['interpolate', ['linear'], ['zoom'],
|
||||
0, ['match', ['get', 'lv'], 'f', 4, 'l', 1.6, 'b', 0.9, 0.7],
|
||||
4, ['match', ['get', 'lv'], 'f', 9, 'l', 4.5, 'b', 2.4, 1.8],
|
||||
8, ['match', ['get', 'lv'], 'f', 14, 'l', 8, 'b', 4, 3.5]]
|
||||
0, ['match', ['get', 'lv'], 'f', 3, 'l', 1, 'b', 0.6, 0.5],
|
||||
1, ['match', ['get', 'lv'], 'f', 4, 'l', 1.6, 'b', 0.9, 0.7],
|
||||
5, ['match', ['get', 'lv'], 'f', 9, 'l', 4.5, 'b', 2.4, 1.8],
|
||||
9, ['match', ['get', 'lv'], 'f', 14, 'l', 8, 'b', 4, 3.5]]
|
||||
const nodeRadiusPlus = (k) => ['interpolate', ['linear'], ['zoom'],
|
||||
0, ['+', k, ['match', ['get', 'lv'], 'f', 4, 'l', 1.6, 'b', 0.9, 0.7]],
|
||||
4, ['+', k, ['match', ['get', 'lv'], 'f', 9, 'l', 4.5, 'b', 2.4, 1.8]],
|
||||
8, ['+', k, ['match', ['get', 'lv'], 'f', 14, 'l', 8, 'b', 4, 3.5]]]
|
||||
0, ['+', k, ['match', ['get', 'lv'], 'f', 3, 'l', 1, 'b', 0.6, 0.5]],
|
||||
1, ['+', k, ['match', ['get', 'lv'], 'f', 4, 'l', 1.6, 'b', 0.9, 0.7]],
|
||||
5, ['+', k, ['match', ['get', 'lv'], 'f', 9, 'l', 4.5, 'b', 2.4, 1.8]],
|
||||
9, ['+', k, ['match', ['get', 'lv'], 'f', 14, 'l', 8, 'b', 4, 3.5]]]
|
||||
|
||||
function addLayers(map) {
|
||||
map.addSource('gt-nodes', { type: 'geojson', data: nodeFC(), promoteId: 'id' })
|
||||
|
|
@ -97,7 +101,7 @@ function addLayers(map) {
|
|||
'circle-stroke-color': '#d1d4cd', 'circle-stroke-width': 1, 'circle-pitch-alignment': 'map',
|
||||
} })
|
||||
map.addLayer({ id: 'gt-links', type: 'line', source: 'gt-links', paint: {
|
||||
'line-color': '#8d968e', 'line-width': ['interpolate', ['linear'], ['zoom'], 0, 0.3, 6, 1],
|
||||
'line-color': '#8d968e', 'line-width': ['interpolate', ['linear'], ['zoom'], 1, 0.3, 7, 1],
|
||||
'line-opacity': ['case', ['==', ['get', 'm'], 1], ['case', ['==', ['get', 'd'], 1], 0.35, 0.6], 0.12],
|
||||
} })
|
||||
map.addLayer({ id: 'gt-nodes', type: 'circle', source: 'gt-nodes', paint: {
|
||||
|
|
@ -115,10 +119,10 @@ function addLayers(map) {
|
|||
} })
|
||||
// labels, one layer per level so each level has its own entry zoom; placement never overlaps labels
|
||||
const LABELS = [
|
||||
{ lv: ['f'], min: 0, size: [0, 11, 5, 15], weight: 'bold', offset: 1.1 },
|
||||
{ lv: ['l'], min: 2.6, size: [2.6, 10, 7, 13], weight: 'regular', offset: 0.8 },
|
||||
{ lv: ['b'], min: 3.4, size: [3.4, 9, 7, 11], weight: 'regular', offset: 0.7, muted: true },
|
||||
{ lv: ['d'], min: 4.6, size: [4.6, 9, 8, 11], weight: 'regular', offset: 0.7, muted: true },
|
||||
{ lv: ['f'], min: 0, size: [0, 10, 1, 11, 6, 15], weight: 'bold', offset: 1.1 },
|
||||
{ lv: ['l'], min: 3.6, size: [3.6, 10, 8, 13], weight: 'regular', offset: 0.8 },
|
||||
{ lv: ['b'], min: 4.4, size: [4.4, 9, 8, 11], weight: 'regular', offset: 0.7, muted: true },
|
||||
{ lv: ['d'], min: 5.6, size: [5.6, 9, 9, 11], weight: 'regular', offset: 0.7, muted: true },
|
||||
]
|
||||
for (const L of LABELS) {
|
||||
map.addLayer({ id: 'gt-lab-' + L.lv[0], type: 'symbol', source: 'gt-nodes', minzoom: L.min,
|
||||
|
|
@ -199,9 +203,9 @@ function frame(coords) {
|
|||
const duration = reducedMotion() ? 0 : 900
|
||||
try {
|
||||
if (e - w < 1e-4 && n - s < 1e-4) {
|
||||
const z = Math.max(map.getZoom(), 5)
|
||||
const z = Math.max(map.getZoom(), 6)
|
||||
duration ? map.easeTo({ center: [w, s], zoom: z, duration, essential: true }) : map.jumpTo({ center: [w, s], zoom: z })
|
||||
} else map.fitBounds([[w, s], [e, n]], { padding: 60, maxZoom: 7, duration, essential: true })
|
||||
} else map.fitBounds([[w, s], [e, n]], { padding: 60, maxZoom: 8, duration, essential: true })
|
||||
} catch (_) { /* a degenerate frame never breaks the board */ }
|
||||
}
|
||||
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -578,7 +578,7 @@
|
|||
"bundle": "gospel-internet",
|
||||
"scriptUrl": "./gospel-internet/gospel-internet.js",
|
||||
"output": "dx-maps/gospel-internet/gospel-internet.js",
|
||||
"integrity": "sha384-7OLwBf2bK1Szc8ISMHusFv6dZkvimSiZdBtnCIsRCMZtVnMbBe1KaZ96OvXbu37e",
|
||||
"integrity": "sha384-deOFSn4WjpXO/pQwb+/3TK1qR6tEsxDfl4Fi66Myv/KmPiuWd1rV8YG62fEctMEF",
|
||||
"elements": [
|
||||
"gospel-internet-board"
|
||||
],
|
||||
|
|
@ -594,7 +594,7 @@
|
|||
"scriptUrl": "./gospel-internet/gospel-internet.js",
|
||||
"embed": {
|
||||
"iframe": "<iframe src=\"./gospel-internet/board/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
|
||||
"script": "<!-- Mapbox engine, fetched early. Keep it only with a real Mapbox token in \"tk\": without one (or with \"provider\":\"maplibre\") the map draws with MapLibre and this line must go -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./gospel-internet/gospel-internet.js\" integrity=\"sha384-7OLwBf2bK1Szc8ISMHusFv6dZkvimSiZdBtnCIsRCMZtVnMbBe1KaZ96OvXbu37e\" crossorigin=\"anonymous\"></script>\n<gospel-internet-board profile-config='{\"profile\":\"board\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-internet-board>"
|
||||
"script": "<!-- Mapbox engine, fetched early. Keep it only with a real Mapbox token in \"tk\": without one (or with \"provider\":\"maplibre\") the map draws with MapLibre and this line must go -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./gospel-internet/gospel-internet.js\" integrity=\"sha384-deOFSn4WjpXO/pQwb+/3TK1qR6tEsxDfl4Fi66Myv/KmPiuWd1rV8YG62fEctMEF\" crossorigin=\"anonymous\"></script>\n<gospel-internet-board profile-config='{\"profile\":\"board\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-internet-board>"
|
||||
},
|
||||
"instances": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@
|
|||
|
||||
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
|
||||
<!-- Bundle IIFE — registers the <gospel-internet-board> custom element. -->
|
||||
<script src="../../gospel-internet.js" integrity="sha384-7OLwBf2bK1Szc8ISMHusFv6dZkvimSiZdBtnCIsRCMZtVnMbBe1KaZ96OvXbu37e" crossorigin="anonymous"></script>
|
||||
<script src="../../gospel-internet.js" integrity="sha384-deOFSn4WjpXO/pQwb+/3TK1qR6tEsxDfl4Fi66Myv/KmPiuWd1rV8YG62fEctMEF" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@
|
|||
|
||||
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
|
||||
<!-- Bundle IIFE — registers the <gospel-internet-board> custom element. -->
|
||||
<script src="../gospel-internet.js" integrity="sha384-7OLwBf2bK1Szc8ISMHusFv6dZkvimSiZdBtnCIsRCMZtVnMbBe1KaZ96OvXbu37e" crossorigin="anonymous"></script>
|
||||
<script src="../gospel-internet.js" integrity="sha384-deOFSn4WjpXO/pQwb+/3TK1qR6tEsxDfl4Fi66Myv/KmPiuWd1rV8YG62fEctMEF" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@
|
|||
|
||||
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
|
||||
<!-- Bundle IIFE — registers the <gospel-internet-board> custom element. -->
|
||||
<script src="../../gospel-internet.js" integrity="sha384-7OLwBf2bK1Szc8ISMHusFv6dZkvimSiZdBtnCIsRCMZtVnMbBe1KaZ96OvXbu37e" crossorigin="anonymous"></script>
|
||||
<script src="../../gospel-internet.js" integrity="sha384-deOFSn4WjpXO/pQwb+/3TK1qR6tEsxDfl4Fi66Myv/KmPiuWd1rV8YG62fEctMEF" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@
|
|||
|
||||
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
|
||||
<!-- Bundle IIFE — registers the <gospel-internet-board> custom element. -->
|
||||
<script src="../../gospel-internet.js" integrity="sha384-7OLwBf2bK1Szc8ISMHusFv6dZkvimSiZdBtnCIsRCMZtVnMbBe1KaZ96OvXbu37e" crossorigin="anonymous"></script>
|
||||
<script src="../../gospel-internet.js" integrity="sha384-deOFSn4WjpXO/pQwb+/3TK1qR6tEsxDfl4Fi66Myv/KmPiuWd1rV8YG62fEctMEF" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@
|
|||
|
||||
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
|
||||
<!-- Bundle IIFE — registers the <gospel-internet-board> custom element. -->
|
||||
<script src="../../gospel-internet.js" integrity="sha384-7OLwBf2bK1Szc8ISMHusFv6dZkvimSiZdBtnCIsRCMZtVnMbBe1KaZ96OvXbu37e" crossorigin="anonymous"></script>
|
||||
<script src="../../gospel-internet.js" integrity="sha384-deOFSn4WjpXO/pQwb+/3TK1qR6tEsxDfl4Fi66Myv/KmPiuWd1rV8YG62fEctMEF" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@
|
|||
|
||||
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
|
||||
<!-- Bundle IIFE — registers the <gospel-internet-board> custom element. -->
|
||||
<script src="../../gospel-internet.js" integrity="sha384-7OLwBf2bK1Szc8ISMHusFv6dZkvimSiZdBtnCIsRCMZtVnMbBe1KaZ96OvXbu37e" crossorigin="anonymous"></script>
|
||||
<script src="../../gospel-internet.js" integrity="sha384-deOFSn4WjpXO/pQwb+/3TK1qR6tEsxDfl4Fi66Myv/KmPiuWd1rV8YG62fEctMEF" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@
|
|||
|
||||
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
|
||||
<!-- Bundle IIFE — registers the <gospel-internet-board> custom element. -->
|
||||
<script src="../../gospel-internet.js" integrity="sha384-7OLwBf2bK1Szc8ISMHusFv6dZkvimSiZdBtnCIsRCMZtVnMbBe1KaZ96OvXbu37e" crossorigin="anonymous"></script>
|
||||
<script src="../../gospel-internet.js" integrity="sha384-deOFSn4WjpXO/pQwb+/3TK1qR6tEsxDfl4Fi66Myv/KmPiuWd1rV8YG62fEctMEF" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -578,7 +578,7 @@
|
|||
"bundle": "gospel-internet",
|
||||
"scriptUrl": "./gospel-internet/gospel-internet.js",
|
||||
"output": "dx-maps/gospel-internet/gospel-internet.js",
|
||||
"integrity": "sha384-7OLwBf2bK1Szc8ISMHusFv6dZkvimSiZdBtnCIsRCMZtVnMbBe1KaZ96OvXbu37e",
|
||||
"integrity": "sha384-deOFSn4WjpXO/pQwb+/3TK1qR6tEsxDfl4Fi66Myv/KmPiuWd1rV8YG62fEctMEF",
|
||||
"elements": [
|
||||
"gospel-internet-board"
|
||||
],
|
||||
|
|
@ -594,7 +594,7 @@
|
|||
"scriptUrl": "./gospel-internet/gospel-internet.js",
|
||||
"embed": {
|
||||
"iframe": "<iframe src=\"./gospel-internet/board/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
|
||||
"script": "<!-- Mapbox engine, fetched early. Keep it only with a real Mapbox token in \"tk\": without one (or with \"provider\":\"maplibre\") the map draws with MapLibre and this line must go -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./gospel-internet/gospel-internet.js\" integrity=\"sha384-7OLwBf2bK1Szc8ISMHusFv6dZkvimSiZdBtnCIsRCMZtVnMbBe1KaZ96OvXbu37e\" crossorigin=\"anonymous\"></script>\n<gospel-internet-board profile-config='{\"profile\":\"board\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-internet-board>"
|
||||
"script": "<!-- Mapbox engine, fetched early. Keep it only with a real Mapbox token in \"tk\": without one (or with \"provider\":\"maplibre\") the map draws with MapLibre and this line must go -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./gospel-internet/gospel-internet.js\" integrity=\"sha384-deOFSn4WjpXO/pQwb+/3TK1qR6tEsxDfl4Fi66Myv/KmPiuWd1rV8YG62fEctMEF\" crossorigin=\"anonymous\"></script>\n<gospel-internet-board profile-config='{\"profile\":\"board\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-internet-board>"
|
||||
},
|
||||
"instances": [
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in a new issue