@maptiler/geocoding-control 0.0.32 → 0.0.37
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 +10 -6
- package/dist/leaflet.js +2076 -687
- package/dist/leaflet.umd.cjs +22 -1
- package/dist/lib/LeafletGeocodingControl.d.ts +6 -2
- package/dist/lib/MaplibreglGeocodingControl.d.ts +10 -3
- package/dist/lib/leafletMapController.d.ts +1 -1
- package/dist/lib/maplibreglMapController.d.ts +7 -0
- package/dist/lib/types.d.ts +23 -3
- package/dist/main.d.ts +1 -1
- package/dist/maplibregl.js +2093 -672
- package/dist/maplibregl.umd.cjs +22 -1
- package/dist/style.css +1 -1
- package/package.json +7 -4
- package/src/lib/GeocodingControl.svelte +74 -20
- package/src/lib/LeafletGeocodingControl.ts +23 -4
- package/src/lib/MaplibreglGeocodingControl.ts +32 -8
- package/src/lib/ReverseGeocodingIcon.svelte +12 -0
- package/src/lib/leafletMapController.ts +119 -20
- package/src/lib/maplibreglMapController.ts +291 -0
- package/src/lib/types.ts +26 -3
- package/dist/lib/maplibreMapController.d.ts +0 -4
- package/src/lib/BullseyeIcon.svelte +0 -12
- package/src/lib/maplibreMapController.ts +0 -149
|
@@ -5,11 +5,14 @@ import {
|
|
|
5
5
|
type FlyToOptions,
|
|
6
6
|
type FitBoundsOptions,
|
|
7
7
|
Evented,
|
|
8
|
+
type FillLayerSpecification,
|
|
9
|
+
type LineLayerSpecification,
|
|
8
10
|
} from "maplibre-gl";
|
|
9
11
|
import type maplibregl from "maplibre-gl";
|
|
10
12
|
import GeocodingControlComponent from "./GeocodingControl.svelte";
|
|
11
13
|
import type { ControlOptions } from "./types";
|
|
12
|
-
import {
|
|
14
|
+
import { createMaplibreglMapController } from "./maplibreglMapController";
|
|
15
|
+
export { createMaplibreglMapController } from "./maplibreglMapController";
|
|
13
16
|
|
|
14
17
|
type MapLibreGL = typeof maplibregl;
|
|
15
18
|
|
|
@@ -48,6 +51,14 @@ type MapLibreControlOptions = ControlOptions & {
|
|
|
48
51
|
* @default true
|
|
49
52
|
*/
|
|
50
53
|
flyTo?: boolean | (FlyToOptions & FitBoundsOptions);
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Style for full feature geometry GeoJSON.
|
|
57
|
+
*/
|
|
58
|
+
fullGeometryStyle?: {
|
|
59
|
+
fill: Pick<FillLayerSpecification, "layout" | "paint" | "filter">;
|
|
60
|
+
line: Pick<LineLayerSpecification, "layout" | "paint" | "filter">;
|
|
61
|
+
};
|
|
51
62
|
};
|
|
52
63
|
|
|
53
64
|
export class GeocodingControl extends Evented implements IControl {
|
|
@@ -67,18 +78,25 @@ export class GeocodingControl extends Evented implements IControl {
|
|
|
67
78
|
div.className =
|
|
68
79
|
"mapboxgl-ctrl-geocoder mapboxgl-ctrl maplibregl-ctrl-geocoder maplibregl-ctrl";
|
|
69
80
|
|
|
70
|
-
const {
|
|
71
|
-
|
|
81
|
+
const {
|
|
82
|
+
maplibregl,
|
|
83
|
+
marker,
|
|
84
|
+
showResultMarkers,
|
|
85
|
+
flyTo,
|
|
86
|
+
fullGeometryStyle,
|
|
87
|
+
...restOptions
|
|
88
|
+
} = this.#options;
|
|
72
89
|
|
|
73
90
|
const flyToOptions = typeof flyTo === "boolean" ? {} : flyTo;
|
|
74
91
|
|
|
75
|
-
const mapController =
|
|
92
|
+
const mapController = createMaplibreglMapController(
|
|
76
93
|
map,
|
|
77
94
|
maplibregl,
|
|
78
95
|
marker,
|
|
79
96
|
showResultMarkers,
|
|
80
97
|
flyToOptions,
|
|
81
|
-
flyToOptions
|
|
98
|
+
flyToOptions,
|
|
99
|
+
fullGeometryStyle
|
|
82
100
|
);
|
|
83
101
|
|
|
84
102
|
this.#gc = new GeocodingControlComponent({
|
|
@@ -111,13 +129,19 @@ export class GeocodingControl extends Evented implements IControl {
|
|
|
111
129
|
setOptions(options: MapLibreControlOptions) {
|
|
112
130
|
this.#options = options;
|
|
113
131
|
|
|
114
|
-
const {
|
|
115
|
-
|
|
132
|
+
const {
|
|
133
|
+
maplibregl,
|
|
134
|
+
marker,
|
|
135
|
+
showResultMarkers,
|
|
136
|
+
flyTo,
|
|
137
|
+
fullGeometryStyle,
|
|
138
|
+
...restOptions
|
|
139
|
+
} = this.#options;
|
|
116
140
|
|
|
117
141
|
this.#gc?.$set(restOptions);
|
|
118
142
|
}
|
|
119
143
|
|
|
120
|
-
setQuery(value: string, submit = true) {
|
|
144
|
+
setQuery(value: string, submit: boolean | "always" = true) {
|
|
121
145
|
(this.#gc as any)?.setQuery(value, submit);
|
|
122
146
|
}
|
|
123
147
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<svg viewBox="0 0 60.006 21.412" width="14" height="20">
|
|
2
|
+
<path
|
|
3
|
+
d="M30.003-26.765C13.46-26.765 0-14.158 0 1.337c0 23.286 24.535 42.952 28.39 46.04.24.192.402.316.471.376.323.282.732.424 1.142.424.41 0 .82-.142 1.142-.424.068-.06.231-.183.471-.376 3.856-3.09 28.39-22.754 28.39-46.04 0-15.495-13.46-28.102-30.003-28.102Zm1.757 12.469c4.38 0 7.858 1.052 10.431 3.158 2.595 2.105 3.89 4.913 3.89 8.422 0 2.34-.53 4.362-1.593 6.063-1.063 1.702-3.086 3.616-6.063 5.742-2.042 1.51-3.337 2.659-3.89 3.446-.532.787-.8 1.82-.8 3.096v1.914h-8.449V15.18c0-2.041.434-3.815 1.306-5.325.872-1.51 2.467-3.118 4.785-4.82 2.233-1.594 3.7-2.89 4.402-3.889a5.582 5.582 0 0 0 1.087-3.35c0-1.382-.51-2.435-1.531-3.158-1.02-.723-2.45-1.087-4.28-1.087-3.19 0-6.826 1.047-10.91 3.131l-3.472-6.986c4.742-2.659 9.77-3.992 15.087-3.992Zm-1.88 37.324c1.765 0 3.124.472 4.08 1.408.98.936 1.47 2.276 1.47 4.02 0 1.68-.49 3.007-1.47 3.985-.977.957-2.336 1.435-4.08 1.435-1.787 0-3.171-.465-4.15-1.4-.978-.958-1.47-2.298-1.47-4.02 0-1.787.48-3.14 1.436-4.054.957-.915 2.355-1.374 4.184-1.374Z"
|
|
4
|
+
/>
|
|
5
|
+
</svg>
|
|
6
|
+
|
|
7
|
+
<style>
|
|
8
|
+
svg {
|
|
9
|
+
display: block;
|
|
10
|
+
fill: var(--color-icon-button);
|
|
11
|
+
}
|
|
12
|
+
</style>
|
|
@@ -1,13 +1,35 @@
|
|
|
1
1
|
import * as L from "leaflet";
|
|
2
2
|
import MarkerIcon from "./MarkerIcon.svelte";
|
|
3
3
|
import type { Feature, MapController, Proximity } from "./types";
|
|
4
|
+
import type {
|
|
5
|
+
Polygon,
|
|
6
|
+
MultiPolygon,
|
|
7
|
+
LineString,
|
|
8
|
+
MultiLineString,
|
|
9
|
+
} from "@turf/helpers";
|
|
10
|
+
import mask from "@turf/mask";
|
|
11
|
+
import union from "@turf/union";
|
|
4
12
|
|
|
5
13
|
export function createLeafletMapController(
|
|
6
14
|
map: L.Map,
|
|
7
15
|
marker: boolean | L.MarkerOptions = true,
|
|
8
16
|
showResultMarkers: boolean | L.MarkerOptions = true,
|
|
9
17
|
flyToOptions: L.ZoomPanOptions = {},
|
|
10
|
-
flyToBounds: L.FitBoundsOptions = {}
|
|
18
|
+
flyToBounds: L.FitBoundsOptions = {},
|
|
19
|
+
fullGeometryStyle: L.PathOptions | L.StyleFunction = (feature) => {
|
|
20
|
+
const type = feature?.geometry?.type;
|
|
21
|
+
|
|
22
|
+
const weight = type === "LineString" || type === "MultiLineString" ? 3 : 2;
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
color: "#3170fe",
|
|
26
|
+
fillColor: "#000",
|
|
27
|
+
fillOpacity: 0.1,
|
|
28
|
+
weight,
|
|
29
|
+
dashArray: [weight, weight],
|
|
30
|
+
lineCap: "butt",
|
|
31
|
+
};
|
|
32
|
+
}
|
|
11
33
|
) {
|
|
12
34
|
let proximityChangeHandler: ((proximity: Proximity) => void) | undefined;
|
|
13
35
|
|
|
@@ -19,6 +41,10 @@ export function createLeafletMapController(
|
|
|
19
41
|
|
|
20
42
|
let selectedMarker: L.Marker | undefined;
|
|
21
43
|
|
|
44
|
+
let resultLayer = L.geoJSON(undefined, {
|
|
45
|
+
style: fullGeometryStyle,
|
|
46
|
+
}).addTo(map);
|
|
47
|
+
|
|
22
48
|
const handleMoveEnd = () => {
|
|
23
49
|
if (!proximityChangeHandler) {
|
|
24
50
|
prevProximity = undefined;
|
|
@@ -76,7 +102,7 @@ export function createLeafletMapController(
|
|
|
76
102
|
},
|
|
77
103
|
|
|
78
104
|
flyTo(center: [number, number], zoom: number) {
|
|
79
|
-
map.flyTo(center, zoom, flyToOptions);
|
|
105
|
+
map.flyTo(center, zoom, { duration: 2, ...flyToOptions });
|
|
80
106
|
},
|
|
81
107
|
|
|
82
108
|
fitBounds(bbox: [number, number, number, number], padding: number): void {
|
|
@@ -85,7 +111,7 @@ export function createLeafletMapController(
|
|
|
85
111
|
[bbox[1], bbox[0]],
|
|
86
112
|
[bbox[3], bbox[2]],
|
|
87
113
|
],
|
|
88
|
-
{
|
|
114
|
+
{ padding: [padding, padding], duration: 2, ...flyToBounds }
|
|
89
115
|
);
|
|
90
116
|
},
|
|
91
117
|
|
|
@@ -97,37 +123,110 @@ export function createLeafletMapController(
|
|
|
97
123
|
markedFeatures: Feature[] | undefined,
|
|
98
124
|
picked: Feature | undefined
|
|
99
125
|
): void {
|
|
126
|
+
function setData(data?: GeoJSON.GeoJSON) {
|
|
127
|
+
resultLayer.clearLayers();
|
|
128
|
+
|
|
129
|
+
if (data) {
|
|
130
|
+
resultLayer.addData(data);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
100
134
|
for (const marker of markers) {
|
|
101
135
|
marker.remove();
|
|
102
136
|
}
|
|
103
137
|
|
|
104
138
|
markers.length = 0;
|
|
105
139
|
|
|
106
|
-
|
|
107
|
-
? [...(markedFeatures ?? []), picked]
|
|
108
|
-
: markedFeatures ?? []) {
|
|
109
|
-
let m: L.Marker;
|
|
140
|
+
setData();
|
|
110
141
|
|
|
111
|
-
|
|
142
|
+
const createMarker = (pos: L.LatLngExpression) => {
|
|
143
|
+
const element = document.createElement("div");
|
|
144
|
+
|
|
145
|
+
new MarkerIcon({ props: { displayIn: "leaflet" }, target: element });
|
|
146
|
+
|
|
147
|
+
return new L.Marker(pos, {
|
|
148
|
+
icon: new L.DivIcon({ html: element, className: "" }),
|
|
149
|
+
});
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
if (picked) {
|
|
153
|
+
let handled = false;
|
|
154
|
+
|
|
155
|
+
if (picked.geometry.type === "GeometryCollection") {
|
|
156
|
+
const geoms = picked.geometry.geometries.filter(
|
|
157
|
+
(geometry) =>
|
|
158
|
+
geometry.type === "Polygon" || geometry.type === "MultiPolygon"
|
|
159
|
+
) as (Polygon | MultiPolygon)[];
|
|
160
|
+
|
|
161
|
+
if (geoms.length > 0) {
|
|
162
|
+
let geometry = geoms.pop()!;
|
|
163
|
+
|
|
164
|
+
for (const geom of geoms) {
|
|
165
|
+
geometry = union(geometry, geom) as unknown as
|
|
166
|
+
| Polygon
|
|
167
|
+
| MultiPolygon; // union actually returns geometry
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
setData(mask({ ...picked, geometry }));
|
|
112
171
|
|
|
113
|
-
|
|
114
|
-
|
|
172
|
+
handled = true;
|
|
173
|
+
} else {
|
|
174
|
+
const geometries = picked.geometry.geometries.filter(
|
|
175
|
+
(geometry) =>
|
|
176
|
+
geometry.type === "LineString" ||
|
|
177
|
+
geometry.type === "MultiLineString"
|
|
178
|
+
) as (LineString | MultiLineString)[];
|
|
179
|
+
|
|
180
|
+
if (geometries.length > 0) {
|
|
181
|
+
setData({
|
|
182
|
+
...picked,
|
|
183
|
+
geometry: { type: "GeometryCollection", geometries },
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
handled = true;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (handled) {
|
|
192
|
+
// nothing
|
|
193
|
+
} else if (
|
|
194
|
+
picked.geometry.type === "Polygon" ||
|
|
195
|
+
picked.geometry.type === "MultiPolygon"
|
|
196
|
+
) {
|
|
197
|
+
setData(mask(picked as any));
|
|
115
198
|
} else if (
|
|
116
|
-
|
|
117
|
-
|
|
199
|
+
picked.geometry.type === "LineString" ||
|
|
200
|
+
picked.geometry.type === "MultiLineString"
|
|
118
201
|
) {
|
|
119
|
-
|
|
120
|
-
} else {
|
|
121
|
-
const element = document.createElement("div");
|
|
202
|
+
setData(picked as any);
|
|
122
203
|
|
|
123
|
-
|
|
204
|
+
return; // no pin for (multi)linestrings
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const pos: L.LatLngExpression = [picked.center[1], picked.center[0]];
|
|
208
|
+
|
|
209
|
+
markers.push(
|
|
210
|
+
(typeof marker === "object"
|
|
211
|
+
? new L.Marker(pos, marker)
|
|
212
|
+
: createMarker(pos)
|
|
213
|
+
).addTo(map)
|
|
214
|
+
);
|
|
215
|
+
}
|
|
124
216
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
217
|
+
for (const feature of markedFeatures ?? []) {
|
|
218
|
+
if (feature === picked) {
|
|
219
|
+
continue;
|
|
128
220
|
}
|
|
129
221
|
|
|
130
|
-
|
|
222
|
+
const pos: L.LatLngExpression = [feature.center[1], feature.center[0]];
|
|
223
|
+
|
|
224
|
+
markers.push(
|
|
225
|
+
(typeof showResultMarkers === "object"
|
|
226
|
+
? new L.Marker(pos, showResultMarkers)
|
|
227
|
+
: createMarker(pos)
|
|
228
|
+
).addTo(map)
|
|
229
|
+
);
|
|
131
230
|
}
|
|
132
231
|
},
|
|
133
232
|
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
import type MapLibreGL from "maplibre-gl";
|
|
2
|
+
import type {
|
|
3
|
+
FitBoundsOptions,
|
|
4
|
+
MapMouseEvent,
|
|
5
|
+
LngLat,
|
|
6
|
+
Map,
|
|
7
|
+
Marker,
|
|
8
|
+
FlyToOptions,
|
|
9
|
+
GeoJSONSource,
|
|
10
|
+
FillLayerSpecification,
|
|
11
|
+
LineLayerSpecification,
|
|
12
|
+
} from "maplibre-gl";
|
|
13
|
+
import MarkerIcon from "./MarkerIcon.svelte";
|
|
14
|
+
import type { Feature, MapController, Proximity } from "./types";
|
|
15
|
+
import mask from "@turf/mask";
|
|
16
|
+
import union from "@turf/union";
|
|
17
|
+
import type {
|
|
18
|
+
Polygon,
|
|
19
|
+
MultiPolygon,
|
|
20
|
+
LineString,
|
|
21
|
+
MultiLineString,
|
|
22
|
+
} from "@turf/helpers";
|
|
23
|
+
|
|
24
|
+
let emptyGeojson: GeoJSON.FeatureCollection = {
|
|
25
|
+
type: "FeatureCollection",
|
|
26
|
+
features: [],
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export function createMaplibreglMapController(
|
|
30
|
+
map: Map,
|
|
31
|
+
maplibregl?: typeof MapLibreGL | undefined,
|
|
32
|
+
marker: boolean | maplibregl.MarkerOptions = true,
|
|
33
|
+
showResultMarkers: boolean | maplibregl.MarkerOptions = true,
|
|
34
|
+
flyToOptions: FlyToOptions = {},
|
|
35
|
+
fitBoundsOptions: FitBoundsOptions = {},
|
|
36
|
+
fullGeometryStyle: {
|
|
37
|
+
fill: Pick<FillLayerSpecification, "layout" | "paint" | "filter">;
|
|
38
|
+
line: Pick<LineLayerSpecification, "layout" | "paint" | "filter">;
|
|
39
|
+
} = {
|
|
40
|
+
fill: {
|
|
41
|
+
layout: {},
|
|
42
|
+
paint: {
|
|
43
|
+
"fill-color": "#000",
|
|
44
|
+
"fill-opacity": 0.1,
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
line: {
|
|
48
|
+
layout: {
|
|
49
|
+
"line-cap": "square",
|
|
50
|
+
},
|
|
51
|
+
paint: {
|
|
52
|
+
"line-width": ["case", ["==", ["geometry-type"], "Polygon"], 2, 3],
|
|
53
|
+
"line-dasharray": [1, 1],
|
|
54
|
+
"line-color": "#3170fe",
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
}
|
|
58
|
+
) {
|
|
59
|
+
let proximityChangeHandler: ((proximity: Proximity) => void) | undefined;
|
|
60
|
+
|
|
61
|
+
let mapClickHandler: ((coordinates: [number, number]) => void) | undefined;
|
|
62
|
+
|
|
63
|
+
let prevProximity: Proximity = undefined;
|
|
64
|
+
|
|
65
|
+
let markers: Marker[] = [];
|
|
66
|
+
|
|
67
|
+
let selectedMarker: maplibregl.Marker | undefined;
|
|
68
|
+
|
|
69
|
+
function addFullGeometryLayer() {
|
|
70
|
+
map.addSource("full-geom", {
|
|
71
|
+
type: "geojson",
|
|
72
|
+
data: emptyGeojson,
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
map.addLayer({
|
|
76
|
+
...fullGeometryStyle.fill,
|
|
77
|
+
id: "full-geom-fill",
|
|
78
|
+
type: "fill",
|
|
79
|
+
source: "full-geom",
|
|
80
|
+
filter: ["==", ["geometry-type"], "Polygon"],
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
map.addLayer({
|
|
84
|
+
...fullGeometryStyle.line,
|
|
85
|
+
id: "full-geom-line",
|
|
86
|
+
type: "line",
|
|
87
|
+
source: "full-geom",
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (map.loaded()) {
|
|
92
|
+
addFullGeometryLayer();
|
|
93
|
+
} else {
|
|
94
|
+
map.once("load", () => {
|
|
95
|
+
addFullGeometryLayer();
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const handleMapClick = (e: MapMouseEvent) => {
|
|
100
|
+
mapClickHandler?.([e.lngLat.lng, e.lngLat.lat]);
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const handleMoveEnd = () => {
|
|
104
|
+
let c: LngLat;
|
|
105
|
+
|
|
106
|
+
const proximity =
|
|
107
|
+
map.getZoom() > 9
|
|
108
|
+
? ([(c = map.getCenter().wrap()).lng, c.lat] as [number, number])
|
|
109
|
+
: undefined;
|
|
110
|
+
|
|
111
|
+
if (prevProximity !== proximity) {
|
|
112
|
+
prevProximity = proximity;
|
|
113
|
+
|
|
114
|
+
proximityChangeHandler?.(proximity);
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
const ctrl: MapController = {
|
|
119
|
+
setProximityChangeHandler(
|
|
120
|
+
_proximityChangeHandler: ((proximity: Proximity) => void) | undefined
|
|
121
|
+
): void {
|
|
122
|
+
if (_proximityChangeHandler) {
|
|
123
|
+
proximityChangeHandler = _proximityChangeHandler;
|
|
124
|
+
|
|
125
|
+
map.on("moveend", handleMoveEnd);
|
|
126
|
+
|
|
127
|
+
handleMoveEnd();
|
|
128
|
+
} else {
|
|
129
|
+
map.off("moveend", handleMoveEnd);
|
|
130
|
+
|
|
131
|
+
proximityChangeHandler?.(undefined);
|
|
132
|
+
|
|
133
|
+
proximityChangeHandler = undefined;
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
|
|
137
|
+
setMapClickHandler(
|
|
138
|
+
_mapClickHandler: ((coordinates: [number, number]) => void) | undefined
|
|
139
|
+
): void {
|
|
140
|
+
mapClickHandler = _mapClickHandler;
|
|
141
|
+
|
|
142
|
+
if (mapClickHandler) {
|
|
143
|
+
map.on("click", handleMapClick);
|
|
144
|
+
} else {
|
|
145
|
+
map.off("click", handleMapClick);
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
|
|
149
|
+
flyTo(center: [number, number], zoom: number): void {
|
|
150
|
+
map.flyTo({ center, zoom, ...flyToOptions });
|
|
151
|
+
},
|
|
152
|
+
|
|
153
|
+
fitBounds(bbox: [number, number, number, number], padding: number): void {
|
|
154
|
+
map.fitBounds(
|
|
155
|
+
[
|
|
156
|
+
[bbox[0], bbox[1]],
|
|
157
|
+
[bbox[2], bbox[3]],
|
|
158
|
+
],
|
|
159
|
+
{ padding, ...fitBoundsOptions }
|
|
160
|
+
);
|
|
161
|
+
},
|
|
162
|
+
|
|
163
|
+
indicateReverse(reverse: boolean): void {
|
|
164
|
+
map.getCanvas().style.cursor = reverse ? "crosshair" : "";
|
|
165
|
+
},
|
|
166
|
+
|
|
167
|
+
setMarkers(
|
|
168
|
+
markedFeatures: Feature[] | undefined,
|
|
169
|
+
picked: Feature | undefined
|
|
170
|
+
): void {
|
|
171
|
+
function setData(data: GeoJSON.GeoJSON) {
|
|
172
|
+
(map.getSource("full-geom") as GeoJSONSource)?.setData(data);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
for (const marker of markers) {
|
|
176
|
+
marker.remove();
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
markers.length = 0;
|
|
180
|
+
|
|
181
|
+
setData(emptyGeojson);
|
|
182
|
+
|
|
183
|
+
if (!maplibregl) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const createMarker = () => {
|
|
188
|
+
const element = document.createElement("div");
|
|
189
|
+
|
|
190
|
+
new MarkerIcon({
|
|
191
|
+
props: { displayIn: "maplibre" },
|
|
192
|
+
target: element,
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
return new maplibregl.Marker({ element });
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
if (picked) {
|
|
199
|
+
let handled = false;
|
|
200
|
+
|
|
201
|
+
if (picked.geometry.type === "GeometryCollection") {
|
|
202
|
+
const geoms = picked.geometry.geometries.filter(
|
|
203
|
+
(geometry) =>
|
|
204
|
+
geometry.type === "Polygon" || geometry.type === "MultiPolygon"
|
|
205
|
+
) as (Polygon | MultiPolygon)[];
|
|
206
|
+
|
|
207
|
+
if (geoms.length > 0) {
|
|
208
|
+
let geometry = geoms.pop()!;
|
|
209
|
+
|
|
210
|
+
for (const geom of geoms) {
|
|
211
|
+
geometry = union(geometry, geom) as unknown as
|
|
212
|
+
| Polygon
|
|
213
|
+
| MultiPolygon; // union actually returns geometry
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
setData(mask({ ...picked, geometry }));
|
|
217
|
+
|
|
218
|
+
handled = true;
|
|
219
|
+
} else {
|
|
220
|
+
const geometries = picked.geometry.geometries.filter(
|
|
221
|
+
(geometry) =>
|
|
222
|
+
geometry.type === "LineString" ||
|
|
223
|
+
geometry.type === "MultiLineString"
|
|
224
|
+
) as (LineString | MultiLineString)[];
|
|
225
|
+
|
|
226
|
+
if (geometries.length > 0) {
|
|
227
|
+
setData({
|
|
228
|
+
...picked,
|
|
229
|
+
geometry: { type: "GeometryCollection", geometries },
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
handled = true;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (handled) {
|
|
238
|
+
// nothing
|
|
239
|
+
} else if (
|
|
240
|
+
picked.geometry.type === "Polygon" ||
|
|
241
|
+
picked.geometry.type === "MultiPolygon"
|
|
242
|
+
) {
|
|
243
|
+
setData(mask(picked as any));
|
|
244
|
+
} else if (
|
|
245
|
+
picked.geometry.type === "LineString" ||
|
|
246
|
+
picked.geometry.type === "MultiLineString"
|
|
247
|
+
) {
|
|
248
|
+
setData(picked as any);
|
|
249
|
+
|
|
250
|
+
return; // no pin for (multi)linestrings
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
markers.push(
|
|
254
|
+
(typeof marker === "object"
|
|
255
|
+
? new maplibregl.Marker(marker)
|
|
256
|
+
: createMarker()
|
|
257
|
+
)
|
|
258
|
+
.setLngLat(picked.center)
|
|
259
|
+
.addTo(map)
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
for (const feature of markedFeatures ?? []) {
|
|
264
|
+
if (feature === picked) {
|
|
265
|
+
continue;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
markers.push(
|
|
269
|
+
(typeof showResultMarkers === "object"
|
|
270
|
+
? new maplibregl.Marker(showResultMarkers)
|
|
271
|
+
: createMarker()
|
|
272
|
+
)
|
|
273
|
+
.setLngLat(feature.center)
|
|
274
|
+
.addTo(map)
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
},
|
|
278
|
+
|
|
279
|
+
setSelectedMarker(index: number): void {
|
|
280
|
+
if (selectedMarker) {
|
|
281
|
+
selectedMarker.getElement().classList.toggle("marker-selected", false);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
selectedMarker = index > -1 ? markers[index] : undefined;
|
|
285
|
+
|
|
286
|
+
selectedMarker?.getElement().classList.toggle("marker-selected", true);
|
|
287
|
+
},
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
return ctrl;
|
|
291
|
+
}
|
package/src/lib/types.ts
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
export type Feature = {
|
|
1
|
+
export type Feature = GeoJSON.Feature & {
|
|
2
2
|
id: string;
|
|
3
3
|
text: string;
|
|
4
4
|
place_name: string;
|
|
5
5
|
place_type: string;
|
|
6
6
|
center: [number, number];
|
|
7
7
|
bbox: [number, number, number, number];
|
|
8
|
+
address?: string;
|
|
8
9
|
};
|
|
9
10
|
|
|
10
11
|
export type FeatureCollection = {
|
|
12
|
+
type: "FeatureCollection";
|
|
11
13
|
features: Feature[];
|
|
12
14
|
};
|
|
13
15
|
|
|
@@ -177,11 +179,25 @@ export type ControlOptions = {
|
|
|
177
179
|
class?: string;
|
|
178
180
|
|
|
179
181
|
/**
|
|
180
|
-
* Set to `true` to enable reverse geocoding button with title
|
|
182
|
+
* Set to `true` to enable reverse geocoding button with title. Set to `"always"` to reverse geocoding be always active.
|
|
181
183
|
*
|
|
182
184
|
* @default false
|
|
183
185
|
*/
|
|
184
|
-
enableReverse?: boolean |
|
|
186
|
+
enableReverse?: boolean | "always";
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Reverse toggle button title.
|
|
190
|
+
*
|
|
191
|
+
* @default "toggle reverse geocoding"
|
|
192
|
+
*/
|
|
193
|
+
reverseButtonTitle?: string;
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Clear button title.
|
|
197
|
+
*
|
|
198
|
+
* @default "clear"
|
|
199
|
+
*/
|
|
200
|
+
clearButtonTitle?: string;
|
|
185
201
|
|
|
186
202
|
/**
|
|
187
203
|
* Set to `true` to show place type.
|
|
@@ -190,6 +206,13 @@ export type ControlOptions = {
|
|
|
190
206
|
*/
|
|
191
207
|
showPlaceType?: boolean;
|
|
192
208
|
|
|
209
|
+
/**
|
|
210
|
+
* Set to `true` to show full feature geometry of the chosen result. Otherwise only marker will be shown.
|
|
211
|
+
*
|
|
212
|
+
* @default true
|
|
213
|
+
*/
|
|
214
|
+
showFullGeometry?: boolean;
|
|
215
|
+
|
|
193
216
|
// TODO - missing but useful from maplibre-gl-geocoder
|
|
194
217
|
// popup // If true, a Popup will be added to the map when clicking on a marker using a default set of popup options. If the value is an object, the popup will be constructed using these options. If false, no popup will be added to the map. Requires that options.maplibregl also be set. (optional, default true)
|
|
195
218
|
// render // A function that specifies how the results should be rendered in the dropdown menu. This function should accepts a single Carmen GeoJSON object as input and return a string. Any HTML in the returned string will be rendered.
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import type MapLibreGL from "maplibre-gl";
|
|
2
|
-
import type { FitBoundsOptions, Map, FlyToOptions } from "maplibre-gl";
|
|
3
|
-
import type { MapController } from "./types";
|
|
4
|
-
export declare function createMaplibreMapController(map: Map, maplibregl?: typeof MapLibreGL | undefined, marker?: boolean | maplibregl.MarkerOptions, showResultMarkers?: boolean | maplibregl.MarkerOptions, flyToOptions?: FlyToOptions, fitBoundsOptions?: FitBoundsOptions): MapController;
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
<svg viewBox="0 0 1000 1000" width="18px" height="18px">
|
|
2
|
-
<path
|
|
3
|
-
d="M500 115.1c212.2 0 384.9 172.6 384.9 384.9 0 212.2-172.7 384.9-384.9 384.9S115.1 712.2 115.1 500c0-212.4 172.5-384.9 384.9-384.9M500 10C229.4 10 10 229.4 10 500s219.4 490 490 490 490-219.4 490-490c-.2-270.6-219.5-490-490-490zm0 315c96.5 0 175 78.4 175 175 0 96.5-78.4 175-175 175-96.5 0-175-78.4-175-175 0-96.5 78.4-175 175-175m0-105c-154.7 0-279.9 125.4-279.9 279.9 0 154.7 125.4 279.9 279.9 279.9 154.5 0 279.9-125.4 279.9-279.9C779.9 345.3 654.5 220 500 220zm70 280c0 38.7-31.3 70-70 70s-70-31.3-70-70 31.3-70 70-70 70 31.3 70 70z"
|
|
4
|
-
/>
|
|
5
|
-
</svg>
|
|
6
|
-
|
|
7
|
-
<style>
|
|
8
|
-
svg {
|
|
9
|
-
display: block;
|
|
10
|
-
fill: var(--color-icon-button);
|
|
11
|
-
}
|
|
12
|
-
</style>
|