Harden MapLibre style readiness
This commit is contained in:
@@ -162,6 +162,7 @@ React + TypeScript + MapLibre foundation for project/area/dataset workflow.
|
||||
- The strip summarizes existing connected state for project, AOI, datasets, active map layer, persisted QA/QC results and exports.
|
||||
- It suggests the next operator action based on missing V1 loop state without calling new APIs or adding backend behavior.
|
||||
- The status strip is implemented in `src/components/WorkbenchStatusStrip.tsx` and remains driven by `App.tsx` orchestration state.
|
||||
- MapLibre source/layer updates now wait for style readiness to avoid runtime blank-screen failures during first render.
|
||||
|
||||
## Release hardening updates
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useEffect, useRef } from 'react'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import maplibregl from 'maplibre-gl'
|
||||
import 'maplibre-gl/dist/maplibre-gl.css'
|
||||
|
||||
@@ -63,6 +63,7 @@ function GeoMap({
|
||||
const containerRef = useRef<HTMLDivElement | null>(null)
|
||||
const mapRef = useRef<maplibregl.Map | null>(null)
|
||||
const onFeatureSelectRef = useRef<GeoMapProps['onFeatureSelect']>(onFeatureSelect)
|
||||
const [mapStyleReady, setMapStyleReady] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
onFeatureSelectRef.current = onFeatureSelect
|
||||
@@ -80,6 +81,9 @@ function GeoMap({
|
||||
zoom: 9,
|
||||
})
|
||||
map.addControl(new maplibregl.NavigationControl(), 'top-right')
|
||||
map.on('load', () => {
|
||||
setMapStyleReady(true)
|
||||
})
|
||||
map.on('click', (event) => {
|
||||
const layers = ['dataset-fill', 'dataset-line', 'area-fill', 'area-line'].filter((layerId) => map.getLayer(layerId))
|
||||
if (layers.length === 0) {
|
||||
@@ -101,12 +105,13 @@ function GeoMap({
|
||||
return () => {
|
||||
map.remove()
|
||||
mapRef.current = null
|
||||
setMapStyleReady(false)
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
const map = mapRef.current
|
||||
if (!map) {
|
||||
if (!map || !mapStyleReady || !map.isStyleLoaded()) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -174,11 +179,11 @@ function GeoMap({
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [data])
|
||||
}, [data, mapStyleReady])
|
||||
|
||||
useEffect(() => {
|
||||
const map = mapRef.current
|
||||
if (!map) {
|
||||
if (!map || !mapStyleReady || !map.isStyleLoaded()) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -231,11 +236,11 @@ function GeoMap({
|
||||
map.fitBounds(bounds, { padding: 40 })
|
||||
}
|
||||
}
|
||||
}, [areaData, data])
|
||||
}, [areaData, data, mapStyleReady])
|
||||
|
||||
useEffect(() => {
|
||||
const map = mapRef.current
|
||||
if (!map) {
|
||||
if (!map || !mapStyleReady || !map.isStyleLoaded()) {
|
||||
return
|
||||
}
|
||||
const visibility = visible ? 'visible' : 'none'
|
||||
@@ -247,11 +252,11 @@ function GeoMap({
|
||||
map.setLayoutProperty('dataset-line', 'visibility', visibility)
|
||||
map.setPaintProperty('dataset-line', 'line-opacity', visible ? 1 : 0)
|
||||
}
|
||||
}, [visible, opacity, data])
|
||||
}, [visible, opacity, data, mapStyleReady])
|
||||
|
||||
useEffect(() => {
|
||||
const map = mapRef.current
|
||||
if (!map) {
|
||||
if (!map || !mapStyleReady || !map.isStyleLoaded()) {
|
||||
return
|
||||
}
|
||||
const visibility = areaVisible ? 'visible' : 'none'
|
||||
@@ -263,7 +268,7 @@ function GeoMap({
|
||||
map.setLayoutProperty('area-line', 'visibility', visibility)
|
||||
map.setPaintProperty('area-line', 'line-opacity', areaVisible ? 1 : 0)
|
||||
}
|
||||
}, [areaVisible, areaOpacity, areaData])
|
||||
}, [areaVisible, areaOpacity, areaData, mapStyleReady])
|
||||
|
||||
return <div className="map-container" ref={containerRef} />
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user