@maptiler/geocoding-control 0.0.44 → 0.0.48
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 +18 -4
- package/dist/leaflet.js +3909 -3883
- package/dist/leaflet.umd.js +4 -24
- package/dist/lib/types.d.ts +44 -3
- package/dist/main.d.ts +1 -1
- package/dist/maplibregl.js +4014 -3993
- package/dist/maplibregl.umd.js +4 -24
- package/dist/style.css +1 -1
- package/package.json +11 -11
- package/src/lib/GeocodingControl.svelte +106 -40
- package/src/lib/MarkerIcon.svelte +21 -14
- package/src/lib/leafletMapController.ts +102 -51
- package/src/lib/maplibreglMapController.ts +93 -43
- package/src/lib/types.ts +41 -29
package/dist/style.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
div.svelte-7cmwmc{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);pointer-events:none;display:flex;align-items:center}svg.svelte-7cmwmc{animation:svelte-7cmwmc-rotate .8s infinite cubic-bezier(.45,.05,.55,.95)}@keyframes svelte-7cmwmc-rotate{0%{-webkit-transform:rotate(0);transform:rotate(0)}to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}svg.svelte-
|
|
1
|
+
div.svelte-7cmwmc{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);pointer-events:none;display:flex;align-items:center}svg.svelte-7cmwmc{animation:svelte-7cmwmc-rotate .8s infinite cubic-bezier(.45,.05,.55,.95)}@keyframes svelte-7cmwmc-rotate{0%{-webkit-transform:rotate(0);transform:rotate(0)}to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}svg.svelte-edyshv.svelte-edyshv{display:block;fill:#6b7c93;stroke:#6b7c93}.list-icon.svelte-edyshv.svelte-edyshv{grid-row:1/3;align-self:center;margin:8px}.in-map.svelte-edyshv.svelte-edyshv{height:30px}.maplibregl-canvas-container .marker-selected{z-index:1}.maplibregl-canvas-container svg.svelte-edyshv path.svelte-edyshv,.leaflet-map-pane svg.svelte-edyshv path.svelte-edyshv{fill:#3170fe;stroke:#3170fe}.marker-selected svg.svelte-edyshv path.svelte-edyshv{fill:#98b7ff;stroke:#3170fe}.marker-reverse svg.svelte-edyshv path.svelte-edyshv{fill:silver;stroke:gray}.marker-interactive{cursor:pointer!important}.marker-fuzzy svg.svelte-edyshv path.svelte-edyshv{fill:silver;stroke:gray}.marker-fuzzy.marker-selected svg.svelte-edyshv path.svelte-edyshv{fill:#ddd;stroke:silver}svg.svelte-en2qvf{display:block;fill:var(--color-icon-button)}form.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d,form.svelte-1h1zm6d .svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d,form.svelte-1h1zm6d .svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d:after,form.svelte-1h1zm6d .svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d:before{box-sizing:border-box}form.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d{font-family:Ubuntu,Open Sans,Helvetica Neue,Arial,Helvetica,sans-serif;position:relative;background-color:#fff;width:100%;z-index:10;border-radius:4px;transition:max-width .25s;box-shadow:0 2px 8px #33335926;--color-text:#333359;--color-icon-button:#333359}form.can-collapse.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d{max-width:35px}form.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d,form.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d:focus-within,form.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d:hover{max-width:240px}input.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d{font:inherit;font-size:14px;width:100%;border:0;background-color:transparent;margin:0;height:36px;color:#000000bf;white-space:nowrap;overflow:hidden;padding:0}input.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d:focus{color:#000000bf;outline:0;outline:none;box-shadow:none}ul.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d,div.error.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d,div.no-results.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d{background-color:#fff;border-radius:4px;left:0;list-style:none;margin:0;padding:0;position:absolute;width:100%;top:calc(100% + 6px);font-size:14px;box-shadow:0 2px 8px #33335926;line-height:16px;overflow:hidden}.maplibregl-ctrl-bottom-left ul.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d,.maplibregl-ctrl-bottom-right ul.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d{top:auto;bottom:100%}li.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d{cursor:default;display:grid;grid-template-columns:auto 1fr;color:var(--color-text);padding:4px 0}li.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d:first-child{padding-top:8px}li.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d:last-child{padding-bottom:8px}li.svelte-1h1zm6d>span.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d{overflow:hidden;padding-right:8px}li.svelte-1h1zm6d>span.svelte-1h1zm6d>span.svelte-1h1zm6d.svelte-1h1zm6d{white-space:nowrap;display:block;min-width:fit-content}li.selected.svelte-1h1zm6d>span.svelte-1h1zm6d>span.svelte-1h1zm6d.svelte-1h1zm6d{animation:svelte-1h1zm6d-backAndForth 5s linear infinite}li.svelte-1h1zm6d>span.svelte-1h1zm6d:nth-of-type(1)>span.svelte-1h1zm6d>span.svelte-1h1zm6d:nth-of-type(1){font-weight:700}li.svelte-1h1zm6d>span.svelte-1h1zm6d:nth-of-type(1)>span.svelte-1h1zm6d>span.svelte-1h1zm6d:nth-of-type(2){color:#aeb6c7;font-size:12px;padding-left:4px}li.selected.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d{background-color:#f3f3f3}button.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d:hover{background-color:transparent}button.svelte-1h1zm6d:hover svg,button.active.svelte-1h1zm6d svg{fill:#6b7c92}button.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d{padding:0;margin:0;border:0;background-color:transparent}.input-group.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d{display:flex;align-items:stretch;gap:7px;padding-inline:8px;outline:#c1cfe4 solid 2px;border-radius:4px;overflow:hidden}.input-group.svelte-1h1zm6d:hover .displayable.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d{visibility:visible}.input-group.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d:focus-within{outline:#3170fe solid 2px}div.error.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d,div.no-results.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d{font:inherit;font-size:14px;padding:6px 10px}div.error.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d{color:#e25041}div.no-results.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d{color:var(--color-text)}.clear-button-container.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d{position:relative;display:flex;align-items:stretch}.clear-button-container.svelte-1h1zm6d button.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d{visibility:hidden}@keyframes svelte-1h1zm6d-backAndForth{0%{transform:translate(0)}10%{transform:translate(0)}45%{transform:translate(calc(-100% + 196px))}55%{transform:translate(calc(-100% + 196px))}90%{transform:translate(0)}to{transform:translate(0)}}form.can-collapse.svelte-1h1zm6d button.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d:not(:nth-of-type(1)){opacity:0;transition:opacity .25s}form.can-collapse.svelte-1h1zm6d:focus-within .svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d:not(:nth-of-type(1)),form.can-collapse.svelte-1h1zm6d:hover .svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d:not(:nth-of-type(1)){opacity:1}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maptiler/geocoding-control",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.48",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Martin Ždila",
|
|
@@ -43,24 +43,24 @@
|
|
|
43
43
|
},
|
|
44
44
|
"types": "./dist/lib/index.d.ts",
|
|
45
45
|
"devDependencies": {
|
|
46
|
-
"@sveltejs/vite-plugin-svelte": "^
|
|
46
|
+
"@sveltejs/vite-plugin-svelte": "^2.0.2",
|
|
47
47
|
"@tsconfig/svelte": "^3.0.0",
|
|
48
48
|
"@turf/buffer": "^6.5.0",
|
|
49
49
|
"@turf/difference": "^6.5.0",
|
|
50
50
|
"@turf/union": "^6.5.0",
|
|
51
51
|
"@types/leaflet": "^1.9.0",
|
|
52
|
-
"prettier": "^2.8.
|
|
53
|
-
"prettier-plugin-svelte": "^2.
|
|
54
|
-
"svelte": "^3.
|
|
55
|
-
"svelte-check": "^2.
|
|
56
|
-
"svelte-preprocess": "^
|
|
52
|
+
"prettier": "^2.8.1",
|
|
53
|
+
"prettier-plugin-svelte": "^2.9.0",
|
|
54
|
+
"svelte": "^3.55.0",
|
|
55
|
+
"svelte-check": "^2.10.2",
|
|
56
|
+
"svelte-preprocess": "^5.0.0",
|
|
57
57
|
"tslib": "^2.4.1",
|
|
58
|
-
"typescript": "^4.9.
|
|
59
|
-
"vite": "^
|
|
58
|
+
"typescript": "^4.9.4",
|
|
59
|
+
"vite": "^4.0.2"
|
|
60
60
|
},
|
|
61
61
|
"peerDependencies": {
|
|
62
|
-
"leaflet": "^1.9.
|
|
63
|
-
"maplibre-gl": "
|
|
62
|
+
"leaflet": "^1.9.3",
|
|
63
|
+
"maplibre-gl": "^2.4.0"
|
|
64
64
|
},
|
|
65
65
|
"peerDependenciesMeta": {
|
|
66
66
|
"leaflet": {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<script
|
|
1
|
+
<script lang="ts">
|
|
2
2
|
import { createEventDispatcher } from "svelte";
|
|
3
3
|
import { onDestroy } from "svelte/internal";
|
|
4
4
|
import ReverseGeocodingIcon from "./ReverseGeocodingIcon.svelte";
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
|
|
38
38
|
export let minLength = 2;
|
|
39
39
|
|
|
40
|
-
export let language: string | undefined = undefined;
|
|
40
|
+
export let language: string | string[] | undefined = undefined;
|
|
41
41
|
|
|
42
42
|
export let showResultsWhileTyping = true;
|
|
43
43
|
|
|
@@ -65,11 +65,13 @@
|
|
|
65
65
|
|
|
66
66
|
export let showFullGeometry = true;
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
export let limit: number | undefined = undefined;
|
|
69
69
|
|
|
70
|
-
|
|
70
|
+
export let fuzzyMatch = true;
|
|
71
71
|
|
|
72
|
-
|
|
72
|
+
export let countries: string | string[] | undefined = undefined;
|
|
73
|
+
|
|
74
|
+
export let types: string[] | undefined = undefined;
|
|
73
75
|
|
|
74
76
|
export function focus() {
|
|
75
77
|
input.focus();
|
|
@@ -116,7 +118,7 @@
|
|
|
116
118
|
|
|
117
119
|
let abortController: AbortController | undefined;
|
|
118
120
|
|
|
119
|
-
let searchTimeoutRef: number;
|
|
121
|
+
let searchTimeoutRef: number | undefined;
|
|
120
122
|
|
|
121
123
|
let focusedDelayed: boolean;
|
|
122
124
|
|
|
@@ -131,16 +133,6 @@
|
|
|
131
133
|
queryChange: string;
|
|
132
134
|
}>();
|
|
133
135
|
|
|
134
|
-
$: if (mapController) {
|
|
135
|
-
mapController.setProximityChangeHandler(
|
|
136
|
-
trackProximity
|
|
137
|
-
? (p) => {
|
|
138
|
-
proximity = p;
|
|
139
|
-
}
|
|
140
|
-
: undefined
|
|
141
|
-
);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
136
|
$: if (!trackProximity) {
|
|
145
137
|
proximity = undefined;
|
|
146
138
|
}
|
|
@@ -151,7 +143,7 @@
|
|
|
151
143
|
!picked.address &&
|
|
152
144
|
picked.geometry.type === "Point"
|
|
153
145
|
) {
|
|
154
|
-
search(picked.id, true).catch((err) => (error = err));
|
|
146
|
+
search(picked.id, { byId: true }).catch((err) => (error = err));
|
|
155
147
|
}
|
|
156
148
|
|
|
157
149
|
$: if (mapController && picked && flyTo) {
|
|
@@ -205,6 +197,14 @@
|
|
|
205
197
|
|
|
206
198
|
$: selected = listFeatures?.[selectedItemIndex];
|
|
207
199
|
|
|
200
|
+
$: {
|
|
201
|
+
const m = /^(-?\d+(?:\.\d*)?),(-?\d+(?:\.\d*)?)$/.exec(searchValue);
|
|
202
|
+
|
|
203
|
+
mapController?.setReverseMarker(
|
|
204
|
+
m ? [Number(m[1]), Number(m[2])] : undefined
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
208
|
$: dispatch("select", selected);
|
|
209
209
|
|
|
210
210
|
$: dispatch("pick", picked);
|
|
@@ -224,13 +224,47 @@
|
|
|
224
224
|
}
|
|
225
225
|
|
|
226
226
|
$: if (mapController) {
|
|
227
|
-
mapController.
|
|
227
|
+
mapController.setEventHandler((e) => {
|
|
228
|
+
switch (e.type) {
|
|
229
|
+
case "mapClick":
|
|
230
|
+
if (reverseActive) {
|
|
231
|
+
handleReverse(e.coordinates);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
break;
|
|
235
|
+
case "proximityChange":
|
|
236
|
+
proximity = trackProximity ? e.proximity : undefined;
|
|
237
|
+
|
|
238
|
+
break;
|
|
239
|
+
case "markerClick":
|
|
240
|
+
{
|
|
241
|
+
const feature = listFeatures?.find(
|
|
242
|
+
(feature) => feature.id === e.id
|
|
243
|
+
);
|
|
244
|
+
|
|
245
|
+
if (feature) {
|
|
246
|
+
pick(feature);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
break;
|
|
251
|
+
case "markerMouseEnter":
|
|
252
|
+
selectedItemIndex = !focusedDelayed
|
|
253
|
+
? -1
|
|
254
|
+
: listFeatures?.findIndex((feature) => feature.id === e.id) ?? -1;
|
|
255
|
+
|
|
256
|
+
break;
|
|
257
|
+
case "markerMouseLeave":
|
|
258
|
+
selectedItemIndex = -1;
|
|
259
|
+
|
|
260
|
+
break;
|
|
261
|
+
}
|
|
262
|
+
});
|
|
228
263
|
}
|
|
229
264
|
|
|
230
265
|
onDestroy(() => {
|
|
231
266
|
if (mapController) {
|
|
232
|
-
mapController.
|
|
233
|
-
mapController.setMapClickHandler(undefined);
|
|
267
|
+
mapController.setEventHandler(undefined);
|
|
234
268
|
mapController.indicateReverse(false);
|
|
235
269
|
mapController.setSelectedMarker(-1);
|
|
236
270
|
mapController.setMarkers(undefined, undefined);
|
|
@@ -238,6 +272,12 @@
|
|
|
238
272
|
});
|
|
239
273
|
|
|
240
274
|
function handleOnSubmit(event?: unknown) {
|
|
275
|
+
if (searchTimeoutRef) {
|
|
276
|
+
clearTimeout(searchTimeoutRef);
|
|
277
|
+
|
|
278
|
+
searchTimeoutRef = undefined;
|
|
279
|
+
}
|
|
280
|
+
|
|
241
281
|
if (selectedItemIndex > -1 && listFeatures) {
|
|
242
282
|
picked = listFeatures[selectedItemIndex];
|
|
243
283
|
searchValue = picked.place_name.replace(/,.*/, "");
|
|
@@ -247,7 +287,7 @@
|
|
|
247
287
|
} else if (searchValue) {
|
|
248
288
|
const zoomTo = event || !isQuerReverse();
|
|
249
289
|
|
|
250
|
-
search(searchValue)
|
|
290
|
+
search(searchValue, { exact: true })
|
|
251
291
|
.then(() => {
|
|
252
292
|
markedFeatures = listFeatures;
|
|
253
293
|
|
|
@@ -265,7 +305,13 @@
|
|
|
265
305
|
return /^-?\d+(\.\d+)?,-?\d+(\.\d+)?$/.test(searchValue);
|
|
266
306
|
}
|
|
267
307
|
|
|
268
|
-
async function search(
|
|
308
|
+
async function search(
|
|
309
|
+
searchValue: string,
|
|
310
|
+
{
|
|
311
|
+
byId = false,
|
|
312
|
+
exact = false,
|
|
313
|
+
}: undefined | { byId?: boolean; exact?: boolean } = {}
|
|
314
|
+
) {
|
|
269
315
|
error = undefined;
|
|
270
316
|
|
|
271
317
|
const isReverse = isQuerReverse();
|
|
@@ -273,7 +319,21 @@
|
|
|
273
319
|
const sp = new URLSearchParams();
|
|
274
320
|
|
|
275
321
|
if (language) {
|
|
276
|
-
sp.set(
|
|
322
|
+
sp.set(
|
|
323
|
+
"language",
|
|
324
|
+
Array.isArray(language) ? language.join(",") : language
|
|
325
|
+
);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
if (countries) {
|
|
329
|
+
sp.set(
|
|
330
|
+
"stack",
|
|
331
|
+
Array.isArray(countries) ? countries.join(",") : countries
|
|
332
|
+
);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
if (types) {
|
|
336
|
+
sp.set("types", types.join(","));
|
|
277
337
|
}
|
|
278
338
|
|
|
279
339
|
if (!isReverse) {
|
|
@@ -285,12 +345,16 @@
|
|
|
285
345
|
sp.set("proximity", proximity.map((c) => c.toFixed(6)).join(","));
|
|
286
346
|
}
|
|
287
347
|
|
|
288
|
-
|
|
348
|
+
if (exact || !showResultsWhileTyping) {
|
|
349
|
+
sp.set("autocomplete", "false");
|
|
350
|
+
}
|
|
289
351
|
|
|
290
|
-
|
|
352
|
+
sp.set("fuzzyMatch", String(fuzzyMatch));
|
|
291
353
|
}
|
|
292
354
|
|
|
293
|
-
|
|
355
|
+
if (limit !== undefined) {
|
|
356
|
+
sp.set("limit", String(limit));
|
|
357
|
+
}
|
|
294
358
|
|
|
295
359
|
sp.set("key", apiKey);
|
|
296
360
|
|
|
@@ -365,11 +429,15 @@
|
|
|
365
429
|
|
|
366
430
|
const bbox: [number, number, number, number] = [180, 90, -180, -90];
|
|
367
431
|
|
|
432
|
+
const fuzzyOnly = !markedFeatures.some((feature) => !feature.matching_text);
|
|
433
|
+
|
|
368
434
|
for (const feature of markedFeatures) {
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
435
|
+
if (fuzzyOnly || !feature.matching_text) {
|
|
436
|
+
bbox[0] = Math.min(bbox[0], feature.bbox?.[0] ?? feature.center[0]);
|
|
437
|
+
bbox[1] = Math.min(bbox[1], feature.bbox?.[1] ?? feature.center[1]);
|
|
438
|
+
bbox[2] = Math.max(bbox[2], feature.bbox?.[2] ?? feature.center[0]);
|
|
439
|
+
bbox[3] = Math.max(bbox[3], feature.bbox?.[3] ?? feature.center[1]);
|
|
440
|
+
}
|
|
373
441
|
}
|
|
374
442
|
|
|
375
443
|
if (mapController && markedFeatures.length > 0) {
|
|
@@ -382,11 +450,7 @@
|
|
|
382
450
|
}
|
|
383
451
|
|
|
384
452
|
// taken from Leaflet
|
|
385
|
-
|
|
386
|
-
x: number,
|
|
387
|
-
range: [number, number],
|
|
388
|
-
includeMax: boolean
|
|
389
|
-
) {
|
|
453
|
+
function wrapNum(x: number, range: [number, number], includeMax: boolean) {
|
|
390
454
|
const max = range[1],
|
|
391
455
|
min = range[0],
|
|
392
456
|
d = max - min;
|
|
@@ -447,6 +511,12 @@
|
|
|
447
511
|
error = undefined;
|
|
448
512
|
}
|
|
449
513
|
}
|
|
514
|
+
|
|
515
|
+
function pick(feature: Feature) {
|
|
516
|
+
picked = feature;
|
|
517
|
+
searchValue = feature.place_name.replace(/,.*/, "");
|
|
518
|
+
selectedItemIndex = -1;
|
|
519
|
+
}
|
|
450
520
|
</script>
|
|
451
521
|
|
|
452
522
|
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
|
|
@@ -519,11 +589,7 @@
|
|
|
519
589
|
data-selected={selectedItemIndex === i}
|
|
520
590
|
class:selected={selectedItemIndex === i}
|
|
521
591
|
on:mouseover={() => (selectedItemIndex = i)}
|
|
522
|
-
on:focus={() =>
|
|
523
|
-
picked = feature;
|
|
524
|
-
searchValue = feature.place_name.replace(/,.*/, "");
|
|
525
|
-
selectedItemIndex = -1;
|
|
526
|
-
}}
|
|
592
|
+
on:focus={() => pick(feature)}
|
|
527
593
|
>
|
|
528
594
|
<MarkerIcon displayIn="list" />
|
|
529
595
|
<span>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<script
|
|
1
|
+
<script lang="ts">
|
|
2
2
|
export let displayIn: "list" | "leaflet" | "maplibre";
|
|
3
3
|
</script>
|
|
4
4
|
|
|
@@ -7,8 +7,6 @@
|
|
|
7
7
|
viewBox="0 0 70 85"
|
|
8
8
|
fill="none"
|
|
9
9
|
class:in-map={displayIn !== "list"}
|
|
10
|
-
class:for-maplibre={displayIn === "maplibre"}
|
|
11
|
-
class:for-leaflet={displayIn === "leaflet"}
|
|
12
10
|
class:list-icon={displayIn === "list"}
|
|
13
11
|
>
|
|
14
12
|
<path
|
|
@@ -21,6 +19,7 @@
|
|
|
21
19
|
|
|
22
20
|
<style>
|
|
23
21
|
svg {
|
|
22
|
+
display: block;
|
|
24
23
|
fill: #6b7c93;
|
|
25
24
|
stroke: #6b7c93;
|
|
26
25
|
}
|
|
@@ -35,17 +34,6 @@
|
|
|
35
34
|
height: 30px;
|
|
36
35
|
}
|
|
37
36
|
|
|
38
|
-
.for-maplibre {
|
|
39
|
-
position: relative;
|
|
40
|
-
top: -10px;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
.for-leaflet {
|
|
44
|
-
position: relative;
|
|
45
|
-
top: -23px;
|
|
46
|
-
left: -50%;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
37
|
:global(.maplibregl-canvas-container .marker-selected) {
|
|
50
38
|
z-index: 1;
|
|
51
39
|
}
|
|
@@ -60,4 +48,23 @@
|
|
|
60
48
|
fill: #98b7ff;
|
|
61
49
|
stroke: #3170fe;
|
|
62
50
|
}
|
|
51
|
+
|
|
52
|
+
:global(.marker-reverse) svg path {
|
|
53
|
+
fill: silver;
|
|
54
|
+
stroke: gray;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
:global(.marker-interactive) {
|
|
58
|
+
cursor: pointer !important;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
:global(.marker-fuzzy) svg path {
|
|
62
|
+
fill: silver;
|
|
63
|
+
stroke: gray;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
:global(.marker-fuzzy.marker-selected) svg path {
|
|
67
|
+
fill: #ddd;
|
|
68
|
+
stroke: silver;
|
|
69
|
+
}
|
|
63
70
|
</style>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as L from "leaflet";
|
|
2
2
|
import MarkerIcon from "./MarkerIcon.svelte";
|
|
3
|
-
import type { Feature, MapController, Proximity } from "./types";
|
|
3
|
+
import type { Feature, MapController, MapEvent, Proximity } from "./types";
|
|
4
4
|
import type {
|
|
5
5
|
Polygon,
|
|
6
6
|
MultiPolygon,
|
|
@@ -35,9 +35,7 @@ export function createLeafletMapController(
|
|
|
35
35
|
};
|
|
36
36
|
}
|
|
37
37
|
) {
|
|
38
|
-
let
|
|
39
|
-
|
|
40
|
-
let mapClickHandler: ((coordinates: [number, number]) => void) | undefined;
|
|
38
|
+
let eventHandler: ((e: MapEvent) => void) | undefined;
|
|
41
39
|
|
|
42
40
|
let prevProximity: Proximity = undefined;
|
|
43
41
|
|
|
@@ -45,17 +43,14 @@ export function createLeafletMapController(
|
|
|
45
43
|
|
|
46
44
|
let selectedMarker: L.Marker | undefined;
|
|
47
45
|
|
|
46
|
+
let reverseMarker: L.Marker | undefined;
|
|
47
|
+
|
|
48
48
|
let resultLayer = L.geoJSON(undefined, {
|
|
49
49
|
style: fullGeometryStyle,
|
|
50
|
+
interactive: false,
|
|
50
51
|
}).addTo(map);
|
|
51
52
|
|
|
52
53
|
const handleMoveEnd = () => {
|
|
53
|
-
if (!proximityChangeHandler) {
|
|
54
|
-
prevProximity = undefined;
|
|
55
|
-
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
54
|
let c: L.LatLng;
|
|
60
55
|
|
|
61
56
|
const proximity =
|
|
@@ -66,47 +61,55 @@ export function createLeafletMapController(
|
|
|
66
61
|
if (prevProximity !== proximity) {
|
|
67
62
|
prevProximity = proximity;
|
|
68
63
|
|
|
69
|
-
|
|
64
|
+
eventHandler?.({ type: "proximityChange", proximity });
|
|
70
65
|
}
|
|
71
66
|
};
|
|
72
67
|
|
|
73
68
|
const handleMapClick = (e: L.LeafletMouseEvent) => {
|
|
74
|
-
|
|
69
|
+
eventHandler?.({
|
|
70
|
+
type: "mapClick",
|
|
71
|
+
coordinates: [e.latlng.lng, e.latlng.lat],
|
|
72
|
+
});
|
|
75
73
|
};
|
|
76
74
|
|
|
75
|
+
function createMarker(pos: L.LatLngExpression, interactive = false) {
|
|
76
|
+
const element = document.createElement("div");
|
|
77
|
+
|
|
78
|
+
new MarkerIcon({ props: { displayIn: "leaflet" }, target: element });
|
|
79
|
+
|
|
80
|
+
return new L.Marker(pos, {
|
|
81
|
+
interactive,
|
|
82
|
+
icon: new L.DivIcon({
|
|
83
|
+
html: element,
|
|
84
|
+
className: "",
|
|
85
|
+
iconAnchor: [12, 26],
|
|
86
|
+
}),
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
77
90
|
const ctrl: MapController = {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
if (_proximityChangeHandler) {
|
|
82
|
-
proximityChangeHandler = _proximityChangeHandler;
|
|
91
|
+
setEventHandler(handler: undefined | ((e: MapEvent) => void)): void {
|
|
92
|
+
if (handler) {
|
|
93
|
+
eventHandler = handler;
|
|
83
94
|
|
|
84
95
|
map.on("moveend", handleMoveEnd);
|
|
85
96
|
|
|
86
97
|
handleMoveEnd();
|
|
98
|
+
|
|
99
|
+
map.on("click", handleMapClick);
|
|
87
100
|
} else {
|
|
88
101
|
map.off("moveend", handleMoveEnd);
|
|
89
102
|
|
|
90
|
-
|
|
103
|
+
eventHandler?.({ type: "proximityChange", proximity: undefined });
|
|
91
104
|
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
},
|
|
95
|
-
|
|
96
|
-
setMapClickHandler(
|
|
97
|
-
_mapClickHandler: ((coordinates: [number, number]) => void) | undefined
|
|
98
|
-
): void {
|
|
99
|
-
mapClickHandler = _mapClickHandler;
|
|
105
|
+
eventHandler = undefined;
|
|
100
106
|
|
|
101
|
-
if (mapClickHandler) {
|
|
102
|
-
map.on("click", handleMapClick);
|
|
103
|
-
} else {
|
|
104
107
|
map.off("click", handleMapClick);
|
|
105
108
|
}
|
|
106
109
|
},
|
|
107
110
|
|
|
108
111
|
flyTo(center: [number, number], zoom: number) {
|
|
109
|
-
map.flyTo(center, zoom, { duration: 2, ...flyToOptions });
|
|
112
|
+
map.flyTo([center[1], center[0]], zoom, { duration: 2, ...flyToOptions });
|
|
110
113
|
},
|
|
111
114
|
|
|
112
115
|
fitBounds(bbox: [number, number, number, number], padding: number): void {
|
|
@@ -123,10 +126,41 @@ export function createLeafletMapController(
|
|
|
123
126
|
map.getContainer().style.cursor = reverse ? "crosshair" : "";
|
|
124
127
|
},
|
|
125
128
|
|
|
129
|
+
setReverseMarker(coordinates: [number, number]) {
|
|
130
|
+
if (!marker) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const latLng =
|
|
135
|
+
coordinates && ([coordinates[1], coordinates[0]] as [number, number]);
|
|
136
|
+
|
|
137
|
+
if (reverseMarker) {
|
|
138
|
+
if (!latLng) {
|
|
139
|
+
reverseMarker.remove();
|
|
140
|
+
|
|
141
|
+
reverseMarker = undefined;
|
|
142
|
+
} else {
|
|
143
|
+
reverseMarker.setLatLng(latLng);
|
|
144
|
+
}
|
|
145
|
+
} else if (latLng) {
|
|
146
|
+
reverseMarker = (
|
|
147
|
+
typeof marker === "object"
|
|
148
|
+
? new L.Marker(latLng, marker)
|
|
149
|
+
: createMarker(latLng)
|
|
150
|
+
).addTo(map);
|
|
151
|
+
|
|
152
|
+
reverseMarker.getElement()?.classList.add("marker-reverse");
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
|
|
126
156
|
setMarkers(
|
|
127
157
|
markedFeatures: Feature[] | undefined,
|
|
128
158
|
picked: Feature | undefined
|
|
129
159
|
): void {
|
|
160
|
+
if (!marker) {
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
|
|
130
164
|
function setData(data?: GeoJSON.GeoJSON) {
|
|
131
165
|
resultLayer.clearLayers();
|
|
132
166
|
|
|
@@ -143,16 +177,6 @@ export function createLeafletMapController(
|
|
|
143
177
|
|
|
144
178
|
setData();
|
|
145
179
|
|
|
146
|
-
const createMarker = (pos: L.LatLngExpression) => {
|
|
147
|
-
const element = document.createElement("div");
|
|
148
|
-
|
|
149
|
-
new MarkerIcon({ props: { displayIn: "leaflet" }, target: element });
|
|
150
|
-
|
|
151
|
-
return new L.Marker(pos, {
|
|
152
|
-
icon: new L.DivIcon({ html: element, className: "" }),
|
|
153
|
-
});
|
|
154
|
-
};
|
|
155
|
-
|
|
156
180
|
if (picked) {
|
|
157
181
|
let handled = false;
|
|
158
182
|
|
|
@@ -218,19 +242,46 @@ export function createLeafletMapController(
|
|
|
218
242
|
);
|
|
219
243
|
}
|
|
220
244
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
245
|
+
if (showResultMarkers) {
|
|
246
|
+
for (const feature of markedFeatures ?? []) {
|
|
247
|
+
if (feature === picked) {
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
225
250
|
|
|
226
|
-
|
|
251
|
+
const pos: L.LatLngExpression = [
|
|
252
|
+
feature.center[1],
|
|
253
|
+
feature.center[0],
|
|
254
|
+
];
|
|
227
255
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
256
|
+
const marker =
|
|
257
|
+
typeof showResultMarkers === "object"
|
|
258
|
+
? new L.Marker(pos, showResultMarkers)
|
|
259
|
+
: createMarker(pos, true);
|
|
260
|
+
|
|
261
|
+
marker.addTo(map);
|
|
262
|
+
|
|
263
|
+
const element = marker.getElement();
|
|
264
|
+
|
|
265
|
+
if (element) {
|
|
266
|
+
element.addEventListener("click", (e) => {
|
|
267
|
+
e.stopPropagation();
|
|
268
|
+
|
|
269
|
+
eventHandler?.({ type: "markerClick", id: feature.id });
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
element.addEventListener("mouseenter", () => {
|
|
273
|
+
eventHandler?.({ type: "markerMouseEnter", id: feature.id });
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
element.addEventListener("mouseleave", () => {
|
|
277
|
+
eventHandler?.({ type: "markerMouseLeave", id: feature.id });
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
element.classList.toggle("marker-fuzzy", !!feature.matching_text);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
markers.push(marker);
|
|
284
|
+
}
|
|
234
285
|
}
|
|
235
286
|
},
|
|
236
287
|
|