feat: make Mol explorer map-first
GeoIntel CI / docs-smoke (push) Canceled after 0s
GeoIntel CI / contract-smoke (push) Canceled after 0s

This commit is contained in:
Codex
2026-07-14 13:21:53 +02:00
parent e340b7f1ec
commit 2958c25b6f
24 changed files with 1901 additions and 14 deletions
+60 -1
View File
@@ -3,7 +3,7 @@ import maplibregl from 'maplibre-gl'
import 'maplibre-gl/dist/maplibre-gl.css'
import { PRIMARY_FOCUS_CENTER } from '../config/primaryFocus'
import { featureCollectionBounds } from '../lib/geojsonBounds'
import type { MapViewportState } from '../types'
import type { MapViewportState, VectorSelectionBBox } from '../types'
interface GeoMapProps {
data: GeoJSON.FeatureCollection | null
@@ -20,6 +20,8 @@ interface GeoMapProps {
fitDataOnChange?: boolean
onFeatureSelect?: (feature: GeoJSON.Feature | null) => void
onMapCoordinateSelect?: (coordinate: [number, number]) => void
onMapBboxPreview?: (bbox: VectorSelectionBBox) => void
onMapBboxSelect?: (bbox: VectorSelectionBBox) => void
onViewportChange?: (viewport: MapViewportState) => void
}
@@ -114,12 +116,16 @@ function GeoMap({
fitDataOnChange = true,
onFeatureSelect,
onMapCoordinateSelect,
onMapBboxPreview,
onMapBboxSelect,
onViewportChange,
}: GeoMapProps): JSX.Element {
const containerRef = useRef<HTMLDivElement | null>(null)
const mapRef = useRef<maplibregl.Map | null>(null)
const onFeatureSelectRef = useRef<GeoMapProps['onFeatureSelect']>(onFeatureSelect)
const onMapCoordinateSelectRef = useRef<GeoMapProps['onMapCoordinateSelect']>(onMapCoordinateSelect)
const onMapBboxPreviewRef = useRef<GeoMapProps['onMapBboxPreview']>(onMapBboxPreview)
const onMapBboxSelectRef = useRef<GeoMapProps['onMapBboxSelect']>(onMapBboxSelect)
const onViewportChangeRef = useRef<GeoMapProps['onViewportChange']>(onViewportChange)
const bboxSelectionModeRef = useRef(bboxSelectionMode)
const lastFittedAreaRef = useRef<GeoJSON.FeatureCollection | null>(null)
@@ -133,6 +139,14 @@ function GeoMap({
onMapCoordinateSelectRef.current = onMapCoordinateSelect
}, [onMapCoordinateSelect])
useEffect(() => {
onMapBboxPreviewRef.current = onMapBboxPreview
}, [onMapBboxPreview])
useEffect(() => {
onMapBboxSelectRef.current = onMapBboxSelect
}, [onMapBboxSelect])
useEffect(() => {
onViewportChangeRef.current = onViewportChange
}, [onViewportChange])
@@ -141,6 +155,11 @@ function GeoMap({
bboxSelectionModeRef.current = bboxSelectionMode
if (mapRef.current) {
mapRef.current.getCanvas().style.cursor = bboxSelectionMode ? 'crosshair' : ''
if (bboxSelectionMode) {
mapRef.current.dragPan.disable()
} else {
mapRef.current.dragPan.enable()
}
}
}, [bboxSelectionMode])
@@ -181,8 +200,48 @@ function GeoMap({
emitViewport()
})
map.on('moveend', emitViewport)
let dragStart: [number, number] | null = null
let draggedSelection = false
const bboxFromCoordinates = (start: [number, number], end: [number, number]): VectorSelectionBBox => ({
min_x: Math.min(start[0], end[0]),
min_y: Math.min(start[1], end[1]),
max_x: Math.max(start[0], end[0]),
max_y: Math.max(start[1], end[1]),
crs: 'EPSG:4326',
})
map.on('mousedown', (event) => {
if (!bboxSelectionModeRef.current || event.originalEvent.button !== 0) {
return
}
event.preventDefault()
dragStart = [event.lngLat.lng, event.lngLat.lat]
draggedSelection = false
map.getCanvas().style.cursor = 'crosshair'
})
map.on('mousemove', (event) => {
if (!bboxSelectionModeRef.current || !dragStart) {
return
}
draggedSelection = true
onMapBboxPreviewRef.current?.(bboxFromCoordinates(dragStart, [event.lngLat.lng, event.lngLat.lat]))
})
map.on('mouseup', (event) => {
if (!bboxSelectionModeRef.current || !dragStart) {
return
}
const start = dragStart
dragStart = null
const bbox = bboxFromCoordinates(start, [event.lngLat.lng, event.lngLat.lat])
if (bbox.max_x > bbox.min_x && bbox.max_y > bbox.min_y) {
onMapBboxSelectRef.current?.(bbox)
}
})
map.on('click', (event) => {
if (bboxSelectionModeRef.current) {
if (draggedSelection) {
draggedSelection = false
return
}
onMapCoordinateSelectRef.current?.([event.lngLat.lng, event.lngLat.lat])
return
}