Keep selected area as map viewport
GeoIntel release gates / Compile, test, contracts and builds (push) Canceled after 0s
GeoIntel release gates / Python and npm vulnerability policy (push) Canceled after 0s
GeoIntel release gates / GIS image, SBOM and container scan (push) Canceled after 0s

This commit is contained in:
Codex
2026-07-19 02:26:54 +02:00
parent c97cb5bdd3
commit 0bf6068817
3 changed files with 10 additions and 23 deletions
@@ -48,8 +48,8 @@ def test_map_rectangle_drag_is_wired_to_automatic_analysis() -> None:
assert "resizeObserver.observe(containerRef.current)" in geomap assert "resizeObserver.observe(containerRef.current)" in geomap
assert "fitDataOnChangeRef.current" in geomap assert "fitDataOnChangeRef.current" in geomap
assert "map.fitBounds(bounds, { padding: 40, duration: 0 })" in geomap assert "map.fitBounds(bounds, { padding: 40, duration: 0 })" in geomap
assert "const areaChanged = lastFittedAreaRef.current !== areaData" in geomap assert "const activeCollection = areaData ?? (fitDataOnChange ? data : null)" in geomap
assert "areaChanged && areaData" in geomap assert "data && fitDataOnChange && !areaData" in geomap
assert "resizeObserver.disconnect()" in geomap assert "resizeObserver.disconnect()" in geomap
assert ".workbench-main .geo-map-canvas .map-container" in styles assert ".workbench-main .geo-map-canvas .map-container" in styles
assert "position: absolute;" in styles assert "position: absolute;" in styles
+2 -1
View File
@@ -46,7 +46,8 @@
available only through an exact bounded request. available only through an exact bounded request.
- Live browser verification found that a changed work area was fitted together - Live browser verification found that a changed work area was fitted together
with the complete active national layer. Area changes now fit the selected with the complete active national layer. Area changes now fit the selected
geography first; subsequent layer changes retain the existing fit behavior. geography first and retain that viewport when a complete national layer is
loaded on the following render or the map container resizes.
- Focused backend and frontend suites passed before full release validation; - Focused backend and frontend suites passed before full release validation;
full local and Tower evidence follows in the final P5 gate. full local and Tower evidence follows in the final P5 gate.
+6 -20
View File
@@ -110,11 +110,6 @@ function collectCoordinates(featureCollection: GeoJSON.FeatureCollection): mapli
] ]
} }
function mergeFeatureCollections(collections: Array<GeoJSON.FeatureCollection | null | undefined>): GeoJSON.FeatureCollection | null {
const features = collections.flatMap((collection) => collection?.features ?? [])
return features.length > 0 ? { type: 'FeatureCollection', features } : null
}
function bboxToFeatureCollection( function bboxToFeatureCollection(
bbox: { min_x: number; min_y: number; max_x: number; max_y: number } | null | undefined, bbox: { min_x: number; min_y: number; max_x: number; max_y: number } | null | undefined,
): GeoJSON.FeatureCollection { ): GeoJSON.FeatureCollection {
@@ -179,7 +174,6 @@ function GeoMap({
const areaDataRef = useRef<GeoJSON.FeatureCollection | null>(areaData) const areaDataRef = useRef<GeoJSON.FeatureCollection | null>(areaData)
const dataRef = useRef<GeoJSON.FeatureCollection | null>(data) const dataRef = useRef<GeoJSON.FeatureCollection | null>(data)
const fitDataOnChangeRef = useRef(fitDataOnChange) const fitDataOnChangeRef = useRef(fitDataOnChange)
const lastFittedAreaRef = useRef<GeoJSON.FeatureCollection | null>(null)
const imageOverlayIdsRef = useRef<string[]>([]) const imageOverlayIdsRef = useRef<string[]>([])
const [mapStyleReady, setMapStyleReady] = useState(false) const [mapStyleReady, setMapStyleReady] = useState(false)
@@ -233,9 +227,8 @@ function GeoMap({
}) })
const resizeObserver = new ResizeObserver(() => { const resizeObserver = new ResizeObserver(() => {
map.resize() map.resize()
const fitCollection = fitDataOnChangeRef.current const fitCollection = areaDataRef.current
? mergeFeatureCollections([areaDataRef.current, dataRef.current]) ?? (fitDataOnChangeRef.current ? dataRef.current : null)
: areaDataRef.current
const bounds = fitCollection ? collectCoordinates(fitCollection) : null const bounds = fitCollection ? collectCoordinates(fitCollection) : null
if (bounds && map.isStyleLoaded()) { if (bounds && map.isStyleLoaded()) {
map.fitBounds(bounds, { padding: 40, duration: 0 }) map.fitBounds(bounds, { padding: 40, duration: 0 })
@@ -428,7 +421,7 @@ function GeoMap({
}) })
} }
if (data && fitDataOnChange) { if (data && fitDataOnChange && !areaData) {
const collection = data const collection = data
if (collection.type === 'FeatureCollection' && collection.features.length > 0) { if (collection.type === 'FeatureCollection' && collection.features.length > 0) {
const bounds = collectCoordinates(collection) const bounds = collectCoordinates(collection)
@@ -437,7 +430,7 @@ function GeoMap({
} }
} }
} }
}, [data, dataFillColor, dataLineColor, fitDataOnChange, mapStyleReady]) }, [areaData, data, dataFillColor, dataLineColor, fitDataOnChange, mapStyleReady])
useEffect(() => { useEffect(() => {
const map = mapRef.current const map = mapRef.current
@@ -500,20 +493,13 @@ function GeoMap({
) )
} }
const areaChanged = lastFittedAreaRef.current !== areaData const activeCollection = areaData ?? (fitDataOnChange ? data : null)
const activeCollection = areaChanged && areaData if (activeCollection) {
? areaData
: fitDataOnChange
? mergeFeatureCollections([areaData, data])
: areaData
const shouldFitArea = fitDataOnChange || areaChanged
if (activeCollection && shouldFitArea) {
const bounds = collectCoordinates(activeCollection) const bounds = collectCoordinates(activeCollection)
if (bounds) { if (bounds) {
map.fitBounds(bounds, { padding: 40 }) map.fitBounds(bounds, { padding: 40 })
} }
} }
lastFittedAreaRef.current = areaData
}, [areaData, data, fitDataOnChange, mapStyleReady]) }, [areaData, data, fitDataOnChange, mapStyleReady])
useEffect(() => { useEffect(() => {