@maptiler/geocoding-control 0.0.43 → 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.
@@ -11,7 +11,7 @@ import type {
11
11
  LineLayerSpecification,
12
12
  } from "maplibre-gl";
13
13
  import MarkerIcon from "./MarkerIcon.svelte";
14
- import type { Feature, MapController, Proximity } from "./types";
14
+ import type { Feature, MapController, MapEvent, Proximity } from "./types";
15
15
  import union from "@turf/union";
16
16
  import type {
17
17
  Polygon,
@@ -33,10 +33,12 @@ export function createMaplibreglMapController(
33
33
  showResultMarkers: boolean | maplibregl.MarkerOptions = true,
34
34
  flyToOptions: FlyToOptions = {},
35
35
  fitBoundsOptions: FitBoundsOptions = {},
36
- fullGeometryStyle: {
37
- fill: Pick<FillLayerSpecification, "layout" | "paint" | "filter">;
38
- line: Pick<LineLayerSpecification, "layout" | "paint" | "filter">;
39
- } = {
36
+ fullGeometryStyle:
37
+ | undefined
38
+ | {
39
+ fill?: Pick<FillLayerSpecification, "layout" | "paint" | "filter">;
40
+ line?: Pick<LineLayerSpecification, "layout" | "paint" | "filter">;
41
+ } = {
40
42
  fill: {
41
43
  paint: {
42
44
  "fill-color": "#000",
@@ -57,9 +59,7 @@ export function createMaplibreglMapController(
57
59
  },
58
60
  }
59
61
  ) {
60
- let proximityChangeHandler: ((proximity: Proximity) => void) | undefined;
61
-
62
- let mapClickHandler: ((coordinates: [number, number]) => void) | undefined;
62
+ let eventHandler: ((e: MapEvent) => void) | undefined;
63
63
 
64
64
  let prevProximity: Proximity = undefined;
65
65
 
@@ -67,25 +67,33 @@ export function createMaplibreglMapController(
67
67
 
68
68
  let selectedMarker: maplibregl.Marker | undefined;
69
69
 
70
+ let reverseMarker: maplibregl.Marker | undefined;
71
+
70
72
  function addFullGeometryLayer() {
71
- map.addSource("full-geom", {
72
- type: "geojson",
73
- data: emptyGeojson,
74
- });
73
+ if (fullGeometryStyle?.fill || fullGeometryStyle?.line) {
74
+ map.addSource("full-geom", {
75
+ type: "geojson",
76
+ data: emptyGeojson,
77
+ });
78
+ }
75
79
 
76
- map.addLayer({
77
- ...fullGeometryStyle.fill,
78
- id: "full-geom-fill",
79
- type: "fill",
80
- source: "full-geom",
81
- });
80
+ if (fullGeometryStyle?.fill) {
81
+ map.addLayer({
82
+ ...fullGeometryStyle?.fill,
83
+ id: "full-geom-fill",
84
+ type: "fill",
85
+ source: "full-geom",
86
+ });
87
+ }
82
88
 
83
- map.addLayer({
84
- ...fullGeometryStyle.line,
85
- id: "full-geom-line",
86
- type: "line",
87
- source: "full-geom",
88
- });
89
+ if (fullGeometryStyle?.line) {
90
+ map.addLayer({
91
+ ...fullGeometryStyle?.line,
92
+ id: "full-geom-line",
93
+ type: "line",
94
+ source: "full-geom",
95
+ });
96
+ }
89
97
  }
90
98
 
91
99
  if (map.loaded()) {
@@ -97,7 +105,10 @@ export function createMaplibreglMapController(
97
105
  }
98
106
 
99
107
  const handleMapClick = (e: MapMouseEvent) => {
100
- mapClickHandler?.([e.lngLat.lng, e.lngLat.lat]);
108
+ eventHandler?.({
109
+ type: "mapClick",
110
+ coordinates: [e.lngLat.lng, e.lngLat.lat],
111
+ });
101
112
  };
102
113
 
103
114
  const handleMoveEnd = () => {
@@ -111,37 +122,46 @@ export function createMaplibreglMapController(
111
122
  if (prevProximity !== proximity) {
112
123
  prevProximity = proximity;
113
124
 
114
- proximityChangeHandler?.(proximity);
125
+ eventHandler?.({ type: "proximityChange", proximity });
115
126
  }
116
127
  };
117
128
 
129
+ function createMarker(interactive = false) {
130
+ if (!maplibregl) {
131
+ throw new Error();
132
+ }
133
+
134
+ const element = document.createElement("div");
135
+
136
+ if (interactive) {
137
+ element.classList.add("marker-interactive");
138
+ }
139
+
140
+ new MarkerIcon({
141
+ props: { displayIn: "maplibre" },
142
+ target: element,
143
+ });
144
+
145
+ return new maplibregl.Marker({ element, offset: [1, -13] });
146
+ }
147
+
118
148
  const ctrl: MapController = {
119
- setProximityChangeHandler(
120
- _proximityChangeHandler: ((proximity: Proximity) => void) | undefined
121
- ): void {
122
- if (_proximityChangeHandler) {
123
- proximityChangeHandler = _proximityChangeHandler;
149
+ setEventHandler(handler: undefined | ((e: MapEvent) => void)): void {
150
+ if (handler) {
151
+ eventHandler = handler;
124
152
 
125
153
  map.on("moveend", handleMoveEnd);
126
154
 
127
155
  handleMoveEnd();
156
+
157
+ map.on("click", handleMapClick);
128
158
  } else {
129
159
  map.off("moveend", handleMoveEnd);
130
160
 
131
- proximityChangeHandler?.(undefined);
161
+ eventHandler?.({ type: "proximityChange", proximity: undefined });
132
162
 
133
- proximityChangeHandler = undefined;
134
- }
135
- },
163
+ eventHandler = undefined;
136
164
 
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
165
  map.off("click", handleMapClick);
146
166
  }
147
167
  },
@@ -161,13 +181,43 @@ export function createMaplibreglMapController(
161
181
  },
162
182
 
163
183
  indicateReverse(reverse: boolean): void {
164
- map.getCanvas().style.cursor = reverse ? "crosshair" : "";
184
+ map.getCanvasContainer().style.cursor = reverse ? "crosshair" : "";
185
+ },
186
+
187
+ setReverseMarker(coordinates: [number, number]) {
188
+ if (!maplibregl || !marker) {
189
+ return;
190
+ }
191
+
192
+ if (reverseMarker) {
193
+ if (!coordinates) {
194
+ reverseMarker.remove();
195
+
196
+ reverseMarker = undefined;
197
+ } else {
198
+ reverseMarker.setLngLat(coordinates);
199
+ }
200
+ } else if (coordinates) {
201
+ reverseMarker = (
202
+ typeof marker === "object"
203
+ ? new maplibregl.Marker(marker)
204
+ : createMarker()
205
+ )
206
+ .setLngLat(coordinates)
207
+ .addTo(map);
208
+
209
+ reverseMarker.getElement().classList.add("marker-reverse");
210
+ }
165
211
  },
166
212
 
167
213
  setMarkers(
168
214
  markedFeatures: Feature[] | undefined,
169
215
  picked: Feature | undefined
170
216
  ): void {
217
+ if (!marker) {
218
+ return;
219
+ }
220
+
171
221
  function setData(data: GeoJSON.GeoJSON) {
172
222
  (map.getSource("full-geom") as GeoJSONSource)?.setData(data);
173
223
  }
@@ -184,17 +234,6 @@ export function createMaplibreglMapController(
184
234
  return;
185
235
  }
186
236
 
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
237
  if (picked) {
199
238
  let handled = false;
200
239
 
@@ -250,29 +289,52 @@ export function createMaplibreglMapController(
250
289
  return; // no pin for (multi)linestrings
251
290
  }
252
291
 
253
- markers.push(
254
- (typeof marker === "object"
255
- ? new maplibregl.Marker(marker)
256
- : createMarker()
257
- )
258
- .setLngLat(picked.center)
259
- .addTo(map)
260
- );
292
+ if (marker) {
293
+ markers.push(
294
+ (typeof marker === "object"
295
+ ? new maplibregl.Marker(marker)
296
+ : createMarker()
297
+ )
298
+ .setLngLat(picked.center)
299
+ .addTo(map)
300
+ );
301
+ }
261
302
  }
262
303
 
263
- for (const feature of markedFeatures ?? []) {
264
- if (feature === picked) {
265
- continue;
266
- }
304
+ if (showResultMarkers) {
305
+ for (const feature of markedFeatures ?? []) {
306
+ if (feature === picked) {
307
+ continue;
308
+ }
267
309
 
268
- markers.push(
269
- (typeof showResultMarkers === "object"
270
- ? new maplibregl.Marker(showResultMarkers)
271
- : createMarker()
310
+ const marker = (
311
+ typeof showResultMarkers === "object"
312
+ ? new maplibregl.Marker(showResultMarkers)
313
+ : createMarker(true)
272
314
  )
273
315
  .setLngLat(feature.center)
274
- .addTo(map)
275
- );
316
+ .addTo(map);
317
+
318
+ const element = marker.getElement();
319
+
320
+ element.addEventListener("click", (e) => {
321
+ e.stopPropagation();
322
+
323
+ eventHandler?.({ type: "markerClick", id: feature.id });
324
+ });
325
+
326
+ element.addEventListener("mouseenter", () => {
327
+ eventHandler?.({ type: "markerMouseEnter", id: feature.id });
328
+ });
329
+
330
+ element.addEventListener("mouseleave", () => {
331
+ eventHandler?.({ type: "markerMouseLeave", id: feature.id });
332
+ });
333
+
334
+ element.classList.toggle("marker-fuzzy", !!feature.matching_text);
335
+
336
+ markers.push(marker);
337
+ }
276
338
  }
277
339
  },
278
340
 
package/src/lib/types.ts CHANGED
@@ -6,6 +6,7 @@ export type Feature = GeoJSON.Feature & {
6
6
  center: [number, number];
7
7
  bbox: [number, number, number, number];
8
8
  address?: string;
9
+ matching_text?: string;
9
10
  };
10
11
 
11
12
  export type FeatureCollection = {
@@ -13,16 +14,18 @@ export type FeatureCollection = {
13
14
  features: Feature[];
14
15
  };
15
16
 
16
- export type MapController = {
17
- setProximityChangeHandler(
18
- proximityChangeHandler:
19
- | undefined
20
- | ((proximity: [number, number] | undefined) => void)
21
- ): void;
17
+ export type MapEvent =
18
+ | {
19
+ type: "proximityChange";
20
+ proximity: [number, number] | undefined;
21
+ }
22
+ | { type: "mapClick"; coordinates: [number, number] }
23
+ | { type: "markerClick"; id: string }
24
+ | { type: "markerMouseEnter"; id: string }
25
+ | { type: "markerMouseLeave"; id: string };
22
26
 
23
- setMapClickHandler(
24
- mapClickHandler: undefined | ((coordinates: [number, number]) => void)
25
- ): void;
27
+ export type MapController = {
28
+ setEventHandler(handler: undefined | ((e: MapEvent) => void)): void;
26
29
 
27
30
  flyTo(center: [number, number], zoom: number): void;
28
31
 
@@ -35,6 +38,8 @@ export type MapController = {
35
38
  picked: Feature | undefined
36
39
  ): void;
37
40
 
41
+ setReverseMarker(coordinates?: [number, number]): void;
42
+
38
43
  setSelectedMarker(index: number): void;
39
44
  };
40
45
 
@@ -101,12 +106,12 @@ export type ControlOptions = {
101
106
  */
102
107
  bbox?: [number, number, number, number];
103
108
 
104
- // /**
105
- // * Maximum number of results to show.
106
- // *
107
- // * @default 5
108
- // */
109
- // limit?: number;
109
+ /**
110
+ * Maximum number of results to show.
111
+ *
112
+ * @default 5
113
+ */
114
+ limit?: number;
110
115
 
111
116
  /**
112
117
  * Specify the language to use for response text and query result weighting.
@@ -114,7 +119,7 @@ export type ControlOptions = {
114
119
  * More than one value can also be specified, separated by commas.
115
120
  * Defaults to the browser's language settings.
116
121
  */
117
- language?: string;
122
+ language?: string | string[];
118
123
 
119
124
  /**
120
125
  * If `false`, indicates that search will only occur on enter key press.
@@ -124,19 +129,12 @@ export type ControlOptions = {
124
129
  */
125
130
  showResultsWhileTyping?: boolean;
126
131
 
127
- // /**
128
- // * Set to `false` to disable autocomplete.
129
- // *
130
- // * @default true
131
- // */
132
- // autocomplete?: boolean;
133
-
134
- // /**
135
- // * Set to `false` to disable fuzzy search.
136
- // *
137
- // * @default true
138
- // */
139
- // fuzzy?: boolean;
132
+ /**
133
+ * Set to `false` to disable fuzzy search.
134
+ *
135
+ * @default true
136
+ */
137
+ fuzzyMatch?: boolean;
140
138
 
141
139
  /**
142
140
  * On geocoded result what zoom level should the map animate to when a bbox isn't found in the response.
@@ -213,6 +211,20 @@ export type ControlOptions = {
213
211
  */
214
212
  showFullGeometry?: boolean;
215
213
 
214
+ /**
215
+ * Limit search to specified country(ies).
216
+ *
217
+ * @default undefined use all countries
218
+ */
219
+ country?: string | string[];
220
+
221
+ /**
222
+ * Filter of feature types to return.
223
+ *
224
+ * @default undefined all available feature types are returned
225
+ */
226
+ types?: string[];
227
+
216
228
  // TODO - missing but useful from maplibre-gl-geocoder
217
229
  // 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)
218
230
  // 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.