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; +}