1- import { useState , useEffect } from "react" ;
1+ import { useEffect , useState } from "react" ;
22import { MapContainer , TileLayer , useMap } from "react-leaflet" ;
33import SvgSymbol from "../../SvgSymbol/SvgSymbol" ;
44import "leaflet/dist/leaflet.css" ;
55import "leaflet-lasso" ;
6- import BoundsSelector from "./components/BoundsSelector " ;
6+ import L from "leaflet " ;
77import { FormattedMessage } from "react-intl" ;
88import messages from "./Messages" ;
9+ import BoundsSelector from "./components/BoundsSelector" ;
910import { usePriorityBoundsData } from "./context/PriorityBoundsDataContext" ;
1011
1112const MapViewPreserver = ( { onViewChange } ) => {
@@ -31,21 +32,101 @@ const MapViewPreserver = ({ onViewChange }) => {
3132 return null ;
3233} ;
3334
35+ const AutoZoomToBounds = ( {
36+ boundsData,
37+ hasZoomed,
38+ setHasZoomed,
39+ allPriorityBounds,
40+ priorityType,
41+ } ) => {
42+ const map = useMap ( ) ;
43+
44+ useEffect ( ( ) => {
45+ if ( ! map || hasZoomed ) {
46+ return ;
47+ }
48+
49+ try {
50+ // Calculate bounds from all available polygon data
51+ const leafletBounds = L . latLngBounds ( ) ;
52+ let hasValidBounds = false ;
53+
54+ // First, try to use the current priority bounds
55+ if ( boundsData && boundsData . length > 0 ) {
56+ boundsData . forEach ( ( feature ) => {
57+ if ( feature ?. geometry ?. coordinates ?. [ 0 ] ) {
58+ const coords = feature . geometry . coordinates [ 0 ] ;
59+ coords . forEach ( ( coord ) => {
60+ if ( Array . isArray ( coord ) && coord . length >= 2 ) {
61+ // Convert from [lng, lat] to [lat, lng]
62+ leafletBounds . extend ( [ coord [ 1 ] , coord [ 0 ] ] ) ;
63+ hasValidBounds = true ;
64+ }
65+ } ) ;
66+ }
67+ } ) ;
68+ }
69+
70+ // If no bounds from current priority, try to use all priority bounds
71+ if ( ! hasValidBounds && allPriorityBounds ) {
72+ Object . entries ( allPriorityBounds ) . forEach ( ( [ type , priorityData ] ) => {
73+ if ( Array . isArray ( priorityData ) && priorityData . length > 0 ) {
74+ priorityData . forEach ( ( feature ) => {
75+ if ( feature ?. geometry ?. coordinates ?. [ 0 ] ) {
76+ const coords = feature . geometry . coordinates [ 0 ] ;
77+ coords . forEach ( ( coord ) => {
78+ if ( Array . isArray ( coord ) && coord . length >= 2 ) {
79+ // Convert from [lng, lat] to [lat, lng]
80+ leafletBounds . extend ( [ coord [ 1 ] , coord [ 0 ] ] ) ;
81+ hasValidBounds = true ;
82+ }
83+ } ) ;
84+ }
85+ } ) ;
86+ }
87+ } ) ;
88+ }
89+
90+ if ( hasValidBounds ) {
91+ // Add some padding to the bounds
92+ const paddedBounds = leafletBounds . pad ( 0.1 ) ;
93+
94+ // Fit the map to the bounds with a slight delay to ensure map is ready
95+ setTimeout ( ( ) => {
96+ map . fitBounds ( paddedBounds , {
97+ padding : [ 20 , 20 ] ,
98+ maxZoom : 16 , // Prevent zooming in too far
99+ animate : true ,
100+ duration : 0.5 ,
101+ } ) ;
102+ } , 100 ) ;
103+
104+ setHasZoomed ( true ) ;
105+ }
106+ } catch ( error ) {
107+ console . error ( "Error calculating bounds for auto-zoom:" , error ) ;
108+ }
109+ } , [ map , boundsData , hasZoomed , setHasZoomed , allPriorityBounds , priorityType ] ) ;
110+
111+ return null ;
112+ } ;
113+
34114/**
35115 * Custom field for selecting priority bounds on a map
36116 */
37117const CustomPriorityBoundsField = ( props ) => {
38118 const [ isMapVisible , setIsMapVisible ] = useState ( false ) ;
39119 const [ viewState , setViewState ] = useState ( { center : [ 0 , 0 ] , zoom : 2 } ) ;
120+ const [ hasZoomed , setHasZoomed ] = useState ( false ) ;
40121
41122 // Determine priority type from field name
42123 const priorityType = props . name ?. includes ( "highPriorityBounds" )
43124 ? "high"
44125 : props . name ?. includes ( "mediumPriorityBounds" )
45- ? "medium"
46- : props . name ?. includes ( "lowPriorityBounds" )
47- ? "low"
48- : "default" ;
126+ ? "medium"
127+ : props . name ?. includes ( "lowPriorityBounds" )
128+ ? "low"
129+ : "default" ;
49130
50131 const formData = props . formData || [ ] ;
51132 const { priorityBoundsData, updatePriorityBounds } = usePriorityBoundsData ( ) ;
@@ -83,6 +164,13 @@ const CustomPriorityBoundsField = (props) => {
83164 }
84165 } , [ formData ] ) ;
85166
167+ // Reset zoom flag when map becomes visible or data changes
168+ useEffect ( ( ) => {
169+ if ( isMapVisible ) {
170+ setHasZoomed ( false ) ;
171+ }
172+ } , [ isMapVisible ] ) ;
173+
86174 const handleChange = ( newData ) => {
87175 if ( typeof props . onChange === "function" ) {
88176 props . onChange ( Array . isArray ( newData ) ? [ ...newData ] : newData ) ;
@@ -142,6 +230,14 @@ const CustomPriorityBoundsField = (props) => {
142230 attribution = '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
143231 />
144232
233+ < AutoZoomToBounds
234+ boundsData = { formData }
235+ hasZoomed = { hasZoomed }
236+ setHasZoomed = { setHasZoomed }
237+ allPriorityBounds = { priorityBoundsData }
238+ priorityType = { priorityType }
239+ />
240+
145241 < BoundsSelector
146242 value = { formData }
147243 onChange = { handleChange }
0 commit comments