Cities: open on the dots' own extent, and on a phone put the window where most of them are
A hard-coded opening zoom framed the world at one canvas size only. The map now fits the people-group dots on first paint. A portrait phone cannot zoom out far enough to frame the world in Mercator (floor 0.72 at 390x844), so when the fit is clamped the view slides to the longitude window holding the most dots. Measured: desktop 1440x900 still 2107/2107 drawn; phone 390x844 from 1599 to 1907 of 2107.
This commit is contained in:
parent
2624cf8ef5
commit
258fb5006c
1 changed files with 27 additions and 0 deletions
|
|
@ -122,6 +122,33 @@ function paintGroups(map) {
|
|||
dotCount.value = fc.features.length
|
||||
// Named 'language-families' because the shared selected-pin highlight looks for it.
|
||||
map.addSource('language-families', { type: 'geojson', data: fc, promoteId: 'uniqueId' })
|
||||
// OPENING VIEW = the dots' own extent (gospel found this on its clone). A hard-coded zoom frames
|
||||
// the world only at one canvas size: MEASURED at 390 px, zoom 1.3 showed 1,579 of the 2,107
|
||||
// groups and cut off the Americas and the Pacific. Fitting the data means the first view cannot
|
||||
// depend on the screen. Once, on first paint; the user owns the camera after that.
|
||||
if (fc.features.length) {
|
||||
let w = 180, s = 90, e = -180, n = -90
|
||||
for (const f of fc.features) { const [x, y] = f.geometry.coordinates; if (x < w) w = x; if (x > e) e = x; if (y < s) s = y; if (y > n) n = y }
|
||||
const pad = Math.round(Math.min(map.getContainer().clientWidth, map.getContainer().clientHeight) * 0.06) + 8
|
||||
try {
|
||||
const want = map.cameraForBounds([[w, s], [e, n]], { padding: pad })
|
||||
map.fitBounds([[w, s], [e, n]], { padding: pad, duration: 0 })
|
||||
// A PORTRAIT PHONE CANNOT FRAME THE WORLD IN MERCATOR: the engine will not zoom out past the
|
||||
// point where the world stops filling the viewport vertically (MEASURED at 390x844: floor
|
||||
// 0.72 while the fit wanted -0.62). When the fit is clamped like that, some dots must be off
|
||||
// screen; put the visible window where the MOST dots are rather than at the bbox centre.
|
||||
if (want && map.getZoom() > want.zoom + 0.05) {
|
||||
const b = map.getBounds(); const span = Math.min(360, b.getEast() - b.getWest())
|
||||
let bestLng = map.getCenter().lng, best = -1
|
||||
for (let c = -180; c < 180; c += 5) {
|
||||
let k = 0
|
||||
for (const f of fc.features) { let d = f.geometry.coordinates[0] - c; d = ((d + 540) % 360) - 180; if (Math.abs(d) <= span / 2) k++ }
|
||||
if (k > best) { best = k; bestLng = c }
|
||||
}
|
||||
map.jumpTo({ center: [bestLng, (s + n) / 2] })
|
||||
}
|
||||
} catch (_) {}
|
||||
}
|
||||
map.addLayer({
|
||||
id: 'ci-pg-dots', type: 'circle', source: 'language-families',
|
||||
paint: {
|
||||
|
|
|
|||
Loading…
Reference in a new issue