diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx
index 79eae89..e9755c0 100644
--- a/frontend/src/App.jsx
+++ b/frontend/src/App.jsx
@@ -372,6 +372,9 @@ const APP = () => {
setIsPlaying(false);
setFlightSpeed(1.0);
}
+ flightProgressRef.current = 0;
+ setCurrentCityIndex(-1);
+ currentCityIndexRef.current = -1;
if (popupRef.current) {
popupRef.current.remove();
popupRef.current = null;
@@ -458,14 +461,11 @@ const APP = () => {
if (animationRef.current) cancelAnimationFrame(animationRef.current);
setIsPlaying(false);
setFlightSpeed(1.0);
- setCurrentCityIndex(-1);
- currentCityIndexRef.current = -1;
return;
}
setIsPlaying(true);
- setCurrentCityIndex(-1);
- currentCityIndexRef.current = -1;
+ // Don't reset currentCityIndex here, so it resumes correctly
if (popupRef.current) popupRef.current.remove();
const coordinates = lineOfSightData.line_coordinates.map(c => [c.lon, c.lat]);
@@ -474,7 +474,7 @@ const APP = () => {
let lastFetchedDist = flightProgressRef.current;
let currentProgress = flightProgressRef.current;
- flightProgressRef.current = 0;
+ // Removed: flightProgressRef.current = 0; - We keep the ref to resume.
let lastTimestamp = performance.now();
let currentSpeedMultiplier = 1.0;
let frameCount = 0;
@@ -583,6 +583,7 @@ const APP = () => {
}
}
+ flightProgressRef.current = currentProgress;
animationRef.current = requestAnimationFrame(animate);
}
@@ -749,6 +750,10 @@ const APP = () => {
console.error('Error fetching line of sight:', error);
} finally {
setLoading(false);
+ // Reset flight progress for a new line calculation
+ flightProgressRef.current = 0;
+ setCurrentCityIndex(-1);
+ currentCityIndexRef.current = -1;
}
};
@@ -841,13 +846,39 @@ const APP = () => {
) : (
<>
-
+
+
+
+
diff --git a/frontend/src/styles/App.css b/frontend/src/styles/App.css
index 0f7ceeb..ad471bb 100644
--- a/frontend/src/styles/App.css
+++ b/frontend/src/styles/App.css
@@ -463,3 +463,62 @@
font-size: 13px;
margin-bottom: 8px;
}
+
+.fly-controls {
+ display: flex;
+ gap: 8px;
+ margin-top: 10px;
+}
+
+.fly-button {
+ flex: 3;
+ padding: 12px;
+ border: none;
+ border-radius: 6px;
+ color: white;
+ font-weight: 600;
+ cursor: pointer;
+ transition: all 0.2s;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 8px;
+}
+
+.fly-button.play {
+ background: #3498db;
+}
+
+.fly-button.play:hover {
+ background: #2980b9;
+}
+
+.fly-button.pause {
+ background: #e74c3c;
+}
+
+.fly-button.pause:hover {
+ background: #c0392b;
+}
+
+.reset-flight-btn {
+ flex: 1;
+ padding: 12px;
+ background: #95a5a6;
+ color: white;
+ border: none;
+ border-radius: 6px;
+ font-weight: 600;
+ cursor: pointer;
+ transition: all 0.2s;
+}
+
+.reset-flight-btn:hover:not(:disabled) {
+ background: #7f8c8d;
+}
+
+.reset-flight-btn:disabled {
+ background: #ecf0f1;
+ color: #bdc3c7;
+ cursor: not-allowed;
+}