Geocode with Nominatim
This guide will show you how to set up geocoding with nomatim
-
Install the nomatim geocoder library.
Terminal window bun add @maplibre/maplibre-gl-geocoder -
Define the Geocoder API Endpoint:
geoapi.ts import {MaplibreGeocoderOptions} from '@maplibre/maplibre-gl-geocoder';import * as maplibre from "maplibre-gl";export type GeocoderControlProps = Omit<MaplibreGeocoderOptions, "maplibregl" | "marker"> & {marker?: boolean | Partial<maplibregl.MarkerOptions>;position?: maplibregl.ControlPosition;onLoading?: (e: any) => void;onResults?: (e: any) => void;onResult?: (e: any) => void;onError?: (e: any) => void;};const geocoderApi: MaplibreGeocoderApi = {// @ts-expect-errorforwardGeocode: async (config) => {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];features.push({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});}} catch (e) {console.error("Geocode error", e);}return { features };}}; -
Create The
GeocoderControl
that gets theGeocoder API
:geocoder-control.tsx import type {GeocoderControlProps} from './geoapi.ts'import * as maplibre from "maplibre-gl";import { onCleanup, splitProps, createSignal, type JSX, Show } from "solid-js";import { Marker, useMapEffect } from "solidjs-maplibre-gl";export function GeocoderControl(initial: GeocoderControlProps): JSX.Element {const [props, rest] = splitProps(initial, ["marker","position","onLoading","onResults","onResult","onError"]);const [markerLngLat, setMarkerLngLat] = createSignal<maplibregl.LngLatLike>();useMapEffect((map) => {const control = new MaplibreGeocoder(geocoderApi, {...rest,marker: true,maplibregl: maplibre});if (props.onLoading) control.on("loading", props.onLoading);if (props.onResults) control.on("results", props.onResults);if (props.onError) control.on("error", props.onError);control.on("result", (e) => {props.onResult?.(e);const result = e.result;const coords = result.center || result.geometry?.coordinates;if (coords && props.marker) {setMarkerLngLat(coords);} else {setMarkerLngLat(undefined);}});map.addControl(control, props.position || "top-right");onCleanup(() => {map.removeControl(control);});});return (<Show when={markerLngLat()}><Markerlnglat={markerLngLat()!}{...(typeof props.marker === "object" ? props.marker : {})}/></Show>)} -
Now pass in the Controller to a maplibre map.
Geocoder.tsx import type Component from 'solid-js'import { Maplibre } from "solidjs-maplibre-gl";import { GeocoderControl } from "./geocoder-control.tsx"import "maplibre-gl/dist/maplibre-gl.css";import '@maplibre/maplibre-gl-geocoder/dist/maplibre-gl-geocoder.css';const Geocoder: Component = (props) => {return (<Maplibrestyle={{height: "55vh","min-height":'300px'}}options={{center: [-79.4512, 43.6568],zoom: 13,style:"https://tiles.openfreemap.org/styles/bright"}}><GeocoderControl position="top-left" marker={true}/></Maplibre>);};export default Geocoder;