| import React, { useRef, useEffect, useState } from 'react'; |
| import maplibregl from 'maplibre-gl'; |
| import MaplibreInspect from '@/lib/maplibre/dist/maplibre-gl-inspect/maplibre-gl-inspect'; |
| import MaplibreTileBoundaries from '@/lib/maplibre/dist/maplibre-gl-tile-boundaries/maplibre-gl-tile-boundaries'; |
| |
| import styles from './style.module.css'; |
| import { GeocoderSearch } from '../GeocoderSearch'; |
| |
| interface MapProps { |
| longitude?: number; |
| latitude?: number; |
| zoom?: number; |
| mapStyle?: string | maplibregl.StyleSpecification; |
| /** |
| * 'getMapStyle' a function we might want to fetch the style from the server |
| * |
| * Note: This precedes 'mapStyle' if both are defined |
| */ |
| getMapStyle?: () => Promise<string | maplibregl.StyleSpecification>; |
| mapOptions?: Partial<maplibregl.MapOptions>; |
| /** |
| * 'getControls' a function because some controls access the window object |
| * which is not available until the component is mounted |
| */ |
| getControls?: () => maplibregl.IControl[]; |
| geocoder?: boolean; |
| ipToLoc?: boolean; |
| } |
| |
| export const getDefaultControls = (): maplibregl.IControl[] => [ |
| // Add navigation control (the +/- zoom and compass buttons) |
| new maplibregl.NavigationControl({}), |
| // Add the inspect control to the map. |
| new MaplibreInspect({ |
| showMapPopup: true, |
| showMapPopupOnHover: false, |
| showInspectMapPopupOnHover: false, |
| popup: new maplibregl.Popup({ |
| closeButton: true, |
| closeOnClick: true |
| }) |
| }), |
| // Add the tile boundaries control to the map. |
| new MaplibreTileBoundaries({ |
| showBoundaries: false |
| }) |
| ]; |
| |
| export default function Map({ |
| longitude = 6.625, |
| latitude = 46.51, |
| zoom = 14, |
| mapStyle = `https://demo.baremaps.com/style.json`, |
| getMapStyle, |
| mapOptions = {} as maplibregl.MapOptions, |
| getControls = getDefaultControls, |
| geocoder = true, |
| ipToLoc = true |
| }: MapProps) { |
| const mapContainer = useRef(null); |
| const [map, setMap] = useState(null); |
| |
| // Initialize map when component mounts |
| useEffect(() => { |
| if (maplibregl.getRTLTextPluginStatus() === 'unavailable') { |
| maplibregl.setRTLTextPlugin( |
| 'https://unpkg.com/@mapbox/mapbox-gl-rtl-text@0.2.3/mapbox-gl-rtl-text.min.js', |
| null, |
| true |
| ); |
| } |
| |
| const initMap = async () => { |
| if (ipToLoc) { |
| try { |
| const response = await fetch(`https://demo.baremaps.com/api/iploc`); |
| const results = await response.json(); |
| if (results.length > 0) { |
| longitude = results[0].longitude; |
| latitude = results[0].latitude; |
| } |
| } catch (err) { |
| // For the moment, we fallback to the default values |
| } |
| } |
| const newMap = new maplibregl.Map({ |
| container: mapContainer.current, |
| style: getMapStyle !== undefined ? await getMapStyle() : mapStyle, |
| center: [longitude, latitude], |
| zoom: zoom, |
| ...mapOptions |
| }); |
| // Add default controls |
| getControls().forEach(control => { |
| newMap.addControl(control); |
| }); |
| |
| setMap(newMap); |
| }; |
| initMap(); |
| }, []); |
| |
| return ( |
| <div className={styles.wrap}> |
| {geocoder && ( |
| <GeocoderSearch |
| url="https://demo.baremaps.com/api/geocoder" |
| map={map} |
| /> |
| )} |
| <div ref={mapContainer} className={styles.map} /> |
| </div> |
| ); |
| } |