@fieldia/map 0.15.0 → 0.17.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.
- package/README.md +79 -11
- package/package.json +4 -4
- package/src/index.d.mts +2 -1
- package/src/index.d.ts +2 -1
- package/src/index.js +3 -1
- package/src/index.js.map +1 -1
- package/src/index.mjs +1 -0
- package/src/index.mjs.map +1 -1
- package/src/lib/answers.d.mts +17 -0
- package/src/lib/answers.d.ts +17 -0
- package/src/lib/answers.js +27 -0
- package/src/lib/answers.js.map +1 -0
- package/src/lib/answers.mjs +21 -0
- package/src/lib/answers.mjs.map +1 -0
- package/src/lib/area.js +2 -1
- package/src/lib/area.js.map +1 -1
- package/src/lib/area.mjs +3 -2
- package/src/lib/area.mjs.map +1 -1
- package/src/lib/card.d.mts +10 -2
- package/src/lib/card.d.ts +10 -2
- package/src/lib/card.js +13 -4
- package/src/lib/card.js.map +1 -1
- package/src/lib/card.mjs +13 -4
- package/src/lib/card.mjs.map +1 -1
- package/src/lib/form-map.d.mts +18 -0
- package/src/lib/form-map.d.ts +18 -0
- package/src/lib/form-map.js +586 -0
- package/src/lib/form-map.js.map +1 -0
- package/src/lib/form-map.mjs +583 -0
- package/src/lib/form-map.mjs.map +1 -0
- package/src/lib/heat.d.mts +25 -0
- package/src/lib/heat.d.ts +25 -0
- package/src/lib/heat.js +111 -0
- package/src/lib/heat.js.map +1 -0
- package/src/lib/heat.mjs +108 -0
- package/src/lib/heat.mjs.map +1 -0
- package/src/lib/labels.d.mts +33 -0
- package/src/lib/labels.d.ts +33 -0
- package/src/lib/labels.js +60 -1
- package/src/lib/labels.js.map +1 -1
- package/src/lib/labels.mjs +58 -0
- package/src/lib/labels.mjs.map +1 -1
- package/src/lib/list-view.js +168 -70
- package/src/lib/list-view.js.map +1 -1
- package/src/lib/list-view.mjs +162 -64
- package/src/lib/list-view.mjs.map +1 -1
- package/src/lib/map-core.d.mts +8 -0
- package/src/lib/map-core.d.ts +8 -0
- package/src/lib/map-core.js +57 -4
- package/src/lib/map-core.js.map +1 -1
- package/src/lib/map-core.mjs +56 -4
- package/src/lib/map-core.mjs.map +1 -1
- package/src/lib/marks.d.mts +34 -0
- package/src/lib/marks.d.ts +34 -0
- package/src/lib/marks.js +56 -0
- package/src/lib/marks.js.map +1 -0
- package/src/lib/marks.mjs +49 -0
- package/src/lib/marks.mjs.map +1 -0
- package/src/lib/measure.d.mts +15 -0
- package/src/lib/measure.d.ts +15 -0
- package/src/lib/measure.js +157 -0
- package/src/lib/measure.js.map +1 -0
- package/src/lib/measure.mjs +153 -0
- package/src/lib/measure.mjs.map +1 -0
- package/src/lib/pins.d.mts +2 -0
- package/src/lib/pins.d.ts +2 -0
- package/src/lib/pins.js +5 -1
- package/src/lib/pins.js.map +1 -1
- package/src/lib/pins.mjs +3 -1
- package/src/lib/pins.mjs.map +1 -1
- package/src/lib/place.js +3 -1
- package/src/lib/place.js.map +1 -1
- package/src/lib/place.mjs +4 -2
- package/src/lib/place.mjs.map +1 -1
- package/src/lib/providers.d.mts +43 -3
- package/src/lib/providers.d.ts +43 -3
- package/src/lib/providers.js +76 -67
- package/src/lib/providers.js.map +1 -1
- package/src/lib/providers.mjs +24 -15
- package/src/lib/providers.mjs.map +1 -1
- package/src/lib/reach.d.mts +25 -0
- package/src/lib/reach.d.ts +25 -0
- package/src/lib/reach.js +158 -0
- package/src/lib/reach.js.map +1 -0
- package/src/lib/reach.mjs +153 -0
- package/src/lib/reach.mjs.map +1 -0
- package/src/lib/regions.d.mts +137 -0
- package/src/lib/regions.d.ts +137 -0
- package/src/lib/regions.js +456 -0
- package/src/lib/regions.js.map +1 -0
- package/src/lib/regions.mjs +445 -0
- package/src/lib/regions.mjs.map +1 -0
- package/src/lib/route-line.d.mts +34 -0
- package/src/lib/route-line.d.ts +34 -0
- package/src/lib/route-line.js +53 -0
- package/src/lib/route-line.js.map +1 -0
- package/src/lib/route-line.mjs +47 -0
- package/src/lib/route-line.mjs.map +1 -0
- package/src/lib/routes.d.mts +40 -0
- package/src/lib/routes.d.ts +40 -0
- package/src/lib/routes.js +149 -0
- package/src/lib/routes.js.map +1 -0
- package/src/lib/routes.mjs +140 -0
- package/src/lib/routes.mjs.map +1 -0
- package/src/lib/settings.d.mts +13 -3
- package/src/lib/settings.d.ts +13 -3
- package/src/lib/styles.d.mts +10 -2
- package/src/lib/styles.d.ts +10 -2
- package/src/lib/styles.js +52 -3
- package/src/lib/styles.js.map +1 -1
- package/src/lib/styles.mjs +50 -2
- package/src/lib/styles.mjs.map +1 -1
- package/src/lib/tools.d.mts +27 -0
- package/src/lib/tools.d.ts +27 -0
- package/src/lib/tools.js +84 -0
- package/src/lib/tools.js.map +1 -0
- package/src/lib/tools.mjs +81 -0
- package/src/lib/tools.mjs.map +1 -0
package/src/lib/labels.mjs
CHANGED
|
@@ -53,6 +53,14 @@ export const MAP_LABELS = {
|
|
|
53
53
|
settingShapes: 'Shapes',
|
|
54
54
|
settingAddress: 'Address goes into',
|
|
55
55
|
settingNowhere: 'Nowhere',
|
|
56
|
+
satellite: 'Satellite',
|
|
57
|
+
fullScreen: 'Full screen',
|
|
58
|
+
leaveFullScreen: 'Leave full screen',
|
|
59
|
+
measure: 'Measure a distance',
|
|
60
|
+
measureHint: 'Click points along the way; double-click or press Enter to finish. Escape clears.',
|
|
61
|
+
measured: 'The way measures {distance}.',
|
|
62
|
+
areaValue: '{name}: {value}',
|
|
63
|
+
areasNone: 'None',
|
|
56
64
|
},
|
|
57
65
|
ar: {
|
|
58
66
|
mapOf: '{label}، خريطة',
|
|
@@ -108,6 +116,14 @@ export const MAP_LABELS = {
|
|
|
108
116
|
settingShapes: 'الأشكال',
|
|
109
117
|
settingAddress: 'يُكتب العنوان في',
|
|
110
118
|
settingNowhere: 'لا مكان',
|
|
119
|
+
satellite: 'القمر الصناعي',
|
|
120
|
+
fullScreen: 'ملء الشاشة',
|
|
121
|
+
leaveFullScreen: 'الخروج من ملء الشاشة',
|
|
122
|
+
measure: 'قِس مسافة',
|
|
123
|
+
measureHint: 'انقر نقاطًا على طول الطريق؛ انقر مرتين أو اضغط Enter للإنهاء، ويمسح Escape القياس.',
|
|
124
|
+
measured: 'يبلغ الطريق {distance}.',
|
|
125
|
+
areaValue: '{name}: {value}',
|
|
126
|
+
areasNone: 'لا شيء',
|
|
111
127
|
},
|
|
112
128
|
fr: {
|
|
113
129
|
mapOf: '{label}, carte',
|
|
@@ -163,6 +179,14 @@ export const MAP_LABELS = {
|
|
|
163
179
|
settingShapes: 'Formes',
|
|
164
180
|
settingAddress: 'L’adresse va dans',
|
|
165
181
|
settingNowhere: 'Nulle part',
|
|
182
|
+
satellite: 'Satellite',
|
|
183
|
+
fullScreen: 'Plein écran',
|
|
184
|
+
leaveFullScreen: 'Quitter le plein écran',
|
|
185
|
+
measure: 'Mesurer une distance',
|
|
186
|
+
measureHint: 'Cliquez des points le long du trajet ; double-cliquez ou appuyez sur Entrée pour terminer. Échap efface.',
|
|
187
|
+
measured: 'Le trajet mesure {distance}.',
|
|
188
|
+
areaValue: '{name} : {value}',
|
|
189
|
+
areasNone: 'Aucun',
|
|
166
190
|
},
|
|
167
191
|
de: {
|
|
168
192
|
mapOf: '{label}, Karte',
|
|
@@ -218,6 +242,14 @@ export const MAP_LABELS = {
|
|
|
218
242
|
settingShapes: 'Formen',
|
|
219
243
|
settingAddress: 'Adresse kommt in',
|
|
220
244
|
settingNowhere: 'Nirgends',
|
|
245
|
+
satellite: 'Satellit',
|
|
246
|
+
fullScreen: 'Vollbild',
|
|
247
|
+
leaveFullScreen: 'Vollbild verlassen',
|
|
248
|
+
measure: 'Entfernung messen',
|
|
249
|
+
measureHint: 'Punkte entlang des Weges anklicken; Doppelklick oder Eingabe beendet, Escape löscht.',
|
|
250
|
+
measured: 'Der Weg misst {distance}.',
|
|
251
|
+
areaValue: '{name}: {value}',
|
|
252
|
+
areasNone: 'Keine',
|
|
221
253
|
},
|
|
222
254
|
};
|
|
223
255
|
export const LIST_MAP_LABELS = {
|
|
@@ -235,6 +267,10 @@ export const LIST_MAP_LABELS = {
|
|
|
235
267
|
mapFailed: 'The map could not load the records.',
|
|
236
268
|
drawArea: 'Draw an area to search in',
|
|
237
269
|
inDrawnArea: 'In the area drawn',
|
|
270
|
+
inRegion: 'In {name}',
|
|
271
|
+
nearestFirst: 'Nearest first',
|
|
272
|
+
nearestFromMiddle: 'Nearest the middle of the map first: your place was not given.',
|
|
273
|
+
heatNote: 'A heat map from afar: zoom in to the streets to see each one.',
|
|
238
274
|
},
|
|
239
275
|
ar: {
|
|
240
276
|
pinKeys: 'ينتقل Tab بين الدبابيس. يفتح Enter بطاقة الدبوس، ويغلقها Escape.',
|
|
@@ -250,6 +286,10 @@ export const LIST_MAP_LABELS = {
|
|
|
250
286
|
mapFailed: 'تعذّر تحميل السجلات على الخريطة.',
|
|
251
287
|
drawArea: 'ارسم منطقة للبحث فيها',
|
|
252
288
|
inDrawnArea: 'في المنطقة المرسومة',
|
|
289
|
+
inRegion: 'في {name}',
|
|
290
|
+
nearestFirst: 'الأقرب أولًا',
|
|
291
|
+
nearestFromMiddle: 'الأقرب إلى منتصف الخريطة أولًا: لم يُعطَ موقعك.',
|
|
292
|
+
heatNote: 'خريطة حرارية من بعيد: قرّب إلى الشوارع لترى كلًّا منها.',
|
|
253
293
|
},
|
|
254
294
|
fr: {
|
|
255
295
|
pinKeys: 'Tab parcourt les épingles. Entrée ouvre la fiche d’une épingle, Échap la ferme.',
|
|
@@ -265,6 +305,10 @@ export const LIST_MAP_LABELS = {
|
|
|
265
305
|
mapFailed: 'La carte n’a pas pu charger les enregistrements.',
|
|
266
306
|
drawArea: 'Tracer une zone où chercher',
|
|
267
307
|
inDrawnArea: 'Dans la zone tracée',
|
|
308
|
+
inRegion: 'À {name}',
|
|
309
|
+
nearestFirst: 'Les plus proches d’abord',
|
|
310
|
+
nearestFromMiddle: 'Les plus proches du centre de la carte d’abord : votre position n’a pas été donnée.',
|
|
311
|
+
heatNote: 'Une carte de chaleur vue de loin : zoomez jusqu’aux rues pour voir chacun.',
|
|
268
312
|
},
|
|
269
313
|
de: {
|
|
270
314
|
pinKeys: 'Tab springt von Nadel zu Nadel. Eingabe öffnet die Karte einer Nadel, Escape schließt sie.',
|
|
@@ -280,8 +324,18 @@ export const LIST_MAP_LABELS = {
|
|
|
280
324
|
mapFailed: 'Die Karte konnte die Datensätze nicht laden.',
|
|
281
325
|
drawArea: 'Ein Gebiet zum Suchen zeichnen',
|
|
282
326
|
inDrawnArea: 'Im gezeichneten Gebiet',
|
|
327
|
+
inRegion: 'In {name}',
|
|
328
|
+
nearestFirst: 'Nächste zuerst',
|
|
329
|
+
nearestFromMiddle: 'Die der Kartenmitte nächsten zuerst: Ihr Standort wurde nicht freigegeben.',
|
|
330
|
+
heatNote: 'Eine Heatmap aus der Ferne: bis zu den Straßen zoomen, um jeden zu sehen.',
|
|
283
331
|
},
|
|
284
332
|
};
|
|
333
|
+
export const FORM_MAP_LABELS = {
|
|
334
|
+
en: { map: 'Map', lastSeen: 'Last seen {time}', follow: 'Follow', routeFailed: 'The way could not be found.' },
|
|
335
|
+
ar: { map: 'خريطة', lastSeen: 'آخر ظهور {time}', follow: 'تتبّع', routeFailed: 'تعذّر إيجاد الطريق.' },
|
|
336
|
+
fr: { map: 'Carte', lastSeen: 'Vu pour la dernière fois {time}', follow: 'Suivre', routeFailed: 'Le trajet est introuvable.' },
|
|
337
|
+
de: { map: 'Karte', lastSeen: 'Zuletzt gesehen {time}', follow: 'Folgen', routeFailed: 'Der Weg wurde nicht gefunden.' },
|
|
338
|
+
};
|
|
285
339
|
/** The words for a page's language, with the app's own over them. */
|
|
286
340
|
export function mapLabels(locale, own) {
|
|
287
341
|
return { ...MAP_LABELS[locale ?? 'en'], ...own };
|
|
@@ -292,4 +346,8 @@ export function listMapLabels(locale, own) {
|
|
|
292
346
|
}
|
|
293
347
|
/** A word with its `{name}`s filled in. */
|
|
294
348
|
export const fill = (words, values) => words.replace(/\{(\w+)\}/g, (all, key) => (key in values ? String(values[key]) : all));
|
|
349
|
+
/** A form's map's words for a page's language: the maps' own, a list map's (its pins and cards), its own, the app's over all. */
|
|
350
|
+
export function formMapLabels(locale, own) {
|
|
351
|
+
return { ...MAP_LABELS[locale ?? 'en'], ...LIST_MAP_LABELS[locale ?? 'en'], ...FORM_MAP_LABELS[locale ?? 'en'], ...own };
|
|
352
|
+
}
|
|
295
353
|
//# sourceMappingURL=labels.mjs.map
|
package/src/lib/labels.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"labels.mjs","sourceRoot":"","sources":["../../../../../libs/map/src/lib/labels.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"labels.mjs","sourceRoot":"","sources":["../../../../../libs/map/src/lib/labels.ts"],"names":[],"mappings":"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"}
|
package/src/lib/list-view.js
CHANGED
|
@@ -7,6 +7,7 @@ const drawing_1 = require("./drawing");
|
|
|
7
7
|
const geo_1 = require("./geo");
|
|
8
8
|
const labels_1 = require("./labels");
|
|
9
9
|
const map_core_1 = require("./map-core");
|
|
10
|
+
const marks_1 = require("./marks");
|
|
10
11
|
const styles_1 = require("./styles");
|
|
11
12
|
const pins_1 = require("./pins");
|
|
12
13
|
/**
|
|
@@ -26,12 +27,10 @@ function mapListViews(settings) {
|
|
|
26
27
|
const CROWD = 48;
|
|
27
28
|
/** Room kept around the records when the map fits them, in pixels. */
|
|
28
29
|
const ROOM = 40;
|
|
29
|
-
/**
|
|
30
|
-
const
|
|
31
|
-
/**
|
|
32
|
-
const
|
|
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');
|
|
30
|
+
/** The zoom from which a heat map gives way to the records' pins: the streets. */
|
|
31
|
+
const PINS_FROM = 15;
|
|
32
|
+
/** A place as an arrow points it out: "Nearest first". */
|
|
33
|
+
const NEAREST_ICON = '<path d="M3 11l18-8-8 18-2-8z"/>';
|
|
35
34
|
function listMap(settings, context) {
|
|
36
35
|
const { page, node, document: doc, locale } = context;
|
|
37
36
|
// The viewer asks for a map only for a list with `map`.
|
|
@@ -42,7 +41,18 @@ function listMap(settings, context) {
|
|
|
42
41
|
const cardFields = spec.card?.fields ?? node.columns.filter((name) => name !== title).slice(0, 4);
|
|
43
42
|
const pins = (0, pins_1.makePins)({ document: doc, page, locale, pin: spec.pin ?? {}, title, icons: context.icons, drawers: settings.pins });
|
|
44
43
|
const where = spec.point ? [spec.point] : [spec.latitude, spec.longitude];
|
|
45
|
-
const
|
|
44
|
+
const heatSpec = spec.heat ? (spec.heat === true ? {} : spec.heat) : null;
|
|
45
|
+
const areaSpec = spec.regions;
|
|
46
|
+
const fields = [
|
|
47
|
+
...new Set([
|
|
48
|
+
...where,
|
|
49
|
+
...pins.fields,
|
|
50
|
+
...(spec.card?.image ? [spec.card.image] : []),
|
|
51
|
+
...cardFields.flatMap((name) => (0, pins_1.withCurrency)(page, name)),
|
|
52
|
+
...(heatSpec?.weight ? [heatSpec.weight] : []),
|
|
53
|
+
...(areaSpec ? [areaSpec.field] : []),
|
|
54
|
+
]),
|
|
55
|
+
];
|
|
46
56
|
const count = (n) => new Intl.NumberFormat(locale, { numberingSystem: 'latn' }).format(n);
|
|
47
57
|
(0, styles_1.installListMapStyles)(doc);
|
|
48
58
|
const element = doc.createElement('div');
|
|
@@ -57,6 +67,7 @@ function listMap(settings, context) {
|
|
|
57
67
|
center: settings.center,
|
|
58
68
|
zoom: settings.zoom,
|
|
59
69
|
height: 'clamp(320px, 64vh, 640px)',
|
|
70
|
+
tools: (spec.tools ?? []).filter((tool) => tool !== 'nearest'),
|
|
60
71
|
});
|
|
61
72
|
element.append(box.element);
|
|
62
73
|
const here = doc.createElement('button');
|
|
@@ -103,14 +114,93 @@ function listMap(settings, context) {
|
|
|
103
114
|
for (const [shape, button] of toolButtons)
|
|
104
115
|
button.setAttribute('aria-pressed', String(shape === mode));
|
|
105
116
|
},
|
|
106
|
-
done: (area) =>
|
|
117
|
+
done: (area) => searchIn(area),
|
|
107
118
|
escaped: () => toolButtons.get('polygon')?.focus(),
|
|
108
119
|
finishesOn: (target) => target === toolButtons.get('polygon'),
|
|
109
120
|
over: '.fd-map-here, .fd-map-draw, .fd-map-list-note',
|
|
110
121
|
});
|
|
111
|
-
/** The
|
|
112
|
-
|
|
113
|
-
|
|
122
|
+
/** The areas drawn that the search holds, on the map under the pins. */
|
|
123
|
+
const searched = [];
|
|
124
|
+
// ---- nearest first ---------------------------------------------------------------
|
|
125
|
+
const nearest = spec.tools?.includes('nearest') ? box.tool(labels.nearestFirst, NEAREST_ICON) : null;
|
|
126
|
+
const isNearest = () => !!context.sort()[0]?.near;
|
|
127
|
+
nearest?.addEventListener('click', () => {
|
|
128
|
+
nearestWords = '';
|
|
129
|
+
if (isNearest())
|
|
130
|
+
return context.sortBy(null);
|
|
131
|
+
const from = (at) => context.sortBy([{ field: where[0], near: { lat: at.lat, lng: at.lng, ...(spec.point ? {} : { longitude: where[1] }) } }]);
|
|
132
|
+
const middle = () => box.ready((map) => {
|
|
133
|
+
const c = map.getCenter();
|
|
134
|
+
// Said, and kept under the map for as long as the order is from there.
|
|
135
|
+
nearestWords = labels.nearestFromMiddle;
|
|
136
|
+
announce(nearestWords);
|
|
137
|
+
from({ lat: c.lat, lng: c.lng });
|
|
138
|
+
});
|
|
139
|
+
const geolocation = doc.defaultView?.navigator.geolocation;
|
|
140
|
+
if (!geolocation)
|
|
141
|
+
return middle();
|
|
142
|
+
nearest.setAttribute('aria-busy', 'true');
|
|
143
|
+
geolocation.getCurrentPosition((found) => {
|
|
144
|
+
nearest.removeAttribute('aria-busy');
|
|
145
|
+
from({ lat: found.coords.latitude, lng: found.coords.longitude });
|
|
146
|
+
}, () => {
|
|
147
|
+
nearest.removeAttribute('aria-busy');
|
|
148
|
+
middle();
|
|
149
|
+
}, { timeout: 8000, maximumAge: 60000 });
|
|
150
|
+
});
|
|
151
|
+
let regions = null;
|
|
152
|
+
function shadeRegions(filter, asked) {
|
|
153
|
+
if (!areaSpec)
|
|
154
|
+
return;
|
|
155
|
+
regions ??= Promise.resolve().then(() => require('./regions')).then(({ listRegions }) => new Promise((resolve) => box.ready((map, L) => resolve(destroyed
|
|
156
|
+
? null
|
|
157
|
+
: listRegions({
|
|
158
|
+
sets: settings.regions,
|
|
159
|
+
spec: areaSpec,
|
|
160
|
+
box,
|
|
161
|
+
map,
|
|
162
|
+
L,
|
|
163
|
+
document: doc,
|
|
164
|
+
locale,
|
|
165
|
+
labels,
|
|
166
|
+
title: page.title ?? model,
|
|
167
|
+
model,
|
|
168
|
+
dataSource: context.dataSource,
|
|
169
|
+
addSearch: (search) => {
|
|
170
|
+
ownSearch = false;
|
|
171
|
+
context.addSearch(search);
|
|
172
|
+
},
|
|
173
|
+
records: () => records,
|
|
174
|
+
})))));
|
|
175
|
+
void regions.then((made) => made?.shade(filter, () => asked === asking && !destroyed));
|
|
176
|
+
}
|
|
177
|
+
// ---- a heat map, from afar ---------------------------------------------------------
|
|
178
|
+
let heat = null;
|
|
179
|
+
const heatShown = (map) => !!heatSpec && map.getZoom() < PINS_FROM;
|
|
180
|
+
function drawHeat(map, L) {
|
|
181
|
+
if (!heatSpec)
|
|
182
|
+
return;
|
|
183
|
+
const shown = heatShown(map);
|
|
184
|
+
if (!shown && !heat)
|
|
185
|
+
return;
|
|
186
|
+
heat ??= Promise.resolve().then(() => require('./heat')).then(({ drawHeat: make }) => make({
|
|
187
|
+
map,
|
|
188
|
+
L,
|
|
189
|
+
document: doc,
|
|
190
|
+
colours: () => {
|
|
191
|
+
const style = doc.defaultView?.getComputedStyle(box.element);
|
|
192
|
+
return ['--fd-accent', '--fd-warning', '--fd-error'].map((name) => style?.getPropertyValue(name).trim() || '#2563eb');
|
|
193
|
+
},
|
|
194
|
+
}));
|
|
195
|
+
const points = records.flatMap((record, i) => {
|
|
196
|
+
const at = places[i];
|
|
197
|
+
if (!at)
|
|
198
|
+
return [];
|
|
199
|
+
const weight = heatSpec.weight ? Number(record.values[heatSpec.weight]) : 1;
|
|
200
|
+
return Number.isFinite(weight) && weight > 0 ? [{ lat: at.lat, lng: at.lng, weight }] : [];
|
|
201
|
+
});
|
|
202
|
+
void heat.then((layer) => !destroyed && layer.draw(points, heatShown(map)));
|
|
203
|
+
}
|
|
114
204
|
let records = [];
|
|
115
205
|
let places = [];
|
|
116
206
|
let drawn = [];
|
|
@@ -128,7 +218,6 @@ function listMap(settings, context) {
|
|
|
128
218
|
let ownSearch = false;
|
|
129
219
|
let moving = false;
|
|
130
220
|
const dir = () => (doc.defaultView?.getComputedStyle(element).direction === 'rtl' ? 'rtl' : 'ltr');
|
|
131
|
-
const isKeys = (event) => !!event && event.type.startsWith('key');
|
|
132
221
|
const placeOf = (values) => {
|
|
133
222
|
if (spec.point)
|
|
134
223
|
return (0, geo_1.readPoint)(values[spec.point]);
|
|
@@ -143,7 +232,7 @@ function listMap(settings, context) {
|
|
|
143
232
|
moving = true;
|
|
144
233
|
};
|
|
145
234
|
const keyed = (event) => {
|
|
146
|
-
if (event.target === box.element && MOVE_KEYS.has(event.key))
|
|
235
|
+
if (event.target === box.element && marks_1.MOVE_KEYS.has(event.key))
|
|
147
236
|
moving = true;
|
|
148
237
|
};
|
|
149
238
|
const wheeled = (event) => {
|
|
@@ -178,7 +267,7 @@ function listMap(settings, context) {
|
|
|
178
267
|
context.addSearch({ label: labels.inThisArea, filter });
|
|
179
268
|
}
|
|
180
269
|
/** 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(
|
|
270
|
+
function searchIn(area) {
|
|
182
271
|
const round = (n) => Math.round(n * 1e6) / 1e6;
|
|
183
272
|
const shape = area.shape === 'circle'
|
|
184
273
|
? { center: [round(area.center.lng), round(area.center.lat)], radius: Math.round(area.radius) }
|
|
@@ -186,16 +275,37 @@ function listMap(settings, context) {
|
|
|
186
275
|
const condition = spec.point
|
|
187
276
|
? { field: spec.point, op: 'within', value: shape }
|
|
188
277
|
: { 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
278
|
ownSearch = true;
|
|
195
279
|
here.hidden = true;
|
|
196
280
|
announce(labels.shapeDrawn);
|
|
197
281
|
context.addSearch({ label: labels.inDrawnArea, filter: [condition] });
|
|
198
282
|
}
|
|
283
|
+
/**
|
|
284
|
+
* The areas drawn that the search holds, drawn on the map: one drawn here,
|
|
285
|
+
* or one a favourite brings back; gone when their search leaves the bar.
|
|
286
|
+
*/
|
|
287
|
+
function drawSearched(map, L, filter) {
|
|
288
|
+
for (const path of searched.splice(0))
|
|
289
|
+
path.remove();
|
|
290
|
+
const own = new Set([spec.point, spec.latitude].filter((name) => !!name));
|
|
291
|
+
const style = { className: 'fd-map-shape fd-map-searched', interactive: false };
|
|
292
|
+
const walk = (items) => items.forEach((item) => {
|
|
293
|
+
if ('any' in item)
|
|
294
|
+
return walk(item.any);
|
|
295
|
+
if ('all' in item)
|
|
296
|
+
return walk(item.all);
|
|
297
|
+
if (item.op !== 'within' || !own.has(item.field))
|
|
298
|
+
return;
|
|
299
|
+
const area = item.value;
|
|
300
|
+
if (Array.isArray(area['polygon']))
|
|
301
|
+
searched.push(L.polygon(area['polygon'].map(([lng, lat]) => [lat, lng]), style).addTo(map));
|
|
302
|
+
else if (Array.isArray(area['center'])) {
|
|
303
|
+
const [lng, lat] = area['center'];
|
|
304
|
+
searched.push(L.circle([lat, lng], { ...style, radius: Number(area['radius']) }).addTo(map));
|
|
305
|
+
}
|
|
306
|
+
});
|
|
307
|
+
walk(filter);
|
|
308
|
+
}
|
|
199
309
|
// ---- the card -------------------------------------------------------------------
|
|
200
310
|
function closeCard(map, back) {
|
|
201
311
|
if (!open)
|
|
@@ -206,26 +316,12 @@ function listMap(settings, context) {
|
|
|
206
316
|
if (back)
|
|
207
317
|
to?.focus();
|
|
208
318
|
}
|
|
209
|
-
function showCard(map, L, at, height, card, id, back,
|
|
319
|
+
function showCard(map, L, at, height, card, id, back, keys) {
|
|
210
320
|
closeCard(map, false);
|
|
211
|
-
|
|
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);
|
|
321
|
+
const popup = (0, marks_1.popCard)(map, L, { at, height, card, focus: keys, escape: () => closeCard(map, true) });
|
|
223
322
|
open = { id, card, popup, back };
|
|
224
|
-
popup.openOn(map);
|
|
225
|
-
if (byKeys)
|
|
226
|
-
card.focus();
|
|
227
323
|
}
|
|
228
|
-
function openCard(map, L, record, at, height, back,
|
|
324
|
+
function openCard(map, L, record, at, height, back, keys) {
|
|
229
325
|
const card = (0, card_1.drawCard)({
|
|
230
326
|
document: doc,
|
|
231
327
|
page,
|
|
@@ -239,9 +335,11 @@ function listMap(settings, context) {
|
|
|
239
335
|
chosen: context.isChosen(record.id),
|
|
240
336
|
choose: (on) => context.choose(record.id, on),
|
|
241
337
|
...(context.open ? { open: () => context.open?.(record.id) } : {}),
|
|
338
|
+
actions: context.actions,
|
|
339
|
+
act: (id, button) => void context.act(id, [record.id], button),
|
|
242
340
|
close: () => closeCard(map, true),
|
|
243
341
|
});
|
|
244
|
-
showCard(map, L, at, height, card, record.id, back,
|
|
342
|
+
showCard(map, L, at, height, card, record.id, back, keys);
|
|
245
343
|
}
|
|
246
344
|
// ---- the pins -------------------------------------------------------------------
|
|
247
345
|
function draw(map, L) {
|
|
@@ -249,6 +347,14 @@ function listMap(settings, context) {
|
|
|
249
347
|
layer.clearLayers();
|
|
250
348
|
drawn = [];
|
|
251
349
|
drawnOf.clear();
|
|
350
|
+
drawHeat(map, L);
|
|
351
|
+
drawNote(map);
|
|
352
|
+
// From afar, the heat map in place of the pins.
|
|
353
|
+
if (heatShown(map)) {
|
|
354
|
+
ghost?.remove();
|
|
355
|
+
ghost = null;
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
252
358
|
const placed = records.flatMap((record, i) => (places[i] ? [{ record, at: places[i] }] : []));
|
|
253
359
|
const zoom = map.getZoom();
|
|
254
360
|
const groups = spec.cluster === false
|
|
@@ -263,20 +369,6 @@ function listMap(settings, context) {
|
|
|
263
369
|
restyle();
|
|
264
370
|
light(map, L);
|
|
265
371
|
}
|
|
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
372
|
function mark(entry, name) {
|
|
281
373
|
const element = entry.marker.getElement();
|
|
282
374
|
element?.setAttribute('aria-label', name);
|
|
@@ -287,18 +379,18 @@ function listMap(settings, context) {
|
|
|
287
379
|
}
|
|
288
380
|
function single(map, L, record, at) {
|
|
289
381
|
const face = pins.face(record);
|
|
290
|
-
const icon = L.divIcon({ className: `fd-map-mark ${anchor(face)}`, html: face.element, iconSize: SIZED_BY_FACE });
|
|
382
|
+
const icon = L.divIcon({ className: `fd-map-mark ${(0, marks_1.anchor)(face)}`, html: face.element, iconSize: marks_1.SIZED_BY_FACE });
|
|
291
383
|
const marker = L.marker([at.lat, at.lng], { icon, keyboard: true, riseOnHover: true, riseOffset: 500 }).addTo(layer);
|
|
292
384
|
const element = mark({ marker, face: face.element, ids: [record.id] }, pins.name(record));
|
|
293
385
|
if (element)
|
|
294
386
|
element.dataset['id'] = String(record.id);
|
|
295
387
|
const height = face.stands === 'foot' ? face.height : face.height / 2;
|
|
296
|
-
onPress(marker, (event) => {
|
|
388
|
+
(0, marks_1.onPress)(marker, (event) => {
|
|
297
389
|
// Ctrl (⌘) and a click chooses the record, as in a list of files.
|
|
298
390
|
if (event && (event.ctrlKey || event.metaKey))
|
|
299
391
|
context.choose(record.id, !context.isChosen(record.id));
|
|
300
392
|
else
|
|
301
|
-
openCard(map, L, record, at, height, element ?? null,
|
|
393
|
+
openCard(map, L, record, at, height, element ?? null, (0, marks_1.byKeys)(event));
|
|
302
394
|
});
|
|
303
395
|
marker.on('mouseover', () => context.highlight(record.id));
|
|
304
396
|
marker.on('mouseout', () => context.highlight(null));
|
|
@@ -312,18 +404,18 @@ function listMap(settings, context) {
|
|
|
312
404
|
face.dataset['size'] = n < 10 ? 's' : n < 100 ? 'm' : 'l';
|
|
313
405
|
face.textContent = new Intl.NumberFormat(locale, { notation: 'compact', numberingSystem: 'latn' }).format(n);
|
|
314
406
|
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 });
|
|
407
|
+
const icon = L.divIcon({ className: 'fd-map-mark fd-map-middle', html: face, iconSize: marks_1.SIZED_BY_FACE });
|
|
316
408
|
const marker = L.marker([centre.lat, centre.lng], { icon, keyboard: true, riseOnHover: true }).addTo(layer);
|
|
317
409
|
const element = mark({ marker, face, ids: members.map((p) => p.record.id) }, (0, labels_1.fill)(labels.cluster, { n: count(n) }));
|
|
318
410
|
const bounds = L.latLngBounds(members.map((p) => [p.at.lat, p.at.lng]));
|
|
319
|
-
onPress(marker, (event) => {
|
|
320
|
-
const
|
|
411
|
+
(0, marks_1.onPress)(marker, (event) => {
|
|
412
|
+
const fromKeys = (0, marks_1.byKeys)(event);
|
|
321
413
|
const most = Math.min(map.getMaxZoom(), 19);
|
|
322
414
|
// Closer, until they part; on one spot (a tower's flats), a list of them.
|
|
323
415
|
if (map.getZoom() < most && !bounds.getNorthEast().equals(bounds.getSouthWest(), 1e-7)) {
|
|
324
416
|
moving = true;
|
|
325
417
|
map.fitBounds(bounds, { padding: [ROOM, ROOM], maxZoom: most });
|
|
326
|
-
if (
|
|
418
|
+
if (fromKeys)
|
|
327
419
|
box.element.focus();
|
|
328
420
|
return;
|
|
329
421
|
}
|
|
@@ -338,7 +430,7 @@ function listMap(settings, context) {
|
|
|
338
430
|
},
|
|
339
431
|
close: () => closeCard(map, true),
|
|
340
432
|
});
|
|
341
|
-
showCard(map, L, centre, 20, crowd, null, element ?? null,
|
|
433
|
+
showCard(map, L, centre, 20, crowd, null, element ?? null, fromKeys);
|
|
342
434
|
});
|
|
343
435
|
}
|
|
344
436
|
/** A lit record that is in a bubble shows where it is: its own pin, over the bubble. */
|
|
@@ -355,7 +447,7 @@ function listMap(settings, context) {
|
|
|
355
447
|
const face = pins.face(records[i]);
|
|
356
448
|
face.element.toggleAttribute('data-hot', true);
|
|
357
449
|
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 });
|
|
450
|
+
const icon = L.divIcon({ className: `fd-map-mark fd-map-ghost ${(0, marks_1.anchor)(face)}`, html: face.element, iconSize: marks_1.SIZED_BY_FACE });
|
|
359
451
|
ghost = L.marker([at.lat, at.lng], { icon, interactive: false, keyboard: false, zIndexOffset: 2000 }).addTo(map);
|
|
360
452
|
ghost.getElement()?.setAttribute('aria-hidden', 'true');
|
|
361
453
|
}
|
|
@@ -368,6 +460,14 @@ function listMap(settings, context) {
|
|
|
368
460
|
entry.marker.setZIndexOffset(lit ? 1000 : 0);
|
|
369
461
|
}
|
|
370
462
|
}
|
|
463
|
+
/** What the map says under its pins: how many it shows of how many, those with no place, and a heat map's way in. */
|
|
464
|
+
let noteWords = [];
|
|
465
|
+
let nearestWords = '';
|
|
466
|
+
function drawNote(map) {
|
|
467
|
+
const words = [...noteWords, ...(nearestWords && isNearest() ? [nearestWords] : []), ...(heatShown(map) && records.length ? [labels.heatNote] : [])];
|
|
468
|
+
note.textContent = words.join(' ');
|
|
469
|
+
note.hidden = !words.length;
|
|
470
|
+
}
|
|
371
471
|
function fit(map) {
|
|
372
472
|
const at = places.filter((p) => !!p);
|
|
373
473
|
if (!at.length)
|
|
@@ -405,7 +505,8 @@ function listMap(settings, context) {
|
|
|
405
505
|
const key = JSON.stringify(filter);
|
|
406
506
|
let result;
|
|
407
507
|
try {
|
|
408
|
-
|
|
508
|
+
// The list's order, so the map shows the same first records: nearest first, when asked.
|
|
509
|
+
result = await source.list({ model, fields, filter, sort: context.sort(), offset: 0, limit: spec.limit ?? 500 });
|
|
409
510
|
}
|
|
410
511
|
catch {
|
|
411
512
|
if (asked !== asking || destroyed)
|
|
@@ -421,19 +522,13 @@ function listMap(settings, context) {
|
|
|
421
522
|
const refit = !fitted || (key !== lastFilter && !ownSearch);
|
|
422
523
|
lastFilter = key;
|
|
423
524
|
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
525
|
const missing = places.filter((p) => !p).length;
|
|
431
|
-
|
|
526
|
+
noteWords = [
|
|
432
527
|
result.total > records.length ? (0, labels_1.fill)(labels.mapShowsFirst, { n: count(records.length), total: count(result.total) }) : '',
|
|
433
528
|
missing ? (0, labels_1.fill)(labels.notOnMap, { n: count(missing) }) : '',
|
|
434
529
|
].filter(Boolean);
|
|
435
|
-
|
|
436
|
-
|
|
530
|
+
nearest?.setAttribute('aria-pressed', String(isNearest()));
|
|
531
|
+
void shadeRegions(filter, asked);
|
|
437
532
|
box.ready((map, L) => {
|
|
438
533
|
if (destroyed)
|
|
439
534
|
return;
|
|
@@ -442,6 +537,7 @@ function listMap(settings, context) {
|
|
|
442
537
|
here.hidden = true;
|
|
443
538
|
}
|
|
444
539
|
draw(map, L);
|
|
540
|
+
drawSearched(map, L, filter);
|
|
445
541
|
if (open?.id !== null && open && !records.some((r) => r.id === open?.id))
|
|
446
542
|
closeCard(map, false);
|
|
447
543
|
else
|
|
@@ -471,6 +567,8 @@ function listMap(settings, context) {
|
|
|
471
567
|
},
|
|
472
568
|
destroy() {
|
|
473
569
|
destroyed = true;
|
|
570
|
+
void regions?.then((made) => made?.destroy());
|
|
571
|
+
void heat?.then((layer) => layer.destroy());
|
|
474
572
|
box.element.removeEventListener('pointerdown', pressed, { capture: true });
|
|
475
573
|
box.element.removeEventListener('keydown', keyed, { capture: true });
|
|
476
574
|
box.element.removeEventListener('wheel', wheeled, { capture: true });
|