diff --git a/cypress/e2e/map.cy.ts b/cypress/e2e/map.cy.ts index cfec8810..c8c11cb3 100644 --- a/cypress/e2e/map.cy.ts +++ b/cypress/e2e/map.cy.ts @@ -23,4 +23,10 @@ describe("map", () => { ); }); }); + + describe("search", () => { + it('should exist', () => { + then(get.searchControl()).shouldBeVisible(); + }); + }); }); diff --git a/cypress/e2e/maputnik-driver.ts b/cypress/e2e/maputnik-driver.ts index 45ca2543..ca8a3d01 100644 --- a/cypress/e2e/maputnik-driver.ts +++ b/cypress/e2e/maputnik-driver.ts @@ -177,5 +177,6 @@ export class MaputnikDriver { skipTargetLayerEditor: () => this.helper.get.elementByTestId("skip-target-layer-editor"), canvas: () => this.helper.get.element("canvas"), + searchControl: () => this.helper.get.element('.maplibregl-ctrl-geocoder') }; } diff --git a/package-lock.json b/package-lock.json index 00962ed8..ce73cdc2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "license": "MIT", "dependencies": { "@mapbox/mapbox-gl-rtl-text": "^0.2.3", + "@maplibre/maplibre-gl-geocoder": "^1.5.0", "@maplibre/maplibre-gl-style-spec": "^20.1.0", "@mdi/js": "^6.6.96", "@mdi/react": "^1.5.0", @@ -2572,6 +2573,23 @@ "node": ">=6.0.0" } }, + "node_modules/@maplibre/maplibre-gl-geocoder": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-geocoder/-/maplibre-gl-geocoder-1.5.0.tgz", + "integrity": "sha512-PsAbV7WFIOu5QYZne95FiXoV7AV1/6ULMjQxgInhZ5DdB0hDLjciQPegnyDgkzI8JfeqoUMZVS/MglZnSZYhyQ==", + "dependencies": { + "lodash.debounce": "^4.0.6", + "subtag": "^0.5.0", + "suggestions-list": "^0.0.2", + "xtend": "^4.0.1" + }, + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "maplibre-gl": ">=1.14.0" + } + }, "node_modules/@maplibre/maplibre-gl-style-spec": { "version": "20.1.0", "resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-20.1.0.tgz", @@ -7229,6 +7247,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/fuzzy": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/fuzzy/-/fuzzy-0.1.3.tgz", + "integrity": "sha512-/gZffu4ykarLrCiP3Ygsa86UAo1E5vEVlvTrpkKywXSbP9Xhln3oSp9QSV57gEq3JFFpGJ4GZ+5zdEp3FcUh4w==", + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -9211,9 +9237,7 @@ "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", - "dev": true, - "peer": true + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" }, "node_modules/lodash.flattendeep": { "version": "4.4.0", @@ -12756,6 +12780,20 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, + "node_modules/subtag": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/subtag/-/subtag-0.5.0.tgz", + "integrity": "sha512-CaIBcTSb/nyk4xiiSOtZYz1B+F12ZxW8NEp54CdT+84vmh/h4sUnHGC6+KQXUfED8u22PQjCYWfZny8d2ELXwg==" + }, + "node_modules/suggestions-list": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/suggestions-list/-/suggestions-list-0.0.2.tgz", + "integrity": "sha512-Yw0fdq14c6RQWQIfE1/8WEi9Dp8rjyCD6FhYA/Tit2/ADbE9Y4ADG4ezlvivsa8Civ5nz++pyVVBMjOMlgIUJw==", + "dependencies": { + "fuzzy": "^0.1.1", + "xtend": "^4.0.0" + } + }, "node_modules/supercluster": { "version": "7.1.5", "resolved": "https://registry.npmjs.org/supercluster/-/supercluster-7.1.5.tgz", @@ -14417,6 +14455,14 @@ "resolved": "https://registry.npmjs.org/xml-utils/-/xml-utils-1.7.0.tgz", "integrity": "sha512-bWB489+RQQclC7A9OW8e5BzbT8Tu//jtAOvkYwewFr+Q9T9KDGvfzC1lp0pYPEQPEoPQLDkmxkepSC/2gIAZGw==" }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/package.json b/package.json index b5b9c67c..93a284ac 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "homepage": "https://github.com/maplibre/maputnik#readme", "dependencies": { "@mapbox/mapbox-gl-rtl-text": "^0.2.3", + "@maplibre/maplibre-gl-geocoder": "^1.5.0", "@maplibre/maplibre-gl-style-spec": "^20.1.0", "@mdi/js": "^6.6.96", "@mdi/react": "^1.5.0", diff --git a/src/components/MapMaplibreGl.tsx b/src/components/MapMaplibreGl.tsx index 46c3fffe..1d440d36 100644 --- a/src/components/MapMaplibreGl.tsx +++ b/src/components/MapMaplibreGl.tsx @@ -13,6 +13,9 @@ import { HighlightedLayer, colorHighlightedLayer } from '../libs/highlight' import 'maplibre-gl/dist/maplibre-gl.css' import '../maplibregl.css' import '../libs/maplibre-rtl' +//@ts-ignore +import MaplibreGeocoder from '@maplibre/maplibre-gl-geocoder'; +import '@maplibre/maplibre-gl-geocoder/dist/maplibre-gl-geocoder.css'; function renderPopup(popup: JSX.Element, mountNode: ReactDOM.Container) { ReactDOM.render(popup, mountNode); @@ -160,6 +163,8 @@ export default class MapMaplibreGl extends React.Component { + const features = []; + try { + const request = `https://nominatim.openstreetmap.org/search?q=${config.query}&format=geojson&polygon_geojson=1&addressdetails=1`; + const response = await fetch(request); + const geojson = await response.json(); + for (const feature of geojson.features) { + const center = [ + feature.bbox[0] + + (feature.bbox[2] - feature.bbox[0]) / 2, + feature.bbox[1] + + (feature.bbox[3] - feature.bbox[1]) / 2 + ]; + const point = { + type: 'Feature', + geometry: { + type: 'Point', + coordinates: center + }, + place_name: feature.properties.display_name, + properties: feature.properties, + text: feature.properties.display_name, + place_type: ['place'], + center + }; + features.push(point); + } + } catch (e) { + console.error(`Failed to forwardGeocode with error: ${e}`); + } + return { + features + }; + } + }; + const geocoder = new MaplibreGeocoder(geocoderConfig, {maplibregl: MapLibreGl}); + map.addControl(geocoder, 'top-left'); + } + render() { return