Skip to content

Commit ed96499

Browse files
committed
new colors for multiple segement map, new algorithm for overlay segment click
1 parent 1eb695c commit ed96499

File tree

1 file changed

+152
-59
lines changed

1 file changed

+152
-59
lines changed

cesnet_service_path_plugin/templates/cesnet_service_path_plugin/segments_map.html

Lines changed: 152 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)