@maptiler/geocoding-control 0.0.44 → 0.0.52
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/index.d.ts +0 -0
- package/dist/leaflet.js +3927 -3891
- package/dist/leaflet.umd.js +4 -24
- package/dist/lib/types.d.ts +44 -3
- package/dist/maplibregl.js +4002 -3968
- package/dist/maplibregl.umd.js +4 -24
- package/dist/style.css +1 -1
- package/package.json +15 -13
- package/src/lib/GeocodingControl.svelte +108 -43
- package/src/lib/MarkerIcon.svelte +25 -14
- package/src/lib/leafletMapController.ts +108 -51
- package/src/lib/maplibreglMapController.ts +104 -42
- 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-1k1cmht.svelte-1k1cmht{display:block;fill:#6b7c93;stroke:#6b7c93}.list-icon.svelte-1k1cmht.svelte-1k1cmht{grid-row:1/3;align-self:center;margin:8px}.in-map.svelte-1k1cmht.svelte-1k1cmht{height:30px}.maplibregl-canvas-container .marker-selected{z-index:1}.maplibregl-canvas-container svg.svelte-1k1cmht path.svelte-1k1cmht,.leaflet-map-pane svg.svelte-1k1cmht path.svelte-1k1cmht{fill:#3170fe;stroke:#3170fe}.marker-selected svg.svelte-1k1cmht path.svelte-1k1cmht{fill:#98b7ff;stroke:#3170fe}.marker-reverse svg.svelte-1k1cmht path.svelte-1k1cmht{fill:silver;stroke:gray}.marker-interactive{cursor:pointer!important}.marker-fuzzy svg.svelte-1k1cmht path.svelte-1k1cmht{fill:silver;stroke:gray}.marker-fuzzy.marker-selected svg.svelte-1k1cmht path.svelte-1k1cmht{fill:#ddd;stroke:silver}.maptiler-gc-popup>.maplibregl-popup-content{padding:2px 8px}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.52",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Martin Ždila",
|
|
@@ -26,11 +26,13 @@
|
|
|
26
26
|
"exports": {
|
|
27
27
|
"./leaflet": {
|
|
28
28
|
"import": "./dist/leaflet.js",
|
|
29
|
-
"require": "./dist/leaflet.umd.js"
|
|
29
|
+
"require": "./dist/leaflet.umd.js",
|
|
30
|
+
"types": "./dist/lib/LeafletGeocodingControl.d.ts"
|
|
30
31
|
},
|
|
31
32
|
"./maplibregl": {
|
|
32
33
|
"import": "./dist/maplibregl.js",
|
|
33
|
-
"require": "./dist/maplibregl.umd.js"
|
|
34
|
+
"require": "./dist/maplibregl.umd.js",
|
|
35
|
+
"types": "./dist/lib/MaplibreglGeocodingControl.d.ts"
|
|
34
36
|
},
|
|
35
37
|
"./dist/style.css": {
|
|
36
38
|
"import": "./dist/style.css",
|
|
@@ -43,24 +45,24 @@
|
|
|
43
45
|
},
|
|
44
46
|
"types": "./dist/lib/index.d.ts",
|
|
45
47
|
"devDependencies": {
|
|
46
|
-
"@sveltejs/vite-plugin-svelte": "^
|
|
48
|
+
"@sveltejs/vite-plugin-svelte": "^2.0.2",
|
|
47
49
|
"@tsconfig/svelte": "^3.0.0",
|
|
48
50
|
"@turf/buffer": "^6.5.0",
|
|
49
51
|
"@turf/difference": "^6.5.0",
|
|
50
52
|
"@turf/union": "^6.5.0",
|
|
51
53
|
"@types/leaflet": "^1.9.0",
|
|
52
|
-
"prettier": "^2.8.
|
|
53
|
-
"prettier-plugin-svelte": "^2.
|
|
54
|
-
"svelte": "^3.
|
|
55
|
-
"svelte-check": "^
|
|
56
|
-
"svelte-preprocess": "^
|
|
54
|
+
"prettier": "^2.8.3",
|
|
55
|
+
"prettier-plugin-svelte": "^2.9.0",
|
|
56
|
+
"svelte": "^3.55.1",
|
|
57
|
+
"svelte-check": "^3.0.2",
|
|
58
|
+
"svelte-preprocess": "^5.0.0",
|
|
57
59
|
"tslib": "^2.4.1",
|
|
58
|
-
"typescript": "^4.9.
|
|
59
|
-
"vite": "^
|
|
60
|
+
"typescript": "^4.9.4",
|
|
61
|
+
"vite": "^4.0.4"
|
|
60
62
|
},
|
|
61
63
|
"peerDependencies": {
|
|
62
|
-
"leaflet": "^1.9.
|
|
63
|
-
"maplibre-gl": "
|
|
64
|
+
"leaflet": "^1.9.3",
|
|
65
|
+
"maplibre-gl": "^2.4.0"
|
|
64
66
|
},
|
|
65
67
|
"peerDependenciesMeta": {
|
|
66
68
|
"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 country: 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,18 @@
|
|
|
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 (country) {
|
|
329
|
+
sp.set("country", Array.isArray(country) ? country.join(",") : country);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
if (types) {
|
|
333
|
+
sp.set("types", types.join(","));
|
|
277
334
|
}
|
|
278
335
|
|
|
279
336
|
if (!isReverse) {
|
|
@@ -285,12 +342,16 @@
|
|
|
285
342
|
sp.set("proximity", proximity.map((c) => c.toFixed(6)).join(","));
|
|
286
343
|
}
|
|
287
344
|
|
|
288
|
-
|
|
345
|
+
if (exact || !showResultsWhileTyping) {
|
|
346
|
+
sp.set("autocomplete", "false");
|
|
347
|
+
}
|
|
289
348
|
|
|
290
|
-
|
|
349
|
+
sp.set("fuzzyMatch", String(fuzzyMatch));
|
|
291
350
|
}
|
|
292
351
|
|
|
293
|
-
|
|
352
|
+
if (limit !== undefined) {
|
|
353
|
+
sp.set("limit", String(limit));
|
|
354
|
+
}
|
|
294
355
|
|
|
295
356
|
sp.set("key", apiKey);
|
|
296
357
|
|
|
@@ -365,11 +426,15 @@
|
|
|
365
426
|
|
|
366
427
|
const bbox: [number, number, number, number] = [180, 90, -180, -90];
|
|
367
428
|
|
|
429
|
+
const fuzzyOnly = !markedFeatures.some((feature) => !feature.matching_text);
|
|
430
|
+
|
|
368
431
|
for (const feature of markedFeatures) {
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
432
|
+
if (fuzzyOnly || !feature.matching_text) {
|
|
433
|
+
bbox[0] = Math.min(bbox[0], feature.bbox?.[0] ?? feature.center[0]);
|
|
434
|
+
bbox[1] = Math.min(bbox[1], feature.bbox?.[1] ?? feature.center[1]);
|
|
435
|
+
bbox[2] = Math.max(bbox[2], feature.bbox?.[2] ?? feature.center[0]);
|
|
436
|
+
bbox[3] = Math.max(bbox[3], feature.bbox?.[3] ?? feature.center[1]);
|
|
437
|
+
}
|
|
373
438
|
}
|
|
374
439
|
|
|
375
440
|
if (mapController && markedFeatures.length > 0) {
|
|
@@ -382,11 +447,7 @@
|
|
|
382
447
|
}
|
|
383
448
|
|
|
384
449
|
// taken from Leaflet
|
|
385
|
-
|
|
386
|
-
x: number,
|
|
387
|
-
range: [number, number],
|
|
388
|
-
includeMax: boolean
|
|
389
|
-
) {
|
|
450
|
+
function wrapNum(x: number, range: [number, number], includeMax: boolean) {
|
|
390
451
|
const max = range[1],
|
|
391
452
|
min = range[0],
|
|
392
453
|
d = max - min;
|
|
@@ -447,6 +508,14 @@
|
|
|
447
508
|
error = undefined;
|
|
448
509
|
}
|
|
449
510
|
}
|
|
511
|
+
|
|
512
|
+
function pick(feature: Feature) {
|
|
513
|
+
console.log(feature);
|
|
514
|
+
|
|
515
|
+
picked = feature;
|
|
516
|
+
searchValue = feature.place_name;
|
|
517
|
+
selectedItemIndex = -1;
|
|
518
|
+
}
|
|
450
519
|
</script>
|
|
451
520
|
|
|
452
521
|
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
|
|
@@ -504,10 +573,10 @@
|
|
|
504
573
|
<slot />
|
|
505
574
|
</div>
|
|
506
575
|
|
|
507
|
-
{#if
|
|
508
|
-
{""}
|
|
509
|
-
{:else if error}
|
|
576
|
+
{#if error}
|
|
510
577
|
<div class="error">{errorMessage}</div>
|
|
578
|
+
{:else if !focusedDelayed}
|
|
579
|
+
{""}
|
|
511
580
|
{:else if listFeatures?.length === 0}
|
|
512
581
|
<div class="no-results">{noResultsMessage}</div>
|
|
513
582
|
{:else if focusedDelayed && listFeatures?.length}
|
|
@@ -519,11 +588,7 @@
|
|
|
519
588
|
data-selected={selectedItemIndex === i}
|
|
520
589
|
class:selected={selectedItemIndex === i}
|
|
521
590
|
on:mouseover={() => (selectedItemIndex = i)}
|
|
522
|
-
on:focus={() =>
|
|
523
|
-
picked = feature;
|
|
524
|
-
searchValue = feature.place_name.replace(/,.*/, "");
|
|
525
|
-
selectedItemIndex = -1;
|
|
526
|
-
}}
|
|
591
|
+
on:focus={() => pick(feature)}
|
|
527
592
|
>
|
|
528
593
|
<MarkerIcon displayIn="list" />
|
|
529
594
|
<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,27 @@
|
|
|
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
|
+
}
|
|
70
|
+
|
|
71
|
+
:global(.maptiler-gc-popup > .maplibregl-popup-content) {
|
|
72
|
+
padding: 2px 8px;
|
|
73
|
+
}
|
|
63
74
|
</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,57 @@ 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
|
+
iconSize: [25, 30],
|
|
87
|
+
tooltipAnchor: [1, -24],
|
|
88
|
+
}),
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
77
92
|
const ctrl: MapController = {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
if (_proximityChangeHandler) {
|
|
82
|
-
proximityChangeHandler = _proximityChangeHandler;
|
|
93
|
+
setEventHandler(handler: undefined | ((e: MapEvent) => void)): void {
|
|
94
|
+
if (handler) {
|
|
95
|
+
eventHandler = handler;
|
|
83
96
|
|
|
84
97
|
map.on("moveend", handleMoveEnd);
|
|
85
98
|
|
|
86
99
|
handleMoveEnd();
|
|
100
|
+
|
|
101
|
+
map.on("click", handleMapClick);
|
|
87
102
|
} else {
|
|
88
103
|
map.off("moveend", handleMoveEnd);
|
|
89
104
|
|
|
90
|
-
|
|
105
|
+
eventHandler?.({ type: "proximityChange", proximity: undefined });
|
|
91
106
|
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
},
|
|
107
|
+
eventHandler = undefined;
|
|
95
108
|
|
|
96
|
-
setMapClickHandler(
|
|
97
|
-
_mapClickHandler: ((coordinates: [number, number]) => void) | undefined
|
|
98
|
-
): void {
|
|
99
|
-
mapClickHandler = _mapClickHandler;
|
|
100
|
-
|
|
101
|
-
if (mapClickHandler) {
|
|
102
|
-
map.on("click", handleMapClick);
|
|
103
|
-
} else {
|
|
104
109
|
map.off("click", handleMapClick);
|
|
105
110
|
}
|
|
106
111
|
},
|
|
107
112
|
|
|
108
113
|
flyTo(center: [number, number], zoom: number) {
|
|
109
|
-
map.flyTo(center, zoom, { duration: 2, ...flyToOptions });
|
|
114
|
+
map.flyTo([center[1], center[0]], zoom, { duration: 2, ...flyToOptions });
|
|
110
115
|
},
|
|
111
116
|
|
|
112
117
|
fitBounds(bbox: [number, number, number, number], padding: number): void {
|
|
@@ -123,10 +128,41 @@ export function createLeafletMapController(
|
|
|
123
128
|
map.getContainer().style.cursor = reverse ? "crosshair" : "";
|
|
124
129
|
},
|
|
125
130
|
|
|
131
|
+
setReverseMarker(coordinates: [number, number]) {
|
|
132
|
+
if (!marker) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const latLng =
|
|
137
|
+
coordinates && ([coordinates[1], coordinates[0]] as [number, number]);
|
|
138
|
+
|
|
139
|
+
if (reverseMarker) {
|
|
140
|
+
if (!latLng) {
|
|
141
|
+
reverseMarker.remove();
|
|
142
|
+
|
|
143
|
+
reverseMarker = undefined;
|
|
144
|
+
} else {
|
|
145
|
+
reverseMarker.setLatLng(latLng);
|
|
146
|
+
}
|
|
147
|
+
} else if (latLng) {
|
|
148
|
+
reverseMarker = (
|
|
149
|
+
typeof marker === "object"
|
|
150
|
+
? new L.Marker(latLng, marker)
|
|
151
|
+
: createMarker(latLng)
|
|
152
|
+
).addTo(map);
|
|
153
|
+
|
|
154
|
+
reverseMarker.getElement()?.classList.add("marker-reverse");
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
|
|
126
158
|
setMarkers(
|
|
127
159
|
markedFeatures: Feature[] | undefined,
|
|
128
160
|
picked: Feature | undefined
|
|
129
161
|
): void {
|
|
162
|
+
if (!marker) {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
|
|
130
166
|
function setData(data?: GeoJSON.GeoJSON) {
|
|
131
167
|
resultLayer.clearLayers();
|
|
132
168
|
|
|
@@ -143,16 +179,6 @@ export function createLeafletMapController(
|
|
|
143
179
|
|
|
144
180
|
setData();
|
|
145
181
|
|
|
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
182
|
if (picked) {
|
|
157
183
|
let handled = false;
|
|
158
184
|
|
|
@@ -218,19 +244,50 @@ export function createLeafletMapController(
|
|
|
218
244
|
);
|
|
219
245
|
}
|
|
220
246
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
247
|
+
if (showResultMarkers) {
|
|
248
|
+
for (const feature of markedFeatures ?? []) {
|
|
249
|
+
if (feature === picked) {
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
225
252
|
|
|
226
|
-
|
|
253
|
+
const pos: L.LatLngExpression = [
|
|
254
|
+
feature.center[1],
|
|
255
|
+
feature.center[0],
|
|
256
|
+
];
|
|
227
257
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
258
|
+
const marker =
|
|
259
|
+
typeof showResultMarkers === "object"
|
|
260
|
+
? new L.Marker(pos, showResultMarkers)
|
|
261
|
+
: createMarker(pos, true);
|
|
262
|
+
|
|
263
|
+
marker
|
|
264
|
+
.addTo(map)
|
|
265
|
+
.bindTooltip(feature.place_name.replace(/,.*/, ""), {
|
|
266
|
+
direction: "top",
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
const element = marker.getElement();
|
|
270
|
+
|
|
271
|
+
if (element) {
|
|
272
|
+
element.addEventListener("click", (e) => {
|
|
273
|
+
e.stopPropagation();
|
|
274
|
+
|
|
275
|
+
eventHandler?.({ type: "markerClick", id: feature.id });
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
element.addEventListener("mouseenter", () => {
|
|
279
|
+
eventHandler?.({ type: "markerMouseEnter", id: feature.id });
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
element.addEventListener("mouseleave", () => {
|
|
283
|
+
eventHandler?.({ type: "markerMouseLeave", id: feature.id });
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
element.classList.toggle("marker-fuzzy", !!feature.matching_text);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
markers.push(marker);
|
|
290
|
+
}
|
|
234
291
|
}
|
|
235
292
|
},
|
|
236
293
|
|