|
| 1 | +'use client'; |
| 2 | + |
| 3 | +import { useEffect, useRef } from 'react'; |
| 4 | +import { Map } from 'maplibre-gl'; |
| 5 | +import 'maplibre-gl/dist/maplibre-gl.css'; |
| 6 | + |
| 7 | +export function BaseMap({ onMapLoaded, onCleanup }: { onMapLoaded?: (map: Map) => void; onCleanup?: () => void }) { |
| 8 | + const mapContainerRef = useRef<HTMLDivElement>(null); |
| 9 | + const mapRef = useRef<Map | null>(null); |
| 10 | + |
| 11 | + useEffect(() => { |
| 12 | + if (mapContainerRef.current === null) return; |
| 13 | + |
| 14 | + const map = new Map({ |
| 15 | + container: mapContainerRef.current, |
| 16 | + style: { |
| 17 | + version: 8, |
| 18 | + name: 'ExpTech Studio', |
| 19 | + sources: { |
| 20 | + map: { |
| 21 | + type: 'vector', |
| 22 | + url: 'https://lb.exptech.dev/api/v1/map/tiles/tiles.json', |
| 23 | + }, |
| 24 | + }, |
| 25 | + sprite: '', |
| 26 | + glyphs: 'https://glyphs.geolonia.com/{fontstack}/{range}.pbf', |
| 27 | + layers: [ |
| 28 | + { |
| 29 | + id: 'background', |
| 30 | + type: 'background', |
| 31 | + paint: { 'background-color': '#1f2025' }, |
| 32 | + }, |
| 33 | + { |
| 34 | + 'id': 'county', |
| 35 | + 'type': 'fill', |
| 36 | + 'source': 'map', |
| 37 | + 'source-layer': 'city', |
| 38 | + 'paint': { 'fill-color': '#3F4045' }, |
| 39 | + }, |
| 40 | + { |
| 41 | + 'id': 'county-outline', |
| 42 | + 'type': 'line', |
| 43 | + 'source': 'map', |
| 44 | + 'source-layer': 'city', |
| 45 | + 'paint': { 'line-color': '#a9b4bc' }, |
| 46 | + }, |
| 47 | + { |
| 48 | + 'id': 'town', |
| 49 | + 'type': 'fill', |
| 50 | + 'source': 'map', |
| 51 | + 'source-layer': 'town', |
| 52 | + 'paint': { 'fill-color': 'transparent' }, |
| 53 | + }, |
| 54 | + ], |
| 55 | + }, |
| 56 | + center: [121.6, 23.5], |
| 57 | + zoom: 6.8, |
| 58 | + attributionControl: false, |
| 59 | + pitchWithRotate: false, |
| 60 | + dragRotate: false, |
| 61 | + maxZoom: 12, |
| 62 | + minZoom: 4, |
| 63 | + }); |
| 64 | + |
| 65 | + mapRef.current = map; |
| 66 | + |
| 67 | + const MAP_BOUNDS = [[118.0, 21.2], [124.0, 25.8]] as [[number, number], [number, number]]; |
| 68 | + void map.fitBounds(MAP_BOUNDS, { padding: 20, duration: 0 }); |
| 69 | + |
| 70 | + if (onMapLoaded) onMapLoaded(map); |
| 71 | + |
| 72 | + map.on('error', () => void 0); |
| 73 | + |
| 74 | + return () => { |
| 75 | + if (onCleanup) onCleanup(); |
| 76 | + map.remove(); |
| 77 | + }; |
| 78 | + }, []); |
| 79 | + |
| 80 | + return <div ref={mapContainerRef} className="h-full w-full" />; |
| 81 | +} |
0 commit comments