@@ -13,7 +13,8 @@ import {
1313} from '../utils/mapStyles'
1414
1515export const useMapLayers = (
16- map : React . MutableRefObject < mapboxgl . Map | null >
16+ map : React . MutableRefObject < mapboxgl . Map | null > ,
17+ onTripClick ?: ( trip : Trip ) => void
1718) => {
1819 const stopMarkers = useRef < mapboxgl . Marker [ ] > ( [ ] )
1920 const vehicleMarkers = useRef < mapboxgl . Marker [ ] > ( [ ] )
@@ -124,33 +125,7 @@ export const useMapLayers = (
124125 ( trips : Trip [ ] , showTrips : boolean ) => {
125126 if ( ! map . current ) return
126127
127- // Check if we already have the right number of trip sources
128- const expectedSources = trips . filter (
129- ( trip ) => trip . trip_stops && trip . trip_stops . length >= 2
130- ) . length
131-
132- if ( tripSources . current . length === expectedSources ) {
133- // Just toggle visibility if sources already exist
134- tripSources . current . forEach ( ( sourceId ) => {
135- const layerId = `${ sourceId } -layer`
136- if ( map . current ?. getLayer ( layerId ) ) {
137- map . current . setLayoutProperty (
138- layerId ,
139- 'visibility' ,
140- showTrips ? 'visible' : 'none'
141- )
142- }
143- } )
144-
145- // Toggle arrow markers visibility
146- const arrowElements = document . querySelectorAll ( '.trip-arrow' )
147- arrowElements . forEach ( ( element ) => {
148- ; ( element as HTMLElement ) . style . opacity = showTrips ? '0.8' : '0'
149- } )
150- return
151- }
152-
153- // Clear existing trip sources if count doesn't match
128+ // Always clear existing trip sources to ensure fresh data
154129 tripSources . current . forEach ( ( sourceId ) => {
155130 if ( map . current ?. getSource ( sourceId ) ) {
156131 if ( map . current ?. getLayer ( `${ sourceId } -layer` ) ) {
@@ -204,7 +179,11 @@ export const useMapLayers = (
204179 } )
205180
206181 const statusColor = getStatusColor ( trip . status )
207- const patternId = 'trip-chevron'
182+ // Use selected pattern if this trip is currently selected
183+ const patternId =
184+ selectedTripId . current === trip . id
185+ ? 'trip-chevron-selected'
186+ : 'trip-chevron'
208187
209188 // Load chevron pattern images if they don't exist
210189 if ( ! map . current ! . hasImage ( 'trip-chevron' ) ) {
@@ -240,6 +219,7 @@ export const useMapLayers = (
240219 layout : {
241220 'line-join' : 'none' ,
242221 'line-cap' : 'round' ,
222+ visibility : showTrips ? 'visible' : 'none' ,
243223 } ,
244224 paint : {
245225 'line-color' : statusColor ,
@@ -251,53 +231,71 @@ export const useMapLayers = (
251231
252232 // Add click handler for trip lines
253233 map . current ! . on ( 'click' , `${ sourceId } -layer` , ( e ) => {
254- const coordinates = e . lngLat
255-
256- // Create popup content using the same styling as stops
257- const popupContent = createTripPopupContent ( trip , validStops )
258-
259- const popup = new mapboxgl . Popup ( {
260- offset : 25 ,
261- closeButton : true ,
262- closeOnClick : false ,
263- className : 'custom-popup' ,
264- } ) . setHTML ( popupContent )
265-
266- // Close all other popups when this one opens
267- closeAllPopups ( )
268- activePopups . current . push ( popup )
269-
270- // Update selected trip pattern
271- selectedTripId . current = trip . id
272- const layerId = `${ sourceId } -layer`
273- if ( map . current ?. getLayer ( layerId ) ) {
274- map . current . setPaintProperty (
275- layerId ,
276- 'line-pattern' ,
277- 'trip-chevron-selected'
278- )
279- }
234+ if ( onTripClick ) {
235+ // Close all popups and update selected trip pattern
236+ closeAllPopups ( )
237+ selectedTripId . current = trip . id
238+ const layerId = `${ sourceId } -layer`
239+ if ( map . current ?. getLayer ( layerId ) ) {
240+ map . current . setPaintProperty (
241+ layerId ,
242+ 'line-pattern' ,
243+ 'trip-chevron-selected'
244+ )
245+ }
280246
281- // Remove from active popups when closed and reset pattern
282- popup . on ( 'close' , ( ) => {
283- activePopups . current = activePopups . current . filter (
284- ( p ) => p !== popup
285- )
247+ // Call the trip click callback (for drawer)
248+ onTripClick ( trip )
249+ } else {
250+ // Fallback to popup behavior
251+ const coordinates = e . lngLat
252+
253+ // Create popup content using the same styling as stops
254+ const popupContent = createTripPopupContent ( trip , validStops )
255+
256+ const popup = new mapboxgl . Popup ( {
257+ offset : 25 ,
258+ closeButton : true ,
259+ closeOnClick : false ,
260+ className : 'custom-popup' ,
261+ } ) . setHTML ( popupContent )
262+
263+ // Close all other popups when this one opens
264+ closeAllPopups ( )
265+ activePopups . current . push ( popup )
266+
267+ // Update selected trip pattern
268+ selectedTripId . current = trip . id
269+ const layerId = `${ sourceId } -layer`
270+ if ( map . current ?. getLayer ( layerId ) ) {
271+ map . current . setPaintProperty (
272+ layerId ,
273+ 'line-pattern' ,
274+ 'trip-chevron-selected'
275+ )
276+ }
286277
287- // Reset pattern back to normal when popup closes
288- if ( selectedTripId . current === trip . id ) {
289- selectedTripId . current = null
290- if ( map . current ?. getLayer ( layerId ) ) {
291- map . current . setPaintProperty (
292- layerId ,
293- 'line-pattern' ,
294- 'trip-chevron'
295- )
278+ // Remove from active popups when closed and reset pattern
279+ popup . on ( 'close' , ( ) => {
280+ activePopups . current = activePopups . current . filter (
281+ ( p ) => p !== popup
282+ )
283+
284+ // Reset pattern back to normal when popup closes
285+ if ( selectedTripId . current === trip . id ) {
286+ selectedTripId . current = null
287+ if ( map . current ?. getLayer ( layerId ) ) {
288+ map . current . setPaintProperty (
289+ layerId ,
290+ 'line-pattern' ,
291+ 'trip-chevron'
292+ )
293+ }
296294 }
297- }
298- } )
295+ } )
299296
300- popup . setLngLat ( coordinates ) . addTo ( map . current ! )
297+ popup . setLngLat ( coordinates ) . addTo ( map . current ! )
298+ }
301299 } )
302300
303301 // Change cursor on hover
@@ -310,7 +308,7 @@ export const useMapLayers = (
310308 } )
311309 } )
312310 } ,
313- [ map , closeAllPopups ]
311+ [ map , closeAllPopups , onTripClick ]
314312 )
315313
316314 const toggleStopVisibility = useCallback ( ( showStops : boolean ) => {
@@ -440,6 +438,68 @@ export const useMapLayers = (
440438 [ map ]
441439 )
442440
441+ const fitMapToTrip = useCallback (
442+ ( trip : Trip , withDrawerSpace = false ) => {
443+ if ( ! map . current || ! trip . trip_stops || trip . trip_stops . length === 0 )
444+ return
445+
446+ const bounds = new mapboxgl . LngLatBounds ( )
447+
448+ // Add all trip stops to bounds
449+ trip . trip_stops . forEach ( ( tripStop ) => {
450+ if ( tripStop . stop . latitude && tripStop . stop . longitude ) {
451+ const lat = parseFloat ( tripStop . stop . latitude )
452+ const lng = parseFloat ( tripStop . stop . longitude )
453+ bounds . extend ( [ lng , lat ] )
454+ }
455+ } )
456+
457+ // Adjust padding to account for drawer space
458+ const padding = withDrawerSpace
459+ ? { top : 100 , bottom : 100 , left : 100 , right : 1000 } // Extra space on right for drawer
460+ : 50
461+
462+ map . current . fitBounds ( bounds , {
463+ padding,
464+ maxZoom : 12 ,
465+ } )
466+ } ,
467+ [ map ]
468+ )
469+
470+ const resetSelectedTrip = useCallback ( ( ) => {
471+ if ( selectedTripId . current ) {
472+ const tripId = selectedTripId . current
473+ selectedTripId . current = null
474+
475+ const layerId = `trip-${ tripId } -layer`
476+ if ( map . current ?. getLayer ( layerId ) ) {
477+ map . current . setPaintProperty ( layerId , 'line-pattern' , 'trip-chevron' )
478+ }
479+ }
480+ } , [ map ] )
481+
482+ const forceRefreshTrips = useCallback (
483+ ( trips : Trip [ ] , showTrips : boolean ) => {
484+ if ( ! map . current ) return
485+
486+ // Clear existing trip sources
487+ tripSources . current . forEach ( ( sourceId ) => {
488+ if ( map . current ?. getSource ( sourceId ) ) {
489+ if ( map . current ?. getLayer ( `${ sourceId } -layer` ) ) {
490+ map . current . removeLayer ( `${ sourceId } -layer` )
491+ }
492+ map . current . removeSource ( sourceId )
493+ }
494+ } )
495+ tripSources . current = [ ]
496+
497+ // Re-add all trips
498+ addTripsToMap ( trips , showTrips )
499+ } ,
500+ [ map , addTripsToMap ]
501+ )
502+
443503 return {
444504 addMarkersToMap,
445505 addTripsToMap,
@@ -449,5 +509,8 @@ export const useMapLayers = (
449509 toggleVehicleVisibility,
450510 setupMapClickHandler,
451511 fitMapToStops,
512+ fitMapToTrip,
513+ resetSelectedTrip,
514+ forceRefreshTrips,
452515 }
453516}
0 commit comments