From 4e00ec4aa160ae808e0d14669acec0f165ab969f Mon Sep 17 00:00:00 2001 From: Doxa Maps Date: Tue, 29 Sep 2026 00:54:13 +0000 Subject: [PATCH] A pin on the bounded set opens its people group too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The same interaction as the centered set and as GiTree, so a reader who learns one chart has learned all three: click a group, its drawer opens and the camera frames it; reduced motion jumps instead of easing. The centre dish is not a people group, so it is excluded by tier rather than by id — an id test would have to know the dish's private name and would break the day it changed. This chart takes no band layout: its groups are inside or outside one boundary, not on rings, so bandFill has nothing to spread. Only the interaction is shared. --- .../src/components/GiBoundedSetMap.vue | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/plugin-designs/gospel-internet/src/components/GiBoundedSetMap.vue b/plugin-designs/gospel-internet/src/components/GiBoundedSetMap.vue index d9a003c4f..0107b30fc 100644 --- a/plugin-designs/gospel-internet/src/components/GiBoundedSetMap.vue +++ b/plugin-designs/gospel-internet/src/components/GiBoundedSetMap.vue @@ -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 } from '../boardEngine.js' +import { createBoardMap, reducedMotion } from '../boardEngine.js' import { useBoardState } from '../useBoard.js' import { useGiT } from '../useGiT.js' import { layoutBoundedSet } from '@map/components/charts/boundedSet.js' @@ -53,6 +53,24 @@ const data = computed(() => toFeatureCollection(features.value, project).collect const dishDegrees = computed(() => dishRadiusDegrees(R, project)) +/** + * Open a people group and frame it — the same interaction as the centered set and as GiTree, so a + * reader who learns one chart has learned all three. See GiCenteredSetMap.openAndFrame for why the + * camera treats a single dot as a degenerate frame rather than calling fitBounds on it. + */ +function openAndFrame(slug, feature) { + try { board.openGroup?.(slug) } catch (_) { /* the drawer is the ask; the camera is the flourish */ } + const map = mapRef.value + const c = feature?.geometry?.coordinates + if (!map || !Array.isArray(c) || c.length < 2) return + try { + const duration = reducedMotion() ? 0 : 700 + const zoom = Math.max(map.getZoom(), 5.2) + if (duration) map.easeTo({ center: c, zoom, duration, essential: true }) + else map.jumpTo({ center: c, zoom }) + } catch (_) { /* a degenerate frame never breaks the board */ } +} + onMounted(async () => { try { const made = await createBoardMap(el.value, board.profileConfig?.value || {}, @@ -84,6 +102,9 @@ onMounted(async () => { stroke: '#3b463d', // a fill would imply the inside is a region }, font: labelFont, + // A pin opens its people group, the same as the centered set. The centre dish is not a + // group, so it is filtered out by tier rather than by id. + onClick: (id, f) => { if (f?.properties?.tier === TIERS.GROUP && id) openAndFrame(id, f) }, })) } // ★ CALLED UNCONDITIONALLY, AND THE GUARD THAT USED TO BE HERE IS WHY THIS WAS BROKEN TWICE.