diff --git a/templates/index.html b/templates/index.html index 9c84359..8134d46 100644 --- a/templates/index.html +++ b/templates/index.html @@ -8200,8 +8200,11 @@ ctx.beginPath(); pass.trajectory.forEach((point, i) => { - const r = radius * (90 - point.elevation) / 90; - const rad = point.azimuth * Math.PI / 180; + // Backend returns 'el' and 'az' properties + const el = point.el !== undefined ? point.el : point.elevation; + const az = point.az !== undefined ? point.az : point.azimuth; + const r = radius * (90 - el) / 90; + const rad = az * Math.PI / 180; const x = cx + Math.sin(rad) * r; const y = cy - Math.cos(rad) * r; @@ -8212,9 +8215,15 @@ ctx.setLineDash([]); // Draw max elevation point - const maxPoint = pass.trajectory.reduce((max, p) => p.elevation > max.elevation ? p : max, { elevation: 0 }); - const maxR = radius * (90 - maxPoint.elevation) / 90; - const maxRad = maxPoint.azimuth * Math.PI / 180; + const maxPoint = pass.trajectory.reduce((max, p) => { + const pEl = p.el !== undefined ? p.el : p.elevation; + const maxEl = max.el !== undefined ? max.el : max.elevation; + return pEl > maxEl ? p : max; + }, { el: 0, elevation: 0 }); + const maxEl = maxPoint.el !== undefined ? maxPoint.el : maxPoint.elevation; + const maxAz = maxPoint.az !== undefined ? maxPoint.az : maxPoint.azimuth; + const maxR = radius * (90 - maxEl) / 90; + const maxRad = maxAz * Math.PI / 180; const maxX = cx + Math.sin(maxRad) * maxR; const maxY = cy - Math.cos(maxRad) * maxR; @@ -8353,14 +8362,33 @@ if (groundTrackLine) groundTrackMap.removeLayer(groundTrackLine); if (satMarker) groundTrackMap.removeLayer(satMarker); - // Draw ground track - const coords = pass.groundTrack.map(p => [p.lat, p.lon]); - groundTrackLine = L.polyline(coords, { - color: pass.color || '#00ff00', - weight: 2, - opacity: 0.8, - dashArray: '5, 5' - }).addTo(groundTrackMap); + // Split ground track at antimeridian crossings + const segments = []; + let currentSegment = []; + for (let i = 0; i < pass.groundTrack.length; i++) { + const p = pass.groundTrack[i]; + if (currentSegment.length > 0) { + const prevLon = currentSegment[currentSegment.length - 1][1]; + if (Math.abs(p.lon - prevLon) > 180) { + if (currentSegment.length > 1) segments.push(currentSegment); + currentSegment = []; + } + } + currentSegment.push([p.lat, p.lon]); + } + if (currentSegment.length > 1) segments.push(currentSegment); + + // Draw ground track segments + groundTrackLine = L.layerGroup(); + segments.forEach(seg => { + L.polyline(seg, { + color: pass.color || '#00ff00', + weight: 2, + opacity: 0.8, + dashArray: '5, 5' + }).addTo(groundTrackLine); + }); + groundTrackLine.addTo(groundTrackMap); // Add current position marker if (pass.currentPosition) { @@ -8382,7 +8410,7 @@ } // Fit bounds to show track - if (coords.length > 0) { + if (segments.length > 0) { groundTrackMap.fitBounds(groundTrackLine.getBounds(), { padding: [20, 20] }); } } @@ -8448,31 +8476,61 @@ // Draw full orbit track from position endpoint if (pos.orbitTrack && pos.orbitTrack.length > 0 && groundTrackMap) { - // Split into past and future segments - const pastCoords = pos.orbitTrack.filter(p => p.past).map(p => [p.lat, p.lon]); - const futureCoords = pos.orbitTrack.filter(p => !p.past).map(p => [p.lat, p.lon]); + // Split into past and future, handling antimeridian crossings + const pastPoints = pos.orbitTrack.filter(p => p.past); + const futurePoints = pos.orbitTrack.filter(p => !p.past); + + // Helper to split coords at antimeridian crossings + function splitAtAntimeridian(points) { + const segments = []; + let currentSegment = []; + for (let i = 0; i < points.length; i++) { + const p = points[i]; + if (currentSegment.length > 0) { + const prevLon = currentSegment[currentSegment.length - 1][1]; + // If longitude jumps more than 180°, start new segment + if (Math.abs(p.lon - prevLon) > 180) { + if (currentSegment.length > 1) segments.push(currentSegment); + currentSegment = []; + } + } + currentSegment.push([p.lat, p.lon]); + } + if (currentSegment.length > 1) segments.push(currentSegment); + return segments; + } // Remove old lines if (orbitTrackLine) groundTrackMap.removeLayer(orbitTrackLine); if (pastOrbitLine) groundTrackMap.removeLayer(pastOrbitLine); - // Draw past track (dimmer) - if (pastCoords.length > 1) { - pastOrbitLine = L.polyline(pastCoords, { - color: '#666666', - weight: 2, - opacity: 0.5, - dashArray: '3, 6' - }).addTo(groundTrackMap); + // Draw past track segments (dimmer) + const pastSegments = splitAtAntimeridian(pastPoints); + if (pastSegments.length > 0) { + pastOrbitLine = L.layerGroup(); + pastSegments.forEach(seg => { + L.polyline(seg, { + color: '#666666', + weight: 2, + opacity: 0.5, + dashArray: '3, 6' + }).addTo(pastOrbitLine); + }); + pastOrbitLine.addTo(groundTrackMap); } - // Draw future track (brighter) - if (futureCoords.length > 1) { - orbitTrackLine = L.polyline(futureCoords, { - color: selectedPass.color || '#00ff00', - weight: 3, - opacity: 0.8 - }).addTo(groundTrackMap); + // Draw future track segments (brighter) + const futureSegments = splitAtAntimeridian(futurePoints); + if (futureSegments.length > 0) { + orbitTrackLine = L.layerGroup(); + futureSegments.forEach(seg => { + L.polyline(seg, { + color: selectedPass.color || '#00ff00', + weight: 3, + opacity: 0.8 + }).addTo(orbitTrackLine); + }); + orbitTrackLine.addTo(groundTrackMap); } } @@ -8813,8 +8871,11 @@ ctx.setLineDash([8, 4]); ctx.beginPath(); pass.trajectory.forEach((point, i) => { - const r = radius * (90 - point.elevation) / 90; - const rad = point.azimuth * Math.PI / 180; + // Backend returns 'el' and 'az' properties + const el = point.el !== undefined ? point.el : point.elevation; + const az = point.az !== undefined ? point.az : point.azimuth; + const r = radius * (90 - el) / 90; + const rad = az * Math.PI / 180; const x = cx + Math.sin(rad) * r; const y = cy - Math.cos(rad) * r; if (i === 0) ctx.moveTo(x, y); @@ -8823,9 +8884,15 @@ ctx.stroke(); ctx.setLineDash([]); - const maxPoint = pass.trajectory.reduce((max, p) => p.elevation > max.elevation ? p : max, { elevation: 0 }); - const maxR = radius * (90 - maxPoint.elevation) / 90; - const maxRad = maxPoint.azimuth * Math.PI / 180; + const maxPoint = pass.trajectory.reduce((max, p) => { + const pEl = p.el !== undefined ? p.el : p.elevation; + const maxEl = max.el !== undefined ? max.el : max.elevation; + return pEl > maxEl ? p : max; + }, { el: 0, elevation: 0 }); + const maxEl = maxPoint.el !== undefined ? maxPoint.el : maxPoint.elevation; + const maxAz = maxPoint.az !== undefined ? maxPoint.az : maxPoint.azimuth; + const maxR = radius * (90 - maxEl) / 90; + const maxRad = maxAz * Math.PI / 180; ctx.fillStyle = pass.color || '#00ff00'; ctx.beginPath(); ctx.arc(cx + Math.sin(maxRad) * maxR, cy - Math.cos(maxRad) * maxR, 8, 0, Math.PI * 2);