feat: make Mol explorer map-first
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user