fix(news): an application's picture cards stay at every height

Zoomed out, a hotspot's reports give way to its beacon, and the cards an application draws through pictureCards went with them; they came back only once the camera had stopped after zooming in. The cards now come from every report the close-up view would mark, at any height; the layer's own markers and beacons are unchanged.
This commit is contained in:
Sameh Khamis committed 2026-11-11 19:43:06 -08:00
1 parent 202cb8c3dc
commit a105e819e0
3 files changed
+44 -3

No files matched your search

+15 -2
View File
@@ -172,7 +172,8 @@ const emptyInView = () => ({
*
* `pictureCards(cards, { selectedId })`, when given, draws the picture cards
* instead of the layer: it is called on every render with one card per
* pictured event on the map, in rank order (`{ id, title, lat, lon,
* pictured event on the map, at every height (zoomed out too, where the
* hotspots stand as beacons), in rank order (`{ id, title, lat, lon,
* publishedAt, severity, color, image, video, credit }`), and the selected
* report's id or null, whose own card the layer still draws at its marker; it
* is called with no cards when the layer is turned off.
@@ -691,6 +692,16 @@ export function createNewsLayer({
}
}
// What a host's picture cards are chosen from when the hotspots stand as
// beacons: every report the close-up view would mark, and the selection.
function cardable() {
const current = selected();
const all = localMode() ? localReports(NEWS_MAP_LIMIT) : mapReports;
return current && !all.some((r) => r.id === current.id)
? [...all, current]
: all;
}
// With a `pictureCards` function the host draws the picture cards: one per
// event on the map with a picture (its most severe, then newest report),
// most severe then newest first, at its marker. The host chooses which
@@ -825,7 +836,9 @@ export function createNewsLayer({
horizon.update();
updatePulse();
if (drawPictureCards)
drawPictureCards(enabled ? hostCards(drawn) : [], {
// At every height: zoomed out, a hotspot's reports give way to its
// beacon, but their pictures still stand (the host keeps them apart).
drawPictureCards(enabled ? hostCards(detail ? drawn : cardable()) : [], {
selectedId: enabled ? selectedId : null,
});
else pictureCards(drawn, current, labels);
+28
View File
@@ -296,6 +296,34 @@ test('a host that draws the picture cards is handed one card per pictured event
assert.deepEqual(handed.at(-1), { cards: [], selectedId: null });
});
test("a host's picture cards stay at every height, beacons or markers", async (t) => {
const reports = [
report('major', {
severity: 3,
event: {
size: 1,
lastAt: '2026-10-28T09:00:00.000Z',
sides: [],
image: { url: 'https://example.com/major.jpg', publisher: 'Example' },
},
}),
];
const handed = [];
const { layer } = fixture(t, {
// The whole globe: the hotspot stands as one beacon, its reports unmarked.
height: 20_000_000,
source: { getFeed: async () => ({ reports, nextBefore: null }) },
pictureCards: (cards) => handed.push(cards),
});
layer.enable();
await layer.update();
layer.setParams({ filters: { minSeverity: 0 } });
assert.deepEqual(
handed.at(-1).map((card) => card.id),
['major'],
);
});
test('picture cards must be drawn by a function', () => {
assert.throws(
() =>