@@ -178,9 +178,10 @@ <h6 class="card-title mb-0">Selected Segment</h6>
178178
179179 // Status color mapping - using red as primary color for better visibility
180180 const statusColorsLine = {
181- "Active" : "#dc3545 " , // Red - more visible on OSM
182- "Planned" : "#ff6b35 " , // Orange-red
181+ "Active" : "#198754 " , // Dark Green
182+ "Planned" : "#3b82f6 " , // Blue
183183 "Offline" : "#dc3545" , // Red
184+ "Maintenance" : "#ff8c00" , // Dark Orange
184185 "Decommissioned" : "#6c757d" // Gray
185186 } ;
186187
@@ -231,82 +232,75 @@ <h6>${segment.name}</h6>
231232 document . getElementById ( 'segmentInfo' ) . style . display = 'none' ;
232233 }
233234
234- // Enhanced function to handle overlapping segments
235+ // Visual-based overlap detection using screen coordinates
235236 function handleSegmentClick ( e ) {
236237 e . originalEvent . preventDefault ( ) ;
237238 const clickPoint = e . latlng ;
239+ const clickScreenPoint = map . latLngToContainerPoint ( clickPoint ) ;
238240
239- // Find all segments near the click point using a simple distance check
240- const overlappingSegments = [ ] ;
241- const tolerance = 0.01 ; // Adjust this value as needed
241+ // Find all segments that are visually close to the click
242+ const visuallyOverlappingSegments = [ ] ;
243+ const screenTolerance = 10 ; // pixels
242244
243245 segmentLayers . forEach ( ( layer , segmentId ) => {
244246 const segment = segmentsData . find ( s => s . id . toString ( ) === segmentId . toString ( ) ) ;
245247 if ( ! segment ) return ;
246248
247- let isNearClick = false ;
249+ let isVisuallyNear = false ;
248250
249- // Check if click is near this layer
251+ // Check if layer is visually near the click point
250252 if ( layer instanceof L . Polyline ) {
251- const bounds = layer . getBounds ( ) ;
252- if ( bounds . contains ( clickPoint ) ) {
253- // More detailed check - see if click is near the path
254- const latlngs = layer . getLatLngs ( ) ;
255- const flatLatLngs = Array . isArray ( latlngs [ 0 ] ) ? latlngs . flat ( ) : latlngs ;
256-
257- for ( let i = 0 ; i < flatLatLngs . length - 1 ; i ++ ) {
258- if ( distanceToLineSegment ( clickPoint , flatLatLngs [ i ] , flatLatLngs [ i + 1 ] ) < tolerance ) {
259- isNearClick = true ;
260- break ;
261- }
262- }
263- }
253+ isVisuallyNear = checkPolylineVisualProximity ( layer , clickScreenPoint , screenTolerance ) ;
264254 } else if ( layer . eachLayer ) {
265255 // Handle GeoJSON layers
266256 layer . eachLayer ( function ( subLayer ) {
267- if ( subLayer instanceof L . Polyline ) {
268- const bounds = subLayer . getBounds ( ) ;
269- if ( bounds . contains ( clickPoint ) ) {
270- const latlngs = subLayer . getLatLngs ( ) ;
271- const flatLatLngs = Array . isArray ( latlngs [ 0 ] ) ? latlngs . flat ( ) : latlngs ;
272-
273- for ( let i = 0 ; i < flatLatLngs . length - 1 ; i ++ ) {
274- if ( distanceToLineSegment ( clickPoint , flatLatLngs [ i ] , flatLatLngs [ i + 1 ] ) < tolerance ) {
275- isNearClick = true ;
276- return ;
277- }
278- }
279- }
257+ if ( subLayer instanceof L . Polyline && ! isVisuallyNear ) {
258+ isVisuallyNear = checkPolylineVisualProximity ( subLayer , clickScreenPoint , screenTolerance ) ;
280259 }
281260 } ) ;
282261 }
283262
284- if ( isNearClick ) {
285- overlappingSegments . push ( {
263+ if ( isVisuallyNear ) {
264+ visuallyOverlappingSegments . push ( {
286265 layer : layer ,
287266 segment : segment
288267 } ) ;
289268 }
290269 } ) ;
291270
292- if ( overlappingSegments . length === 1 ) {
293- // Single segment - show popup and detailed info
294- const segment = overlappingSegments [ 0 ] . segment ;
295- showSingleSegmentPopup ( segment , clickPoint ) ;
296- showSegmentInfo ( segment ) ;
297- } else if ( overlappingSegments . length > 1 ) {
298- // Multiple segments - show selection popup
299- showOverlappingSegmentsPopup ( overlappingSegments , clickPoint ) ;
300- showSegmentInfo ( overlappingSegments [ 0 ] . segment ) ;
271+ // Now find which segments are truly overlapping (sharing visual space)
272+ const trueOverlaps = findVisualOverlaps ( visuallyOverlappingSegments , clickScreenPoint , screenTolerance ) ;
273+
274+ if ( trueOverlaps . length === 1 ) {
275+ showSingleSegmentPopup ( trueOverlaps [ 0 ] . segment , clickPoint ) ;
276+ showSegmentInfo ( trueOverlaps [ 0 ] . segment ) ;
277+ } else if ( trueOverlaps . length > 1 ) {
278+ showOverlappingSegmentsPopup ( trueOverlaps , clickPoint ) ;
279+ showSegmentInfo ( trueOverlaps [ 0 ] . segment ) ;
301280 }
302281 }
303282
304- // Helper function to calculate distance from point to line segment
305- function distanceToLineSegment ( point , lineStart , lineEnd ) {
306- const A = point . lat - lineStart . lat ;
307- const B = point . lng - lineStart . lng ;
308- const C = lineEnd . lat - lineStart . lat ;
309- const D = lineEnd . lng - lineStart . lng ;
283+ function checkPolylineVisualProximity ( polyline , clickScreenPoint , tolerance ) {
284+ const latlngs = polyline . getLatLngs ( ) ;
285+ const flatLatLngs = Array . isArray ( latlngs [ 0 ] ) ? latlngs . flat ( ) : latlngs ;
286+
287+ for ( let i = 0 ; i < flatLatLngs . length - 1 ; i ++ ) {
288+ const point1 = map . latLngToContainerPoint ( flatLatLngs [ i ] ) ;
289+ const point2 = map . latLngToContainerPoint ( flatLatLngs [ i + 1 ] ) ;
290+
291+ const distance = distanceToLineSegmentScreen ( clickScreenPoint , point1 , point2 ) ;
292+ if ( distance <= tolerance ) {
293+ return true ;
294+ }
295+ }
296+ return false ;
297+ }
298+
299+ function distanceToLineSegmentScreen ( point , lineStart , lineEnd ) {
300+ const A = point . x - lineStart . x ;
301+ const B = point . y - lineStart . y ;
302+ const C = lineEnd . x - lineStart . x ;
303+ const D = lineEnd . y - lineStart . y ;
310304
311305 const dot = A * C + B * D ;
312306 const lenSq = C * C + D * D ;
@@ -315,21 +309,119 @@ <h6>${segment.name}</h6>
315309
316310 let xx , yy ;
317311 if ( param < 0 ) {
318- xx = lineStart . lat ;
319- yy = lineStart . lng ;
312+ xx = lineStart . x ;
313+ yy = lineStart . y ;
320314 } else if ( param > 1 ) {
321- xx = lineEnd . lat ;
322- yy = lineEnd . lng ;
315+ xx = lineEnd . x ;
316+ yy = lineEnd . y ;
323317 } else {
324- xx = lineStart . lat + param * C ;
325- yy = lineStart . lng + param * D ;
318+ xx = lineStart . x + param * C ;
319+ yy = lineStart . y + param * D ;
326320 }
327321
328- const dx = point . lat - xx ;
329- const dy = point . lng - yy ;
322+ const dx = point . x - xx ;
323+ const dy = point . y - yy ;
330324 return Math . sqrt ( dx * dx + dy * dy ) ;
331325 }
332326
327+ function findVisualOverlaps ( segments , clickScreenPoint , tolerance ) {
328+ if ( segments . length <= 1 ) return segments ;
329+
330+ // Group segments that share similar screen coordinates
331+ const groups = [ ] ;
332+
333+ for ( const segmentInfo of segments ) {
334+ let addedToGroup = false ;
335+
336+ for ( const group of groups ) {
337+ // Check if this segment visually overlaps with segments in this group
338+ if ( checkSegmentGroupOverlap ( segmentInfo , group , tolerance ) ) {
339+ group . push ( segmentInfo ) ;
340+ addedToGroup = true ;
341+ break ;
342+ }
343+ }
344+
345+ if ( ! addedToGroup ) {
346+ groups . push ( [ segmentInfo ] ) ;
347+ }
348+ }
349+
350+ // Return the group that contains the most segments near the click point
351+ let bestGroup = groups [ 0 ] ;
352+ let bestScore = 0 ;
353+
354+ for ( const group of groups ) {
355+ let score = 0 ;
356+ for ( const segmentInfo of group ) {
357+ // Check how close this segment is to the click point
358+ const layer = segmentInfo . layer ;
359+ if ( layer instanceof L . Polyline ) {
360+ if ( checkPolylineVisualProximity ( layer , clickScreenPoint , tolerance ) ) {
361+ score += 1 ;
362+ }
363+ } else if ( layer . eachLayer ) {
364+ layer . eachLayer ( function ( subLayer ) {
365+ if ( subLayer instanceof L . Polyline ) {
366+ if ( checkPolylineVisualProximity ( subLayer , clickScreenPoint , tolerance ) ) {
367+ score += 1 ;
368+ }
369+ }
370+ } ) ;
371+ }
372+ }
373+
374+ if ( score > bestScore ) {
375+ bestScore = score ;
376+ bestGroup = group ;
377+ }
378+ }
379+
380+ return bestGroup ;
381+ }
382+
383+ function checkSegmentGroupOverlap ( segmentInfo , group , tolerance ) {
384+ // Simplified check - compare with first segment in group
385+ if ( group . length === 0 ) return false ;
386+
387+ const firstSegment = group [ 0 ] ;
388+
389+ // For a more sophisticated approach, you could compare actual line coordinates
390+ // For now, we'll use a simple heuristic
391+
392+ const segment1 = segmentInfo . segment ;
393+ const segment2 = firstSegment . segment ;
394+
395+ // If both segments don't have path data, check if they share endpoints
396+ if ( ! segment1 . has_path_data && ! segment2 . has_path_data ) {
397+ if ( segment1 . site_a && segment1 . site_b && segment2 . site_a && segment2 . site_b ) {
398+ const tolerance_deg = 0.001 ;
399+ const sameEndpoints = (
400+ Math . abs ( segment1 . site_a . lat - segment2 . site_a . lat ) < tolerance_deg &&
401+ Math . abs ( segment1 . site_a . lng - segment2 . site_a . lng ) < tolerance_deg &&
402+ Math . abs ( segment1 . site_b . lat - segment2 . site_b . lat ) < tolerance_deg &&
403+ Math . abs ( segment1 . site_b . lng - segment2 . site_b . lng ) < tolerance_deg
404+ ) || (
405+ Math . abs ( segment1 . site_a . lat - segment2 . site_b . lat ) < tolerance_deg &&
406+ Math . abs ( segment1 . site_a . lng - segment2 . site_b . lng ) < tolerance_deg &&
407+ Math . abs ( segment1 . site_b . lat - segment2 . site_a . lat ) < tolerance_deg &&
408+ Math . abs ( segment1 . site_b . lng - segment2 . site_a . lng ) < tolerance_deg
409+ ) ;
410+ return sameEndpoints ;
411+ }
412+ return false ;
413+ }
414+
415+ // If both have path data, they could be truly overlapping routes
416+ if ( segment1 . has_path_data && segment2 . has_path_data ) {
417+ return true ; // Let visual proximity determine this
418+ }
419+
420+ // Mixed case - probably not overlapping
421+ return false ;
422+ }
423+
424+
333425 // Show popup for single segment
334426 function showSingleSegmentPopup ( segment , clickPoint ) {
335427 const color = statusBadge [ segment . status ] || '#6c757d' ;
@@ -393,6 +485,7 @@ <h4><i class="mdi mdi-layers"></i> Multiple Segments (${overlappingLayers.length
393485 <ul class="list-unstyled mb-0">
394486 <li><strong>Sites:</strong> ${ segment . site_a ? segment . site_a . name : 'N/A' } ↔ ${ segment . site_b ? segment . site_b . name : 'N/A' } </li>
395487 <li><strong>Status:</strong> <span class="badge text-bg-${ color } ">${ segment . status } </span></li>
488+ <li><strong>Path Data:</strong> ${ segment . has_path_data ? '<span class="badge text-bg-green">Has Path Data</span>' : '<span class="badge text-bg-orange">No Path Data</span>' } </li>
396489 <li><strong>Length:</strong> ${ segment . path_length_km ? segment . path_length_km + ' km' : 'Unknown' } </li>
397490 </ul>
398491
0 commit comments