@@ -29,6 +29,7 @@ import {
2929 addMapLayer ,
3030 createBaseExpressions ,
3131 removeVectorLayer ,
32+ waitForStyleLoad ,
3233} from '../../../utils/map-coloring' ;
3334import { isMapRemoved as checkMapRemoved , markMapAsRemoved as markMapRemoved } from '../../../utils/map-instance-tracker' ;
3435import Map from '../../map' ;
@@ -43,20 +44,24 @@ const HistoricalMap = (props) => {
4344 const {
4445 availableStates,
4546 availableSublocations,
47+ county,
4648 dataMode,
4749 predictionYear,
50+ rangerDistrict,
4851 selectedState,
4952 setCounty,
5053 setRangerDistrict,
5154 setState,
55+ setCountyFilter,
56+ setRangerDistrictFilter,
57+ setStateFilter,
58+ clearAllSelections,
5259 sublocationData : rawData ,
5360 } = props ;
5461
5562 const {
5663 map,
5764 setMap,
58- initialFill,
59- setInitialFill,
6065 hover : trappingHover ,
6166 setHover : setTrappingHover ,
6267 isDownloadingMap,
@@ -65,6 +70,26 @@ const HistoricalMap = (props) => {
6570
6671 const allRangerDistricts = useRangerDistricts ( dataMode ) ;
6772
73+ const colorFillTimeoutRef = useRef ( null ) ;
74+ const isMountedRef = useRef ( true ) ;
75+ const styleRetryCountRef = useRef ( 0 ) ;
76+ const containerCheckTimeoutRef = useRef ( null ) ;
77+
78+ useEffect ( ( ) => {
79+ isMountedRef . current = true ;
80+ return ( ) => {
81+ isMountedRef . current = false ;
82+ if ( colorFillTimeoutRef . current ) {
83+ clearTimeout ( colorFillTimeoutRef . current ) ;
84+ colorFillTimeoutRef . current = null ;
85+ }
86+ if ( containerCheckTimeoutRef . current ) {
87+ clearTimeout ( containerCheckTimeoutRef . current ) ;
88+ containerCheckTimeoutRef . current = null ;
89+ }
90+ } ;
91+ } , [ ] ) ;
92+
6893 const createMapHoverCallback = useCallback ( ( allData , rangerDistricts , mode , state , availStates ) => {
6994 const callback = ( hoverState , location , x , y , counties ) => {
7095 const sublocation = mode === DATA_MODES . COUNTY ? 'county' : 'rangerDistrict' ;
@@ -96,14 +121,11 @@ const HistoricalMap = (props) => {
96121 return createHoverCallback ( map , rangerDistricts , dataMode , callback ) ;
97122 } , [ map , dataMode , setTrappingHover ] ) ;
98123
99- const colorFill = ( d ) => {
100- if ( ! map ) return ;
124+ const colorFill = useCallback ( ( d ) => {
125+ if ( ! isMountedRef . current || ! map ) return false ;
101126
102- if ( ! map . isStyleLoaded ( ) ) {
103- setTimeout ( ( ) => {
104- colorFill ( d ) ;
105- } , 1000 ) ;
106- return ;
127+ if ( ! waitForStyleLoad ( map , colorFill , [ d ] , colorFillTimeoutRef , isMountedRef , styleRetryCountRef ) ) {
128+ return false ;
107129 }
108130
109131 removeVectorLayer ( map ) ;
@@ -114,14 +136,27 @@ const HistoricalMap = (props) => {
114136 const filteredData = d . filter ( ( item ) => {
115137 const itemYear = parseYearFromItem ( item ) ;
116138 if ( itemYear === null ) return false ;
117- return itemYear === selectedYear ;
139+ if ( itemYear !== selectedYear ) return false ;
140+
141+ // Apply visual filtering based on selected state, county, and rangerDistrict
142+ if ( selectedState && item . state !== selectedState ) return false ;
143+
144+ if ( dataMode === DATA_MODES . COUNTY && county && county . length > 0 ) {
145+ if ( ! county . includes ( item . county ) ) return false ;
146+ }
147+
148+ if ( dataMode === DATA_MODES . RANGER_DISTRICT && rangerDistrict && rangerDistrict . length > 0 ) {
149+ if ( ! rangerDistrict . includes ( item . rangerDistrict ) ) return false ;
150+ }
151+
152+ return true ;
118153 } ) ;
119154
120155 const trappingsByLocality = filteredData . reduce ( ( acc , curr ) => {
121156 const {
122- county,
123- rangerDistrict,
124- state,
157+ county : itemCounty ,
158+ rangerDistrict : itemRangerDistrict ,
159+ state : itemState ,
125160 sumSpotst0,
126161 spotst0,
127162 spots,
@@ -136,8 +171,8 @@ const HistoricalMap = (props) => {
136171 spotsValue = spots ;
137172 }
138173
139- const countyFormatName = county && state ? `${ county } ${ state } ` . toUpperCase ( ) : '' ;
140- const rangerDistrictFormatName = rangerDistrict ? getMapboxRDNameFormat ( rangerDistrict ) ?. toUpperCase ( ) : '' ;
174+ const countyFormatName = itemCounty && itemState ? `${ itemCounty } ${ itemState } ` . toUpperCase ( ) : '' ;
175+ const rangerDistrictFormatName = itemRangerDistrict ? getMapboxRDNameFormat ( itemRangerDistrict ) ?. toUpperCase ( ) : '' ;
141176
142177 const localityDescription = dataMode === DATA_MODES . COUNTY ? countyFormatName : rangerDistrictFormatName ;
143178
@@ -178,14 +213,20 @@ const HistoricalMap = (props) => {
178213
179214 addDefaultExpressions ( fillExpression , strokeExpression ) ;
180215
181- addMapLayer ( map , fillExpression , strokeExpression , getSourceLayer ( dataMode ) ) ;
182- } ;
216+ addMapLayer ( map , fillExpression , strokeExpression , getSourceLayer ( dataMode ) , dataMode ) ;
217+
218+ return true ;
219+ } , [ map , dataMode , selectedState , county , rangerDistrict , predictionYear ] ) ;
183220
184221 const mapInitializedRef = useRef ( false ) ;
185222 const lastDataModeRef = useRef ( dataMode ) ;
186223 const initTimeoutRef = useRef ( null ) ;
187224 const containerRetryCountRef = useRef ( 0 ) ;
188225
226+ useEffect ( ( ) => {
227+ mapInitializedRef . current = false ;
228+ } , [ ] ) ;
229+
189230 useEffect ( ( ) => {
190231 const shouldRegenerate = ! map || lastDataModeRef . current !== dataMode ;
191232
@@ -203,7 +244,13 @@ const HistoricalMap = (props) => {
203244 const currentMap = map ;
204245
205246 initTimeoutRef . current = setTimeout ( ( ) => {
247+ initTimeoutRef . current = null ;
248+
249+ if ( ! isMountedRef . current ) return ;
250+
206251 const checkContainer = ( ) => {
252+ if ( ! isMountedRef . current ) return ;
253+
207254 if ( containerRetryCountRef . current >= MAP_INIT_CONSTANTS . MAX_CONTAINER_CHECK_RETRIES ) {
208255 logError ( 'Map container not found after maximum retries' , null , { component : 'TrappingDataMap' } ) ;
209256 return ;
@@ -220,10 +267,14 @@ const HistoricalMap = (props) => {
220267 } ) ;
221268 mapInitializedRef . current = true ;
222269 lastDataModeRef . current = dataMode ;
223- initTimeoutRef . current = null ;
224270 } else {
225271 containerRetryCountRef . current += 1 ;
226- setTimeout ( checkContainer , MAP_INIT_CONSTANTS . CONTAINER_CHECK_INTERVAL ) ;
272+ containerCheckTimeoutRef . current = setTimeout ( ( ) => {
273+ containerCheckTimeoutRef . current = null ;
274+ if ( isMountedRef . current ) {
275+ checkContainer ( ) ;
276+ }
277+ } , MAP_INIT_CONSTANTS . CONTAINER_CHECK_INTERVAL ) ;
227278 }
228279 } ;
229280 checkContainer ( ) ;
@@ -235,6 +286,10 @@ const HistoricalMap = (props) => {
235286 clearTimeout ( initTimeoutRef . current ) ;
236287 initTimeoutRef . current = null ;
237288 }
289+ if ( containerCheckTimeoutRef . current ) {
290+ clearTimeout ( containerCheckTimeoutRef . current ) ;
291+ containerCheckTimeoutRef . current = null ;
292+ }
238293 if ( map && typeof map . remove === 'function' && map . getContainer && ! checkMapRemoved ( map ) ) {
239294 try {
240295 const container = map . getContainer ( ) ;
@@ -251,23 +306,36 @@ const HistoricalMap = (props) => {
251306 }
252307 mapInitializedRef . current = false ;
253308 } ;
309+ // eslint-disable-next-line react-hooks/exhaustive-deps
254310 } , [ dataMode ] ) ;
255311
256312 useEffect ( ( ) => {
257- if ( ! map ) return ;
313+ if ( ! map || rawData . length === 0 || predictionYear . toString ( ) . length !== 4 ) {
314+ return undefined ;
315+ }
258316
259- if ( predictionYear . toString ( ) . length === 4 ) colorFill ( rawData ) ;
317+ const attemptColoring = ( ) => {
318+ if ( map . isStyleLoaded && map . isStyleLoaded ( ) ) {
319+ const didColor = colorFill ( rawData ) ;
320+ if ( didColor ) {
321+ zoomToSelectedState ( selectedState , map ) ;
322+ }
323+ } else {
324+ map . once ( 'styledata' , ( ) => {
325+ const didColor = colorFill ( rawData ) ;
326+ if ( didColor ) {
327+ zoomToSelectedState ( selectedState , map ) ;
328+ }
329+ } ) ;
330+ }
331+ } ;
260332
261- zoomToSelectedState ( selectedState , map ) ;
333+ const timer = setTimeout ( attemptColoring , 50 ) ;
334+ return ( ) => {
335+ clearTimeout ( timer ) ;
336+ } ;
262337 // eslint-disable-next-line react-hooks/exhaustive-deps
263- } , [ rawData , selectedState , map , predictionYear ] ) ;
264-
265- useEffect ( ( ) => {
266- if ( ! initialFill && map && rawData . length > 0 ) {
267- colorFill ( rawData ) ;
268- setInitialFill ( true ) ;
269- }
270- } , [ initialFill , map , rawData , setInitialFill ] ) ;
338+ } , [ rawData , selectedState , map , predictionYear , county , rangerDistrict ] ) ;
271339
272340 const hoverCallback = useMemo ( ( ) => {
273341 if ( ! map || ! rawData ) return null ;
@@ -321,27 +389,6 @@ const HistoricalMap = (props) => {
321389 }
322390 } , [ rawData , map ] ) ;
323391
324- useEffect ( ( ) => {
325- const handleDownloadClick = ( event ) => {
326- if ( ! event . target . matches ( '.download-button' ) && ! event . target . matches ( '.download-button p' ) ) return ;
327- downloadMap (
328- map ,
329- predictionYear ,
330- isDownloadingMap ,
331- setIsDownloadingMap ,
332- selectedState ,
333- MAP_TITLES . HISTORICAL ,
334- { titleDetails : { selectedState, period : predictionYear } , thresholds, colors }
335- ) ;
336- } ;
337-
338- document . addEventListener ( 'click' , handleDownloadClick , false ) ;
339-
340- return ( ) => {
341- document . removeEventListener ( 'click' , handleDownloadClick , false ) ;
342- } ;
343- } , [ map , predictionYear , isDownloadingMap , setIsDownloadingMap , selectedState ] ) ;
344-
345392 const getRiskLevel = ( index ) => {
346393 const riskLevels = [ 'No Data' , '0-9' , '10-19' , '20-49' , '50-99' , '100-249' , '250+' ] ;
347394 return riskLevels [ index ] || 'Unknown' ;
@@ -361,16 +408,16 @@ const HistoricalMap = (props) => {
361408 availableStates = { availableStates }
362409 availableYears = { [ ] }
363410 availableSublocations = { availableSublocations }
364- county = { props . county }
411+ county = { county }
365412 dataMode = { dataMode }
366413 predictionYear = { predictionYear }
367- rangerDistrict = { props . rangerDistrict }
414+ rangerDistrict = { rangerDistrict }
368415 selectedState = { selectedState }
369- setCounty = { setCounty }
416+ setCounty = { setCountyFilter }
370417 setPredictionYear = { ( ) => { } }
371- setRangerDistrict = { setRangerDistrict }
372- setState = { setState }
373- clearAllSelections = { props . clearAllSelections }
418+ setRangerDistrict = { setRangerDistrictFilter }
419+ setState = { setStateFilter }
420+ clearAllSelections = { clearAllSelections }
374421 legendItems = { legendItems }
375422 legendTitle = "Total Number of Spots"
376423 downloadCallback = { ( ) => downloadMap (
0 commit comments