Let the key filter the map, so the gap can be looked at on its own
The map could say what one group has, on tap. It could not answer the question it exists for — show me only the ones with nothing — so the 3,444 groups that still have no resource were spread through 12,379 dots and could not be seen as a pattern. THE KEY IS THE FILTER. A reader who has just worked out what a colour means is exactly the reader who wants to see only that colour, so the legend entries became the controls rather than adding a second row beneath them. Each carries its live count: 4,711 with Scripture and film, 4,224 with some resource, 3,444 with nothing — summing to 12,379, which is the check that the three buckets partition the set rather than overlap it. FILTERED ON THE LAYER, NOT THE SOURCE. setFilter is a GL-side predicate, so all 12,379 features stay on the GPU and nothing is re-parsed or re-uploaded on a toggle. Rebuilding the FeatureCollection per click would re-upload a megabyte to redraw a subset it already holds. Clicking an active filter clears it, and the state line names what is hidden with a "Show all 12,379" out — a filtered map that does not say it is filtered is how a reader concludes the data is missing. Verified on the served tree: rendered features 12,379 -> 3,444 on the "nothing found" filter, getFilter returns ["==",["get","tier"],0], and the only tier visible afterwards is 0. All three buttons expose an accessible name and aria-pressed. The filtered view shows the remaining gap concentrated in the Sahel, the Horn, north India and Nepal, Myanmar, Indonesia and the Philippines.
This commit is contained in:
parent
f9808d0c8b
commit
fc04f14a52
8 changed files with 82 additions and 33 deletions
|
|
@ -146,6 +146,22 @@ const pinCodes = ref({}) // ISO 639-3 -> { l, s, f, a, o, ck, un }
|
|||
const pinCount = ref(0)
|
||||
|
||||
// The legend quotes these, so they can never drift from what the layer is drawing.
|
||||
// PIN FILTER. The map answers "what does this group have" on tap, but it could not answer
|
||||
// "show me only the ones with nothing" — which is the question the map exists for. Filtering
|
||||
// the LAYER rather than rebuilding the source: setFilter is a GL-side predicate, so 12,379
|
||||
// features stay on the GPU and nothing is re-parsed or re-uploaded on a toggle.
|
||||
const pinFilter = ref('all') // all | none | some | both
|
||||
function setPinFilter(v) {
|
||||
pinFilter.value = v
|
||||
const m = mapRef.value
|
||||
if (!m || !m.getLayer('gr-pins')) return
|
||||
m.setFilter('gr-pins',
|
||||
v === 'all' ? null
|
||||
: v === 'none' ? ['==', ['get', 'tier'], 0]
|
||||
: v === 'some' ? ['==', ['get', 'tier'], 1]
|
||||
: ['==', ['get', 'tier'], 2])
|
||||
}
|
||||
|
||||
const pinTally = computed(() => {
|
||||
const t = [0, 0, 0]
|
||||
for (const r of pinRows.value) t[r[6]]++
|
||||
|
|
@ -473,6 +489,16 @@ useShadowStyles(
|
|||
'border:1.4px solid #fff;box-shadow:0 0 0 1px rgba(0,0,0,.18);vertical-align:-1px}' +
|
||||
'.gm-pinkey{margin-top:7px;padding-top:6px;border-top:1px solid rgba(0,0,0,.12)}' +
|
||||
'.is-dark .gm-pinkey{border-top-color:rgba(255,255,255,.16)}' +
|
||||
'.gm-keys-btn{gap:4px 8px}' +
|
||||
'.gm-kbtn{border:1px solid transparent;background:transparent;color:inherit;font:inherit;font-size:11px;' +
|
||||
'padding:2px 6px;border-radius:999px;cursor:pointer;min-height:24px;display:inline-flex;align-items:center;gap:5px}' +
|
||||
'.gm-kbtn:hover{background:#e9ebe6;border-color:#d1d4cd}' +
|
||||
'.gm-kbtn.on{background:#3b463d;border-color:#3b463d;color:#fff}' +
|
||||
'.gm-kbtn b{font-variant-numeric:tabular-nums;opacity:.75;font-weight:700}' +
|
||||
'.gm-filtered{margin-top:5px;font-size:10.5px;line-height:1.45;color:#3b463d}' +
|
||||
'.is-dark .gm-filtered{color:#e5e7eb}' +
|
||||
'.gm-kclear{border:1px solid #d1d4cd;background:#fff;color:#3b463d;font:600 10.5px inherit;' +
|
||||
'padding:3px 8px;border-radius:6px;cursor:pointer;margin-left:4px;min-height:24px}' +
|
||||
'.gm-pinkey-h{font-size:11px;font-weight:600;margin-bottom:4px}' +
|
||||
'.gm-caveat{margin-top:5px;font-size:10.5px;opacity:.72;line-height:1.4}' +
|
||||
// DETAIL: a bottom sheet on a phone, a corner card on desktop.
|
||||
|
|
@ -580,10 +606,33 @@ useShadowStyles(
|
|||
Each <i class="gm-dot" style="background:#6d766e"></i> is ONE people group —
|
||||
{{ fmt(pinTally.total) }} of them, {{ fmt(pinTally.linked) }} with a link
|
||||
</div>
|
||||
<div class="gm-keys">
|
||||
<span class="gm-key"><i class="gm-dot" :style="{ background: PIN_COLOR[2] }"></i>Scripture <em>and</em> film</span>
|
||||
<span class="gm-key"><i class="gm-dot" :style="{ background: PIN_COLOR[1] }"></i>some resource found</span>
|
||||
<span class="gm-key"><i class="gm-dot" :style="{ background: PIN_COLOR[0] }"></i>nothing found</span>
|
||||
<!-- The key IS the filter: a reader who has just understood what a colour means is
|
||||
exactly the reader who wants to see only that colour. Two controls would be one
|
||||
too many. -->
|
||||
<div class="gm-keys gm-keys-btn">
|
||||
<button type="button" class="gm-key gm-kbtn" :class="{ on: pinFilter === 'both' }"
|
||||
@click="setPinFilter(pinFilter === 'both' ? 'all' : 'both')"
|
||||
:aria-pressed="pinFilter === 'both'">
|
||||
<i class="gm-dot" :style="{ background: PIN_COLOR[2] }"></i>Scripture <em>and</em> film
|
||||
<b>{{ fmt(pinTally.both) }}</b>
|
||||
</button>
|
||||
<button type="button" class="gm-key gm-kbtn" :class="{ on: pinFilter === 'some' }"
|
||||
@click="setPinFilter(pinFilter === 'some' ? 'all' : 'some')"
|
||||
:aria-pressed="pinFilter === 'some'">
|
||||
<i class="gm-dot" :style="{ background: PIN_COLOR[1] }"></i>some resource found
|
||||
<b>{{ fmt(pinTally.partial) }}</b>
|
||||
</button>
|
||||
<button type="button" class="gm-key gm-kbtn" :class="{ on: pinFilter === 'none' }"
|
||||
@click="setPinFilter(pinFilter === 'none' ? 'all' : 'none')"
|
||||
:aria-pressed="pinFilter === 'none'">
|
||||
<i class="gm-dot" :style="{ background: PIN_COLOR[0] }"></i>nothing found
|
||||
<b>{{ fmt(pinTally.none) }}</b>
|
||||
</button>
|
||||
</div>
|
||||
<div v-if="pinFilter !== 'all'" class="gm-filtered">
|
||||
Showing only <b>{{ pinFilter === 'none' ? 'groups with nothing found'
|
||||
: pinFilter === 'some' ? 'groups with some resource' : 'groups with Scripture and film' }}</b>.
|
||||
<button type="button" class="gm-kclear" @click="setPinFilter('all')">Show all {{ fmt(pinTally.total) }}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gm-caveat">
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
|
||||
<!-- Bundle IIFE — registers the <gospel-resources-map> custom element. -->
|
||||
<script src="../gospel-resources.js" integrity="sha384-DJOPWgxv0aJTTqWf05/FWiCVqQURbKIlqPP+rlyMLFZmYm8UzzQBrMACWHOPDj5t" crossorigin="anonymous"></script>
|
||||
<script src="../gospel-resources.js" integrity="sha384-DpU1SWn4u94XMNElOTNoASob58FSPB7BTxE522CQEVO+cyFgnwXgNoD6O55tfkht" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
|
||||
<!-- Bundle IIFE — registers the <gospel-resources-map> custom element. -->
|
||||
<script src="../gospel-resources.js" integrity="sha384-DJOPWgxv0aJTTqWf05/FWiCVqQURbKIlqPP+rlyMLFZmYm8UzzQBrMACWHOPDj5t" crossorigin="anonymous"></script>
|
||||
<script src="../gospel-resources.js" integrity="sha384-DpU1SWn4u94XMNElOTNoASob58FSPB7BTxE522CQEVO+cyFgnwXgNoD6O55tfkht" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
|
||||
<!-- Bundle IIFE — registers the <gospel-resources-map> custom element. -->
|
||||
<script src="../gospel-resources.js" integrity="sha384-DJOPWgxv0aJTTqWf05/FWiCVqQURbKIlqPP+rlyMLFZmYm8UzzQBrMACWHOPDj5t" crossorigin="anonymous"></script>
|
||||
<script src="../gospel-resources.js" integrity="sha384-DpU1SWn4u94XMNElOTNoASob58FSPB7BTxE522CQEVO+cyFgnwXgNoD6O55tfkht" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
|
||||
<!-- Bundle IIFE — registers the <gospel-resources-map> custom element. -->
|
||||
<script src="../gospel-resources.js" integrity="sha384-DJOPWgxv0aJTTqWf05/FWiCVqQURbKIlqPP+rlyMLFZmYm8UzzQBrMACWHOPDj5t" crossorigin="anonymous"></script>
|
||||
<script src="../gospel-resources.js" integrity="sha384-DpU1SWn4u94XMNElOTNoASob58FSPB7BTxE522CQEVO+cyFgnwXgNoD6O55tfkht" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
2
public/doxa-maps/index.html
generated
2
public/doxa-maps/index.html
generated
File diff suppressed because one or more lines are too long
10
public/doxa-maps/manifest.json
generated
10
public/doxa-maps/manifest.json
generated
|
|
@ -556,7 +556,7 @@
|
|||
"bundle": "gospel-resources",
|
||||
"scriptUrl": "./gospel-resources/gospel-resources.js",
|
||||
"output": "doxa-maps/gospel-resources/gospel-resources.js",
|
||||
"integrity": "sha384-DJOPWgxv0aJTTqWf05/FWiCVqQURbKIlqPP+rlyMLFZmYm8UzzQBrMACWHOPDj5t",
|
||||
"integrity": "sha384-DpU1SWn4u94XMNElOTNoASob58FSPB7BTxE522CQEVO+cyFgnwXgNoD6O55tfkht",
|
||||
"elements": [
|
||||
"gospel-resources-map"
|
||||
],
|
||||
|
|
@ -572,7 +572,7 @@
|
|||
"scriptUrl": "./gospel-resources/gospel-resources.js",
|
||||
"embed": {
|
||||
"iframe": "<iframe src=\"./gospel-resources/charts/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
|
||||
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./gospel-resources/gospel-resources.js\" integrity=\"sha384-DJOPWgxv0aJTTqWf05/FWiCVqQURbKIlqPP+rlyMLFZmYm8UzzQBrMACWHOPDj5t\" crossorigin=\"anonymous\"></script>\n<gospel-resources-map profile-config='{\"profile\":\"charts\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-resources-map>"
|
||||
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./gospel-resources/gospel-resources.js\" integrity=\"sha384-DpU1SWn4u94XMNElOTNoASob58FSPB7BTxE522CQEVO+cyFgnwXgNoD6O55tfkht\" crossorigin=\"anonymous\"></script>\n<gospel-resources-map profile-config='{\"profile\":\"charts\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-resources-map>"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -586,7 +586,7 @@
|
|||
"scriptUrl": "./gospel-resources/gospel-resources.js",
|
||||
"embed": {
|
||||
"iframe": "<iframe src=\"./gospel-resources/data-tables/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
|
||||
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./gospel-resources/gospel-resources.js\" integrity=\"sha384-DJOPWgxv0aJTTqWf05/FWiCVqQURbKIlqPP+rlyMLFZmYm8UzzQBrMACWHOPDj5t\" crossorigin=\"anonymous\"></script>\n<gospel-resources-map profile-config='{\"profile\":\"data-tables\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-resources-map>"
|
||||
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./gospel-resources/gospel-resources.js\" integrity=\"sha384-DpU1SWn4u94XMNElOTNoASob58FSPB7BTxE522CQEVO+cyFgnwXgNoD6O55tfkht\" crossorigin=\"anonymous\"></script>\n<gospel-resources-map profile-config='{\"profile\":\"data-tables\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-resources-map>"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -600,7 +600,7 @@
|
|||
"scriptUrl": "./gospel-resources/gospel-resources.js",
|
||||
"embed": {
|
||||
"iframe": "<iframe src=\"./gospel-resources/resources-list/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
|
||||
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./gospel-resources/gospel-resources.js\" integrity=\"sha384-DJOPWgxv0aJTTqWf05/FWiCVqQURbKIlqPP+rlyMLFZmYm8UzzQBrMACWHOPDj5t\" crossorigin=\"anonymous\"></script>\n<gospel-resources-map profile-config='{\"profile\":\"resources-list\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-resources-map>"
|
||||
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./gospel-resources/gospel-resources.js\" integrity=\"sha384-DpU1SWn4u94XMNElOTNoASob58FSPB7BTxE522CQEVO+cyFgnwXgNoD6O55tfkht\" crossorigin=\"anonymous\"></script>\n<gospel-resources-map profile-config='{\"profile\":\"resources-list\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-resources-map>"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -614,7 +614,7 @@
|
|||
"scriptUrl": "./gospel-resources/gospel-resources.js",
|
||||
"embed": {
|
||||
"iframe": "<iframe src=\"./gospel-resources/resources-map/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
|
||||
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./gospel-resources/gospel-resources.js\" integrity=\"sha384-DJOPWgxv0aJTTqWf05/FWiCVqQURbKIlqPP+rlyMLFZmYm8UzzQBrMACWHOPDj5t\" crossorigin=\"anonymous\"></script>\n<gospel-resources-map profile-config='{\"profile\":\"resources-map\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-resources-map>"
|
||||
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./gospel-resources/gospel-resources.js\" integrity=\"sha384-DpU1SWn4u94XMNElOTNoASob58FSPB7BTxE522CQEVO+cyFgnwXgNoD6O55tfkht\" crossorigin=\"anonymous\"></script>\n<gospel-resources-map profile-config='{\"profile\":\"resources-map\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-resources-map>"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
|
|||
Loading…
Reference in a new issue