UPG Neighbor: a green group's unreached neighbours one E-level at a time, closest first, and green dots on Campaigns open them
This commit is contained in:
parent
ae7726a554
commit
2d6e8e6912
2 changed files with 39 additions and 5 deletions
|
|
@ -134,8 +134,17 @@ onMounted(async () => {
|
|||
const u = active.value?.unreached.find((g) => g.pgid === id)
|
||||
if (u) openGroup(u)
|
||||
})
|
||||
m.on('mouseenter', 'cp-u', () => { m.getCanvas().style.cursor = 'pointer' })
|
||||
m.on('mouseleave', 'cp-u', () => { m.getCanvas().style.cursor = '' })
|
||||
// A GREEN dot opens that reached group in Mobilize: the unreached neighbours its believers can
|
||||
// reach, the letter's audience (Driver, test round 2: "on the Campaign side you can't click green dots").
|
||||
m.on('click', 'cp-r', (ev) => {
|
||||
const id = ev.features?.[0]?.properties?.id
|
||||
const r = active.value?.reached.find((g) => g.pgid === id)
|
||||
if (r) openGroup(r)
|
||||
})
|
||||
for (const id of ['cp-u', 'cp-r']) {
|
||||
m.on('mouseenter', id, () => { m.getCanvas().style.cursor = 'pointer' })
|
||||
m.on('mouseleave', id, () => { m.getCanvas().style.cursor = '' })
|
||||
}
|
||||
const byId = (id) => active.value && [...active.value.reached, ...active.value.unreached].find((g) => g.pgid === id)
|
||||
for (const id of ['cp-u', 'cp-r']) {
|
||||
m.on('mousemove', id, (ev) => {
|
||||
|
|
|
|||
|
|
@ -51,11 +51,30 @@ const { map, initializeMap, destroy } = useMapInstance({
|
|||
// shows the unreached groups its believers are nearest to. One selection, whichever kind it is.
|
||||
const selected = computed(() => data.value?.groups.find((g) => g.pgid === nbState.pgid) || null)
|
||||
const isReachedSel = computed(() => !!selected.value?.reached)
|
||||
const neighbors = computed(() => {
|
||||
const allNeighbors = computed(() => {
|
||||
const g = selected.value
|
||||
if (!g) return []
|
||||
return g.reached ? data.value.unreachedNeighborsOf(g) : data.value.neighborsOf(g)
|
||||
})
|
||||
// THE LETTER'S AUDIENCE (Driver, test round 2: UPG Neighbor is a letter generator for GREEN groups).
|
||||
// A reached group's unreached neighbours are shown ONE E-level at a time: E-1 (the same language) by
|
||||
// default, E-2 / E-3 on request, closest first. The list, the map lines and the CSV all follow it.
|
||||
const levelCounts = computed(() => {
|
||||
const c = { 1: 0, 2: 0, 3: 0 }
|
||||
for (const n of allNeighbors.value) if (c[n.e] != null) c[n.e]++
|
||||
return c
|
||||
})
|
||||
// The reader's pick while that level has neighbours; otherwise the first level that has any (E-1 first).
|
||||
// Computed, not set on click, because a group opened from a link arrives before its data does.
|
||||
const eChoice = ref(null)
|
||||
watch(() => nbState.pgid, () => { eChoice.value = null })
|
||||
const eLevel = computed({
|
||||
get: () => (eChoice.value && levelCounts.value[eChoice.value]) ? eChoice.value : ([1, 2, 3].find((e) => levelCounts.value[e]) || 1),
|
||||
set: (v) => { eChoice.value = v },
|
||||
})
|
||||
const neighbors = computed(() => (isReachedSel.value
|
||||
? allNeighbors.value.filter((n) => n.e === eLevel.value).sort((a, b) => a.km - b.km)
|
||||
: allNeighbors.value))
|
||||
const byLevel = computed(() => [1, 2, 3].map((e) => ({ e, list: neighbors.value.filter((n) => n.e === e) })).filter((x) => x.list.length))
|
||||
const believersNear = computed(() => neighbors.value.reduce((a, n) => a + n.g.believers, 0))
|
||||
const peopleReachable = computed(() => neighbors.value.reduce((a, n) => a + n.g.pop, 0))
|
||||
|
|
@ -123,7 +142,7 @@ function exportSegments() {
|
|||
re.name, re.country, re.langName, re.lang, re.believers, n.km, re.lat, re.lng,
|
||||
re.bible ? 'yes' : 'no', re.film ? 'yes' : 'no', re.audio ? 'yes' : 'no', re.radio ? 'yes' : 'no', re.pgid]
|
||||
})
|
||||
downloadCsv(`near-neighbors-${u.pgid}.csv`, header, rows)
|
||||
downloadCsv(u.reached ? `unreached-neighbors-${u.pgid}-E${eLevel.value}.csv` : `near-neighbors-${u.pgid}.csv`, header, rows)
|
||||
}
|
||||
function openBridge() { if (selected.value) { nbState.lang = selected.value.lang; nbState.view = 'campaigns' } }
|
||||
const isBridge = computed(() => !!selected.value && !!data.value?.bridges.some((b) => b.lang === selected.value.lang))
|
||||
|
|
@ -210,7 +229,7 @@ function framePadding() {
|
|||
return w > 760 ? { top: 60, bottom: 60, left: 400, right: 60 } : { top: 40, bottom: Math.round(h * 0.55) + 20, left: 30, right: 30 }
|
||||
}
|
||||
|
||||
watch(() => [nbState.pgid, pFilter.value, data.value], () => { repaint(); frame() })
|
||||
watch(() => [nbState.pgid, pFilter.value, data.value, eLevel.value], () => { repaint(); frame() })
|
||||
|
||||
onMounted(async () => {
|
||||
loadNearData(profileConfig).then((d) => { data.value = d; repaint(); frame() })
|
||||
|
|
@ -357,6 +376,12 @@ useShadowStyles(`
|
|||
{{ $t('neighbor.mob.reachedLong', { n: fmtNum(selected.believers) }) }}
|
||||
<div style="margin-top:4px">{{ $t('neighbor.mob.reachCount', { n: neighbors.length.toLocaleString('en-US'), p: fmtNum(peopleReachable) }) }}</div>
|
||||
</div>
|
||||
<!-- ONE E-level at a time, E-1 first: the letter goes to the nearest culture before the farther ones. -->
|
||||
<div v-if="isReachedSel" class="mb-pchips" role="group" :aria-label="$t('neighbor.mob.eFilter')">
|
||||
<button v-for="e in [1, 2, 3]" :key="e" type="button" class="mb-chip" :class="{ on: eLevel === e }"
|
||||
:aria-pressed="eLevel === e ? 'true' : 'false'" :disabled="!levelCounts[e]" :title="$t(E_RLONG[e])"
|
||||
@click="eLevel = e">{{ $t(E_SHORT[e]) }} · {{ levelCounts[e].toLocaleString('en-US') }}</button>
|
||||
</div>
|
||||
<div v-else class="mb-p" :style="{ background: (E_COLORS[selected.p] || '#9aa7b4') + '22' }">
|
||||
<strong><template v-if="selected.p">P-{{ selected.p }} · </template>{{ $t(P_TITLE[selected.p]) }}</strong>
|
||||
{{ $t(P_LONG[selected.p]) }}
|
||||
|
|
|
|||
Loading…
Reference in a new issue