@fieldia/map 0.14.1 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/README.md +63 -3
  2. package/package.json +5 -4
  3. package/src/index.d.mts +3 -0
  4. package/src/index.d.ts +3 -0
  5. package/src/index.js +5 -1
  6. package/src/index.js.map +1 -1
  7. package/src/index.mjs +2 -0
  8. package/src/index.mjs.map +1 -1
  9. package/src/lib/area.js +29 -246
  10. package/src/lib/area.js.map +1 -1
  11. package/src/lib/area.mjs +29 -246
  12. package/src/lib/area.mjs.map +1 -1
  13. package/src/lib/card.d.mts +45 -0
  14. package/src/lib/card.d.ts +45 -0
  15. package/src/lib/card.js +89 -0
  16. package/src/lib/card.js.map +1 -0
  17. package/src/lib/card.mjs +85 -0
  18. package/src/lib/card.mjs.map +1 -0
  19. package/src/lib/cluster.d.mts +12 -0
  20. package/src/lib/cluster.d.ts +12 -0
  21. package/src/lib/cluster.js +60 -0
  22. package/src/lib/cluster.js.map +1 -0
  23. package/src/lib/cluster.mjs +57 -0
  24. package/src/lib/cluster.mjs.map +1 -0
  25. package/src/lib/drawing.d.mts +36 -0
  26. package/src/lib/drawing.d.ts +36 -0
  27. package/src/lib/drawing.js +267 -0
  28. package/src/lib/drawing.js.map +1 -0
  29. package/src/lib/drawing.mjs +263 -0
  30. package/src/lib/drawing.mjs.map +1 -0
  31. package/src/lib/kinds.js +9 -2
  32. package/src/lib/kinds.js.map +1 -1
  33. package/src/lib/kinds.mjs +9 -2
  34. package/src/lib/kinds.mjs.map +1 -1
  35. package/src/lib/labels.d.mts +28 -0
  36. package/src/lib/labels.d.ts +28 -0
  37. package/src/lib/labels.js +76 -1
  38. package/src/lib/labels.js.map +1 -1
  39. package/src/lib/labels.mjs +74 -0
  40. package/src/lib/labels.mjs.map +1 -1
  41. package/src/lib/list-view.d.mts +13 -0
  42. package/src/lib/list-view.d.ts +13 -0
  43. package/src/lib/list-view.js +481 -0
  44. package/src/lib/list-view.js.map +1 -0
  45. package/src/lib/list-view.mjs +478 -0
  46. package/src/lib/list-view.mjs.map +1 -0
  47. package/src/lib/map-core.d.mts +2 -2
  48. package/src/lib/map-core.d.ts +2 -2
  49. package/src/lib/map-core.js +1 -1
  50. package/src/lib/map-core.js.map +1 -1
  51. package/src/lib/map-core.mjs +1 -1
  52. package/src/lib/map-core.mjs.map +1 -1
  53. package/src/lib/map-icons.d.mts +8 -0
  54. package/src/lib/map-icons.d.ts +8 -0
  55. package/src/lib/map-icons.js +21 -0
  56. package/src/lib/map-icons.js.map +1 -0
  57. package/src/lib/map-icons.mjs +18 -0
  58. package/src/lib/map-icons.mjs.map +1 -0
  59. package/src/lib/pins.d.mts +56 -0
  60. package/src/lib/pins.d.ts +56 -0
  61. package/src/lib/pins.js +161 -0
  62. package/src/lib/pins.js.map +1 -0
  63. package/src/lib/pins.mjs +154 -0
  64. package/src/lib/pins.mjs.map +1 -0
  65. package/src/lib/settings.d.mts +5 -2
  66. package/src/lib/settings.d.ts +5 -2
  67. package/src/lib/styles.d.mts +8 -0
  68. package/src/lib/styles.d.ts +8 -0
  69. package/src/lib/styles.js +142 -1
  70. package/src/lib/styles.js.map +1 -1
  71. package/src/lib/styles.mjs +140 -0
  72. package/src/lib/styles.mjs.map +1 -1
@@ -51,6 +51,8 @@ export const MAP_LABELS = {
51
51
  heightMedium: 'Medium',
52
52
  heightLarge: 'Large',
53
53
  settingShapes: 'Shapes',
54
+ settingAddress: 'Address goes into',
55
+ settingNowhere: 'Nowhere',
54
56
  },
55
57
  ar: {
56
58
  mapOf: '{label}، خريطة',
@@ -104,6 +106,8 @@ export const MAP_LABELS = {
104
106
  heightMedium: 'متوسط',
105
107
  heightLarge: 'كبير',
106
108
  settingShapes: 'الأشكال',
109
+ settingAddress: 'يُكتب العنوان في',
110
+ settingNowhere: 'لا مكان',
107
111
  },
108
112
  fr: {
109
113
  mapOf: '{label}, carte',
@@ -157,6 +161,8 @@ export const MAP_LABELS = {
157
161
  heightMedium: 'Moyenne',
158
162
  heightLarge: 'Grande',
159
163
  settingShapes: 'Formes',
164
+ settingAddress: 'L’adresse va dans',
165
+ settingNowhere: 'Nulle part',
160
166
  },
161
167
  de: {
162
168
  mapOf: '{label}, Karte',
@@ -210,12 +216,80 @@ export const MAP_LABELS = {
210
216
  heightMedium: 'Mittel',
211
217
  heightLarge: 'Groß',
212
218
  settingShapes: 'Formen',
219
+ settingAddress: 'Adresse kommt in',
220
+ settingNowhere: 'Nirgends',
221
+ },
222
+ };
223
+ export const LIST_MAP_LABELS = {
224
+ en: {
225
+ pinKeys: 'Tab goes through the pins. Enter opens a pin’s card; Escape closes it.',
226
+ searchThisArea: 'Search this area',
227
+ inThisArea: 'In this area',
228
+ openRecord: 'Open',
229
+ choose: 'Choose',
230
+ closeCard: 'Close',
231
+ cluster: '{n} here. Zoom in to see them.',
232
+ crowd: '{n} in one place',
233
+ notOnMap: '{n} without a place, not on the map',
234
+ mapShowsFirst: 'The map shows {n} of {total}. Zoom in and search this area for the rest.',
235
+ mapFailed: 'The map could not load the records.',
236
+ drawArea: 'Draw an area to search in',
237
+ inDrawnArea: 'In the area drawn',
238
+ },
239
+ ar: {
240
+ pinKeys: 'ينتقل Tab بين الدبابيس. يفتح Enter بطاقة الدبوس، ويغلقها Escape.',
241
+ searchThisArea: 'ابحث في هذه المنطقة',
242
+ inThisArea: 'في هذه المنطقة',
243
+ openRecord: 'فتح',
244
+ choose: 'اختيار',
245
+ closeCard: 'إغلاق',
246
+ cluster: '{n} هنا. كبّر الخريطة لرؤيتها.',
247
+ crowd: '{n} في مكان واحد',
248
+ notOnMap: '{n} بلا مكان، ليست على الخريطة',
249
+ mapShowsFirst: 'تعرض الخريطة {n} من {total}. كبّر الخريطة وابحث في هذه المنطقة لرؤية البقية.',
250
+ mapFailed: 'تعذّر تحميل السجلات على الخريطة.',
251
+ drawArea: 'ارسم منطقة للبحث فيها',
252
+ inDrawnArea: 'في المنطقة المرسومة',
253
+ },
254
+ fr: {
255
+ pinKeys: 'Tab parcourt les épingles. Entrée ouvre la fiche d’une épingle, Échap la ferme.',
256
+ searchThisArea: 'Rechercher dans cette zone',
257
+ inThisArea: 'Dans cette zone',
258
+ openRecord: 'Ouvrir',
259
+ choose: 'Choisir',
260
+ closeCard: 'Fermer',
261
+ cluster: '{n} ici. Zoomez pour les voir.',
262
+ crowd: '{n} au même endroit',
263
+ notOnMap: '{n} sans lieu, absents de la carte',
264
+ mapShowsFirst: 'La carte en montre {n} sur {total}. Zoomez et recherchez dans cette zone pour voir les autres.',
265
+ mapFailed: 'La carte n’a pas pu charger les enregistrements.',
266
+ drawArea: 'Tracer une zone où chercher',
267
+ inDrawnArea: 'Dans la zone tracée',
268
+ },
269
+ de: {
270
+ pinKeys: 'Tab springt von Nadel zu Nadel. Eingabe öffnet die Karte einer Nadel, Escape schließt sie.',
271
+ searchThisArea: 'In diesem Gebiet suchen',
272
+ inThisArea: 'In diesem Gebiet',
273
+ openRecord: 'Öffnen',
274
+ choose: 'Auswählen',
275
+ closeCard: 'Schließen',
276
+ cluster: '{n} hier. Hineinzoomen, um sie zu sehen.',
277
+ crowd: '{n} an einem Ort',
278
+ notOnMap: '{n} ohne Ort, nicht auf der Karte',
279
+ mapShowsFirst: 'Die Karte zeigt {n} von {total}. Hineinzoomen und in diesem Gebiet suchen, um die übrigen zu sehen.',
280
+ mapFailed: 'Die Karte konnte die Datensätze nicht laden.',
281
+ drawArea: 'Ein Gebiet zum Suchen zeichnen',
282
+ inDrawnArea: 'Im gezeichneten Gebiet',
213
283
  },
214
284
  };
215
285
  /** The words for a page's language, with the app's own over them. */
216
286
  export function mapLabels(locale, own) {
217
287
  return { ...MAP_LABELS[locale ?? 'en'], ...own };
218
288
  }
289
+ /** A list's map's words for a page's language, the maps' own with them, and the app's own over both. */
290
+ export function listMapLabels(locale, own) {
291
+ return { ...MAP_LABELS[locale ?? 'en'], ...LIST_MAP_LABELS[locale ?? 'en'], ...own };
292
+ }
219
293
  /** A word with its `{name}`s filled in. */
220
294
  export const fill = (words, values) => words.replace(/\{(\w+)\}/g, (all, key) => (key in values ? String(values[key]) : all));
221
295
  //# sourceMappingURL=labels.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"labels.mjs","sourceRoot":"","sources":["../../../../../libs/map/src/lib/labels.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"labels.mjs","sourceRoot":"","sources":["../../../../../libs/map/src/lib/labels.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { ListViewFactory } from '@fieldia/viewer';
2
+ import type { MapSettings } from './settings.mjs';
3
+ /**
4
+ * A list's records on a map, for the viewer's `listViews`: the list's own
5
+ * search and its chosen records, shared with the table. A pin lights its row
6
+ * and a row its pin; a pin opens a card with the record's picture, a few of
7
+ * its fields, a box to choose it and a button to open it. Pins that crowd
8
+ * become a bubble with their count. After the map is moved, "Search this
9
+ * area" puts the area into the search bar, as the person's own search.
10
+ *
11
+ * mountViewer(host, { page, listViews: mapListViews({ provider }) })
12
+ */
13
+ export declare function mapListViews(settings: MapSettings): Record<string, ListViewFactory>;
@@ -0,0 +1,13 @@
1
+ import type { ListViewFactory } from '@fieldia/viewer';
2
+ import type { MapSettings } from './settings';
3
+ /**
4
+ * A list's records on a map, for the viewer's `listViews`: the list's own
5
+ * search and its chosen records, shared with the table. A pin lights its row
6
+ * and a row its pin; a pin opens a card with the record's picture, a few of
7
+ * its fields, a box to choose it and a button to open it. Pins that crowd
8
+ * become a bubble with their count. After the map is moved, "Search this
9
+ * area" puts the area into the search bar, as the person's own search.
10
+ *
11
+ * mountViewer(host, { page, listViews: mapListViews({ provider }) })
12
+ */
13
+ export declare function mapListViews(settings: MapSettings): Record<string, ListViewFactory>;
@@ -0,0 +1,481 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.mapListViews = mapListViews;
4
+ const card_1 = require("./card");
5
+ const cluster_1 = require("./cluster");
6
+ const drawing_1 = require("./drawing");
7
+ const geo_1 = require("./geo");
8
+ const labels_1 = require("./labels");
9
+ const map_core_1 = require("./map-core");
10
+ const styles_1 = require("./styles");
11
+ const pins_1 = require("./pins");
12
+ /**
13
+ * A list's records on a map, for the viewer's `listViews`: the list's own
14
+ * search and its chosen records, shared with the table. A pin lights its row
15
+ * and a row its pin; a pin opens a card with the record's picture, a few of
16
+ * its fields, a box to choose it and a button to open it. Pins that crowd
17
+ * become a bubble with their count. After the map is moved, "Search this
18
+ * area" puts the area into the search bar, as the person's own search.
19
+ *
20
+ * mountViewer(host, { page, listViews: mapListViews({ provider }) })
21
+ */
22
+ function mapListViews(settings) {
23
+ return { map: (context) => listMap(settings, context) };
24
+ }
25
+ /** Pins nearer than this, in pixels, become one bubble. */
26
+ const CROWD = 48;
27
+ /** Room kept around the records when the map fits them, in pixels. */
28
+ const ROOM = 40;
29
+ /** Moves the person makes; a fit, a card's own pan and a resize are not. */
30
+ const MOVE_KEYS = new Set(['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', '+', '-', '=', '_']);
31
+ /** No size for a mark: Leaflet then sets none, and the mark is as large as its face (its types leave null out; its code takes it). */
32
+ const SIZED_BY_FACE = null;
33
+ /** How a mark stands on its point: its size is its face's, so CSS stands it there. */
34
+ const anchor = (face) => (face.element.dataset['look'] === 'label' ? 'fd-map-tail' : face.stands === 'foot' ? 'fd-map-foot' : 'fd-map-middle');
35
+ function listMap(settings, context) {
36
+ const { page, node, document: doc, locale } = context;
37
+ // The viewer asks for a map only for a list with `map`.
38
+ const spec = node.map;
39
+ const labels = (0, labels_1.listMapLabels)(locale, settings.labels?.[locale]);
40
+ const model = page.data.kind === 'record' ? page.data.model : '';
41
+ const title = spec.card?.title ?? node.columns[0];
42
+ const cardFields = spec.card?.fields ?? node.columns.filter((name) => name !== title).slice(0, 4);
43
+ const pins = (0, pins_1.makePins)({ document: doc, page, locale, pin: spec.pin ?? {}, title, icons: context.icons, drawers: settings.pins });
44
+ const where = spec.point ? [spec.point] : [spec.latitude, spec.longitude];
45
+ const fields = [...new Set([...where, ...pins.fields, ...(spec.card?.image ? [spec.card.image] : []), ...cardFields.flatMap((name) => (0, pins_1.withCurrency)(page, name))])];
46
+ const count = (n) => new Intl.NumberFormat(locale, { numberingSystem: 'latn' }).format(n);
47
+ (0, styles_1.installListMapStyles)(doc);
48
+ const element = doc.createElement('div');
49
+ element.className = 'fd-map-list';
50
+ const box = (0, map_core_1.createMapBox)({
51
+ document: doc,
52
+ provider: settings.provider,
53
+ locale,
54
+ labels,
55
+ name: page.title ?? model,
56
+ keys: labels.pinKeys,
57
+ center: settings.center,
58
+ zoom: settings.zoom,
59
+ height: 'clamp(320px, 64vh, 640px)',
60
+ });
61
+ element.append(box.element);
62
+ const here = doc.createElement('button');
63
+ here.type = 'button';
64
+ here.className = 'fd-map-here';
65
+ here.textContent = labels.searchThisArea;
66
+ here.hidden = true;
67
+ const note = doc.createElement('p');
68
+ note.className = 'fd-map-list-note';
69
+ note.setAttribute('role', 'status');
70
+ note.hidden = true;
71
+ // ---- an area drawn, to search in -----------------------------------------------------
72
+ const live = doc.createElement('div');
73
+ live.className = 'fd-sr-only';
74
+ live.setAttribute('aria-live', 'polite');
75
+ element.append(live);
76
+ const announce = (words) => {
77
+ live.textContent = '';
78
+ // A new node each time, so the same words are said again.
79
+ setTimeout(() => (live.textContent = words), 30);
80
+ };
81
+ const tools = doc.createElement('div');
82
+ tools.className = 'fd-map-draw';
83
+ tools.setAttribute('role', 'group');
84
+ tools.setAttribute('aria-label', labels.drawArea);
85
+ const toolButtons = new Map();
86
+ for (const shape of ['polygon', 'box', 'circle']) {
87
+ const button = doc.createElement('button');
88
+ button.type = 'button';
89
+ button.innerHTML = drawing_1.SHAPE_ICONS[shape];
90
+ button.setAttribute('aria-label', labels[shape]);
91
+ button.title = `${labels.drawArea}: ${labels[shape]}`;
92
+ button.setAttribute('aria-pressed', 'false');
93
+ button.addEventListener('click', () => drawing.arm(drawing.mode === shape ? null : shape));
94
+ toolButtons.set(shape, button);
95
+ tools.append(button);
96
+ }
97
+ const drawing = (0, drawing_1.shapeDrawing)({
98
+ box,
99
+ labels,
100
+ keys: element,
101
+ announce,
102
+ armed: (mode) => {
103
+ for (const [shape, button] of toolButtons)
104
+ button.setAttribute('aria-pressed', String(shape === mode));
105
+ },
106
+ done: (area) => box.ready((map, L) => searchIn(map, L, area)),
107
+ escaped: () => toolButtons.get('polygon')?.focus(),
108
+ finishesOn: (target) => target === toolButtons.get('polygon'),
109
+ over: '.fd-map-here, .fd-map-draw, .fd-map-list-note',
110
+ });
111
+ /** The area drawn, on the map while its search is in the search bar. */
112
+ let searched = null;
113
+ let searchedKey = '';
114
+ let records = [];
115
+ let places = [];
116
+ let drawn = [];
117
+ const drawnOf = new Map();
118
+ let hot = null;
119
+ let open = null;
120
+ let layer = null;
121
+ /** A record lit inside a bubble: its own pin over the bubble, for as long as its row is lit. */
122
+ let ghost = null;
123
+ let asking = 0;
124
+ let destroyed = false;
125
+ let fitted = false;
126
+ let lastFilter = '';
127
+ /** The search changed by the map's own "Search this area": the view stays where the person put it. */
128
+ let ownSearch = false;
129
+ let moving = false;
130
+ const dir = () => (doc.defaultView?.getComputedStyle(element).direction === 'rtl' ? 'rtl' : 'ltr');
131
+ const isKeys = (event) => !!event && event.type.startsWith('key');
132
+ const placeOf = (values) => {
133
+ if (spec.point)
134
+ return (0, geo_1.readPoint)(values[spec.point]);
135
+ const lat = values[spec.latitude];
136
+ const lng = values[spec.longitude];
137
+ return typeof lat === 'number' && typeof lng === 'number' && Math.abs(lat) <= 90 && Math.abs(lng) <= 180 ? { lat, lng } : null;
138
+ };
139
+ // ---- the person's own moves, after which "Search this area" is offered ----------
140
+ const pressed = (event) => {
141
+ const target = event.target;
142
+ if (!target?.closest('.leaflet-marker-icon, .leaflet-popup, .fd-map-here, .fd-map-credits, .fd-map-logo'))
143
+ moving = true;
144
+ };
145
+ const keyed = (event) => {
146
+ if (event.target === box.element && MOVE_KEYS.has(event.key))
147
+ moving = true;
148
+ };
149
+ const wheeled = (event) => {
150
+ if (event.ctrlKey || event.metaKey)
151
+ moving = true;
152
+ };
153
+ box.element.addEventListener('pointerdown', pressed, { capture: true });
154
+ box.element.addEventListener('keydown', keyed, { capture: true });
155
+ box.element.addEventListener('wheel', wheeled, { capture: true, passive: true });
156
+ function searchHere(map) {
157
+ const bounds = map.getBounds();
158
+ const round = (n) => Math.round(n * 1e6) / 1e6;
159
+ const wrap = (lng) => round(((((lng + 180) % 360) + 360) % 360) - 180);
160
+ const south = round(Math.max(-90, bounds.getSouth()));
161
+ const north = round(Math.min(90, bounds.getNorth()));
162
+ const whole = bounds.getEast() - bounds.getWest() >= 360;
163
+ const west = whole ? -180 : wrap(bounds.getWest());
164
+ const east = whole ? 180 : wrap(bounds.getEast());
165
+ const filter = spec.point
166
+ ? [{ field: spec.point, op: 'within', value: { south, west, north, east } }]
167
+ : [
168
+ { field: spec.latitude, op: 'between', value: [south, north] },
169
+ // Over the antimeridian no one range holds the longitudes: either side of it, then.
170
+ ...(whole
171
+ ? []
172
+ : west <= east
173
+ ? [{ field: spec.longitude, op: 'between', value: [west, east] }]
174
+ : [{ any: [{ field: spec.longitude, op: '>=', value: west }, { field: spec.longitude, op: '<=', value: east }] }]),
175
+ ];
176
+ ownSearch = true;
177
+ here.hidden = true;
178
+ context.addSearch({ label: labels.inThisArea, filter });
179
+ }
180
+ /** An area drawn becomes a search of its own, "In the area drawn": the places inside it, in the table and on the map. */
181
+ function searchIn(map, L, area) {
182
+ const round = (n) => Math.round(n * 1e6) / 1e6;
183
+ const shape = area.shape === 'circle'
184
+ ? { center: [round(area.center.lng), round(area.center.lat)], radius: Math.round(area.radius) }
185
+ : { polygon: area.points.map((p) => [round(p.lng), round(p.lat)]) };
186
+ const condition = spec.point
187
+ ? { field: spec.point, op: 'within', value: shape }
188
+ : { field: spec.latitude, op: 'within', value: { ...shape, longitude: spec.longitude } };
189
+ searched?.remove();
190
+ searched = (area.shape === 'circle'
191
+ ? L.circle([area.center.lat, area.center.lng], { radius: area.radius, className: 'fd-map-shape fd-map-searched', interactive: false })
192
+ : L.polygon(area.points.map((p) => [p.lat, p.lng]), { className: 'fd-map-shape fd-map-searched', interactive: false })).addTo(map);
193
+ searchedKey = JSON.stringify(condition);
194
+ ownSearch = true;
195
+ here.hidden = true;
196
+ announce(labels.shapeDrawn);
197
+ context.addSearch({ label: labels.inDrawnArea, filter: [condition] });
198
+ }
199
+ // ---- the card -------------------------------------------------------------------
200
+ function closeCard(map, back) {
201
+ if (!open)
202
+ return;
203
+ const { popup, back: to } = open;
204
+ open = null;
205
+ map.closePopup(popup);
206
+ if (back)
207
+ to?.focus();
208
+ }
209
+ function showCard(map, L, at, height, card, id, back, byKeys) {
210
+ closeCard(map, false);
211
+ // Escape closes the card and goes back to its pin; the arrows stay with the card, not the map.
212
+ card.element.addEventListener('keydown', (event) => {
213
+ if (event.key === 'Escape') {
214
+ event.stopPropagation();
215
+ closeCard(map, true);
216
+ }
217
+ else if (MOVE_KEYS.has(event.key))
218
+ event.stopPropagation();
219
+ });
220
+ const popup = L.popup({ closeButton: false, autoPanPadding: [16, 16], className: 'fd-map-card-popup', minWidth: 220, maxWidth: 280, offset: [0, 4 - height] })
221
+ .setLatLng([at.lat, at.lng])
222
+ .setContent(card.element);
223
+ open = { id, card, popup, back };
224
+ popup.openOn(map);
225
+ if (byKeys)
226
+ card.focus();
227
+ }
228
+ function openCard(map, L, record, at, height, back, byKeys) {
229
+ const card = (0, card_1.drawCard)({
230
+ document: doc,
231
+ page,
232
+ locale,
233
+ labels,
234
+ dir: dir(),
235
+ card: spec.card ?? {},
236
+ title,
237
+ fields: cardFields,
238
+ record,
239
+ chosen: context.isChosen(record.id),
240
+ choose: (on) => context.choose(record.id, on),
241
+ ...(context.open ? { open: () => context.open?.(record.id) } : {}),
242
+ close: () => closeCard(map, true),
243
+ });
244
+ showCard(map, L, at, height, card, record.id, back, byKeys);
245
+ }
246
+ // ---- the pins -------------------------------------------------------------------
247
+ function draw(map, L) {
248
+ layer ??= L.layerGroup().addTo(map);
249
+ layer.clearLayers();
250
+ drawn = [];
251
+ drawnOf.clear();
252
+ const placed = records.flatMap((record, i) => (places[i] ? [{ record, at: places[i] }] : []));
253
+ const zoom = map.getZoom();
254
+ const groups = spec.cluster === false
255
+ ? placed.map((_, i) => [i])
256
+ : (0, cluster_1.clusterPoints)(placed.map(({ at }) => map.project([at.lat, at.lng], zoom)), CROWD);
257
+ for (const group of groups) {
258
+ if (group.length === 1)
259
+ single(map, L, placed[group[0]].record, placed[group[0]].at);
260
+ else
261
+ bubble(map, L, group.map((i) => placed[i]));
262
+ }
263
+ restyle();
264
+ light(map, L);
265
+ }
266
+ /**
267
+ * A mark pressed: clicked, or Enter or Space while it has the focus. Leaflet
268
+ * makes a mark a button to the keyboard but clicks it only for a popup of its own.
269
+ */
270
+ function onPress(marker, act) {
271
+ marker.on('click', (event) => act(event.originalEvent));
272
+ marker.on('keydown', (event) => {
273
+ const key = event.originalEvent;
274
+ if (key.key !== 'Enter' && key.key !== ' ')
275
+ return;
276
+ key.preventDefault();
277
+ act(key);
278
+ });
279
+ }
280
+ function mark(entry, name) {
281
+ const element = entry.marker.getElement();
282
+ element?.setAttribute('aria-label', name);
283
+ drawn.push(entry);
284
+ for (const id of entry.ids)
285
+ drawnOf.set(id, entry);
286
+ return element;
287
+ }
288
+ function single(map, L, record, at) {
289
+ const face = pins.face(record);
290
+ const icon = L.divIcon({ className: `fd-map-mark ${anchor(face)}`, html: face.element, iconSize: SIZED_BY_FACE });
291
+ const marker = L.marker([at.lat, at.lng], { icon, keyboard: true, riseOnHover: true, riseOffset: 500 }).addTo(layer);
292
+ const element = mark({ marker, face: face.element, ids: [record.id] }, pins.name(record));
293
+ if (element)
294
+ element.dataset['id'] = String(record.id);
295
+ const height = face.stands === 'foot' ? face.height : face.height / 2;
296
+ onPress(marker, (event) => {
297
+ // Ctrl (⌘) and a click chooses the record, as in a list of files.
298
+ if (event && (event.ctrlKey || event.metaKey))
299
+ context.choose(record.id, !context.isChosen(record.id));
300
+ else
301
+ openCard(map, L, record, at, height, element ?? null, isKeys(event));
302
+ });
303
+ marker.on('mouseover', () => context.highlight(record.id));
304
+ marker.on('mouseout', () => context.highlight(null));
305
+ element?.addEventListener('focus', () => context.highlight(record.id));
306
+ element?.addEventListener('blur', () => context.highlight(null));
307
+ }
308
+ function bubble(map, L, members) {
309
+ const n = members.length;
310
+ const face = doc.createElement('div');
311
+ face.className = 'fd-map-bubble';
312
+ face.dataset['size'] = n < 10 ? 's' : n < 100 ? 'm' : 'l';
313
+ face.textContent = new Intl.NumberFormat(locale, { notation: 'compact', numberingSystem: 'latn' }).format(n);
314
+ const centre = { lat: members.reduce((sum, p) => sum + p.at.lat, 0) / n, lng: members.reduce((sum, p) => sum + p.at.lng, 0) / n };
315
+ const icon = L.divIcon({ className: 'fd-map-mark fd-map-middle', html: face, iconSize: SIZED_BY_FACE });
316
+ const marker = L.marker([centre.lat, centre.lng], { icon, keyboard: true, riseOnHover: true }).addTo(layer);
317
+ const element = mark({ marker, face, ids: members.map((p) => p.record.id) }, (0, labels_1.fill)(labels.cluster, { n: count(n) }));
318
+ const bounds = L.latLngBounds(members.map((p) => [p.at.lat, p.at.lng]));
319
+ onPress(marker, (event) => {
320
+ const byKeys = isKeys(event);
321
+ const most = Math.min(map.getMaxZoom(), 19);
322
+ // Closer, until they part; on one spot (a tower's flats), a list of them.
323
+ if (map.getZoom() < most && !bounds.getNorthEast().equals(bounds.getSouthWest(), 1e-7)) {
324
+ moving = true;
325
+ map.fitBounds(bounds, { padding: [ROOM, ROOM], maxZoom: most });
326
+ if (byKeys)
327
+ box.element.focus();
328
+ return;
329
+ }
330
+ const crowd = (0, card_1.drawCrowd)({
331
+ document: doc,
332
+ labels,
333
+ dir: dir(),
334
+ records: members.map((p) => ({ record: p.record, name: pins.name(p.record) })),
335
+ pick: (record) => {
336
+ const at = members.find((p) => p.record.id === record.id)?.at ?? centre;
337
+ openCard(map, L, record, at, 20, element ?? null, true);
338
+ },
339
+ close: () => closeCard(map, true),
340
+ });
341
+ showCard(map, L, centre, 20, crowd, null, element ?? null, byKeys);
342
+ });
343
+ }
344
+ /** A lit record that is in a bubble shows where it is: its own pin, over the bubble. */
345
+ function light(map, L) {
346
+ ghost?.remove();
347
+ ghost = null;
348
+ const entry = hot === null ? undefined : drawnOf.get(hot);
349
+ if (!entry || entry.ids.length === 1)
350
+ return;
351
+ const i = records.findIndex((record) => record.id === hot);
352
+ const at = places[i];
353
+ if (!at)
354
+ return;
355
+ const face = pins.face(records[i]);
356
+ face.element.toggleAttribute('data-hot', true);
357
+ face.element.toggleAttribute('data-chosen', context.isChosen(records[i].id));
358
+ const icon = L.divIcon({ className: `fd-map-mark fd-map-ghost ${anchor(face)}`, html: face.element, iconSize: SIZED_BY_FACE });
359
+ ghost = L.marker([at.lat, at.lng], { icon, interactive: false, keyboard: false, zIndexOffset: 2000 }).addTo(map);
360
+ ghost.getElement()?.setAttribute('aria-hidden', 'true');
361
+ }
362
+ /** Each pin as it stands: lit when its row is, ticked when its record is chosen. */
363
+ function restyle() {
364
+ for (const entry of drawn) {
365
+ const lit = hot !== null && entry.ids.includes(hot);
366
+ entry.face.toggleAttribute('data-hot', lit);
367
+ entry.face.toggleAttribute('data-chosen', entry.ids.some((id) => context.isChosen(id)));
368
+ entry.marker.setZIndexOffset(lit ? 1000 : 0);
369
+ }
370
+ }
371
+ function fit(map) {
372
+ const at = places.filter((p) => !!p);
373
+ if (!at.length)
374
+ return;
375
+ fitted = true;
376
+ if (at.length === 1)
377
+ map.setView([at[0].lat, at[0].lng], Math.max(map.getZoom(), 15), { animate: false });
378
+ else
379
+ map.fitBounds(at.map((p) => [p.lat, p.lng]), { padding: [ROOM, ROOM], maxZoom: 16, animate: false });
380
+ }
381
+ box.ready((map, L) => {
382
+ box.element.append(tools, here, note);
383
+ box.shield(tools);
384
+ box.shield(here);
385
+ box.follow(note);
386
+ box.follow(here);
387
+ here.addEventListener('click', () => searchHere(map));
388
+ map.on('zoomend', () => draw(map, L));
389
+ map.on('moveend', () => {
390
+ if (moving)
391
+ here.hidden = false;
392
+ moving = false;
393
+ });
394
+ map.on('popupclose', (event) => {
395
+ if (open?.popup === event.popup)
396
+ open = null;
397
+ });
398
+ });
399
+ async function reload() {
400
+ const source = context.dataSource;
401
+ if (!source?.list)
402
+ return;
403
+ const asked = ++asking;
404
+ const filter = context.filter();
405
+ const key = JSON.stringify(filter);
406
+ let result;
407
+ try {
408
+ result = await source.list({ model, fields, filter, sort: node.sort ?? [], offset: 0, limit: spec.limit ?? 500 });
409
+ }
410
+ catch {
411
+ if (asked !== asking || destroyed)
412
+ return;
413
+ note.textContent = labels.mapFailed;
414
+ note.hidden = false;
415
+ return;
416
+ }
417
+ if (asked !== asking || destroyed)
418
+ return;
419
+ records = result.records;
420
+ places = records.map((record) => placeOf(record.values));
421
+ const refit = !fitted || (key !== lastFilter && !ownSearch);
422
+ lastFilter = key;
423
+ ownSearch = false;
424
+ // The area drawn leaves the map when its search leaves the search bar.
425
+ if (searchedKey && !key.includes(searchedKey)) {
426
+ searched?.remove();
427
+ searched = null;
428
+ searchedKey = '';
429
+ }
430
+ const missing = places.filter((p) => !p).length;
431
+ const words = [
432
+ result.total > records.length ? (0, labels_1.fill)(labels.mapShowsFirst, { n: count(records.length), total: count(result.total) }) : '',
433
+ missing ? (0, labels_1.fill)(labels.notOnMap, { n: count(missing) }) : '',
434
+ ].filter(Boolean);
435
+ note.textContent = words.join(' ');
436
+ note.hidden = !words.length;
437
+ box.ready((map, L) => {
438
+ if (destroyed)
439
+ return;
440
+ if (refit) {
441
+ fit(map);
442
+ here.hidden = true;
443
+ }
444
+ draw(map, L);
445
+ if (open?.id !== null && open && !records.some((r) => r.id === open?.id))
446
+ closeCard(map, false);
447
+ else
448
+ open?.card.setChosen(open.id !== null && context.isChosen(open.id));
449
+ });
450
+ }
451
+ return {
452
+ element,
453
+ reload,
454
+ highlight(id) {
455
+ hot = id;
456
+ restyle();
457
+ box.ready((map, L) => light(map, L));
458
+ },
459
+ chosenChanged() {
460
+ restyle();
461
+ if (open?.id !== null && open)
462
+ open.card.setChosen(context.isChosen(open.id));
463
+ },
464
+ shown() {
465
+ box.refresh();
466
+ box.ready((map) => {
467
+ map.invalidateSize({ pan: false });
468
+ if (!fitted)
469
+ fit(map);
470
+ });
471
+ },
472
+ destroy() {
473
+ destroyed = true;
474
+ box.element.removeEventListener('pointerdown', pressed, { capture: true });
475
+ box.element.removeEventListener('keydown', keyed, { capture: true });
476
+ box.element.removeEventListener('wheel', wheeled, { capture: true });
477
+ box.destroy();
478
+ },
479
+ };
480
+ }
481
+ //# sourceMappingURL=list-view.js.map