diff --git a/public/js/app.js b/public/js/app.js index 0791372..5bfbc99 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -777,26 +777,42 @@ return null; }; - currentLatencies.forEach((route, index) => { - const startCoords = getShiftedCoords(route.source); - const endCoords = getShiftedCoords(route.dest); + // Group latency routes by path to handle overlap visually + const routeGroups = {}; + currentLatencies.forEach(route => { + const start = getShiftedCoords(route.source); + const end = getShiftedCoords(route.dest); + if (start && end) { + // Canonical points for grouping (independent of direction) + // Sort by longitude then latitude + const pts = [start, end].slice().sort((a, b) => a[0] - b[0] || a[1] - b[1]); + const key = `${pts[0][0].toFixed(4)},${pts[0][1].toFixed(4)}_${pts[1][0].toFixed(4)},${pts[1][1].toFixed(4)}`; + if (!routeGroups[key]) routeGroups[key] = []; + routeGroups[key].push({ route, start, end }); + } + }); - if (startCoords && endCoords) { - // Calculate direction and distance - const dx = endCoords[0] - startCoords[0]; - const dy = endCoords[1] - startCoords[1]; + Object.keys(routeGroups).forEach(key => { + const routes = routeGroups[key]; + const count = routes.length; + + routes.forEach((item, i) => { + const { route, start, end } = item; - // Identify major regions - const src = (route.source || '').toLowerCase(); - const dst = (route.dest || '').toLowerCase(); + // Identify if the route is in the "canonical" direction + const pts = [start, end].slice().sort((a, b) => a[0] - b[0] || a[1] - b[1]); + const isForward = (start === pts[0]); - const isUS = (n) => n.includes('united states') || n.includes('us ') || n.includes('seattle') || n.includes('san francisco') || n.includes('los angeles') || n.includes('new york') || n.includes('chicago'); - const isJapan = (n) => n.includes('japan') || n.includes('tokyo'); - const isAsia = (n) => n.includes('china') || n.includes('hong kong') || n.includes('singapore') || n.includes('korea') || n.includes('seoul') || n.includes('japan') || n.includes('tokyo') || n.includes('shanghai') || n.includes('beijing'); - const isEurope = (n) => n.includes('germany') || n.includes('uk') || n.includes('france') || n.includes('london') || n.includes('frankfurt') || n.includes('paris') || n.includes('united kingdom'); - - // Determine base curveness - switched to straight lines (0) per user request + // Calculate curveness spread let finalCurve = 0; + if (count > 1) { + // Spread curveness between -0.3 and 0.3 + const maxSpread = 0.3; + const spread = (i - (count - 1) / 2) * (maxSpread * 2 / Math.max(1, count - 1)); + // Adjust sign based on direction so same "slot" arches same way in absolute terms + // A->B with curve C and B->A with curve -C arch to the same side of the AB chord + finalCurve = isForward ? spread : -spread; + } finalSeries.push({ type: 'lines', @@ -830,10 +846,10 @@ data: [{ fromName: route.source, toName: route.dest, - coords: [startCoords, endCoords] + coords: [start, end] }] }); - } + }); }); }