From dca9023e8d94abb5b89cad2b571dc21ea3820ec3 Mon Sep 17 00:00:00 2001 From: d041705 Date: Wed, 7 Oct 2026 13:47:46 +0200 Subject: [PATCH] Synchronize directional overlays during map rotation --- .../gwt/ui/client/shared/racemap/RaceMap.java | 55 +++++++++++++++---- .../WindStreamletsRaceboardOverlay.java | 14 +++++ 2 files changed, 59 insertions(+), 10 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMap.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMap.java index ac4b71308a1..27a04783c23 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMap.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMap.java @@ -231,6 +231,7 @@ public class RaceMap extends AbstractCompositeComponent impleme * rotated and translated versions of the map, implementing the "wind-up" view. */ private DelegateCoordinateSystem coordinateSystem; + private Double synchronizedMapHeading; /** * Tells whether the {@link RenderingType#VECTOR} is supported on the current platform / browser. @@ -1013,6 +1014,7 @@ public class RaceMap extends AbstractCompositeComponent impleme map.addBoundsChangeHandler(new BoundsChangeMapHandler() { @Override public void onEvent(BoundsChangeMapEvent event) { + synchronizeCoordinateSystemWithMapHeadingDuringCameraMove(); double newZoomLevel = map.getZoom(); if (!isAutoZoomInProgress() && (newZoomLevel != currentZoomLevel)) { removeTransitions(); @@ -3900,20 +3902,53 @@ public class RaceMap extends AbstractCompositeComponent impleme return currentMapBounds.getLowerLeft().getDistance(currentMapBounds.getUpperRight()).scale(2); } + private boolean installActualMapHeading() { + final boolean changed; + if (vectorRenderingTypeSupported && map != null) { + final double mapHeading = map.getHeading(); + changed = synchronizedMapHeading == null || + Math.abs(synchronizedMapHeading - mapHeading) > 0.000001; + if (changed) { + coordinateSystem.setCoordinateSystem(new RotatedCoordinateSystem( + new DegreeBearingImpl(mapHeading).add(new DegreeBearingImpl(90)))); + synchronizedMapHeading = mapHeading; + } + } else { + changed = false; + } + return changed; + } + + private void redrawMapHeadingIndicators() { + combinedWindPanel.redraw(); + final boolean rotated = coordinateSystem.mapDegreeBearing(0) != 0; + trueNorthIndicatorPanel.setVisible(rotated); + trueNorthIndicatorButtonButtonGroup.getElement().getStyle().setProperty( + "transform", "rotate(" + coordinateSystem.mapDegreeBearing(0) + "deg)"); + if (rotated) { + trueNorthIndicatorPanel.redraw(); + } + } + + private void synchronizeCoordinateSystemWithMapHeadingDuringCameraMove() { + final double previousMapHeading = synchronizedMapHeading == null ? map.getHeading() : synchronizedMapHeading; + if (installActualMapHeading()) { + if (streamletOverlay != null + && settings.isShowWindStreamletOverlay() + && paywallResolver.hasPermission(SecuredDomainType.TrackedRaceActions.VIEWSTREAMLETS, + raceMapLifecycle.getRaceDTO())) { + streamletOverlay.onMapHeadingChanged(previousMapHeading, map.getHeading()); + } + redrawMapHeadingIndicators(); + } + } + private void synchronizeCoordinateSystemWithMapHeading() { if (vectorRenderingTypeSupported && map != null) { - coordinateSystem.setCoordinateSystem(new RotatedCoordinateSystem( - new DegreeBearingImpl(map.getHeading()).add(new DegreeBearingImpl(90)))); + installActualMapHeading(); windSensorOverlays.values().forEach(WindSensorOverlay::draw); courseMarkOverlays.values().forEach(CourseMarkOverlay::draw); - combinedWindPanel.redraw(); - final boolean rotated = coordinateSystem.mapDegreeBearing(0) != 0; - trueNorthIndicatorPanel.setVisible(rotated); - trueNorthIndicatorButtonButtonGroup.getElement().getStyle().setProperty( - "transform", "rotate(" + coordinateSystem.mapDegreeBearing(0) + "deg)"); - if (rotated) { - trueNorthIndicatorPanel.redraw(); - } + redrawMapHeadingIndicators(); } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/WindStreamletsRaceboardOverlay.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/WindStreamletsRaceboardOverlay.java index 6687172adb9..7e91452330d 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/WindStreamletsRaceboardOverlay.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/racemap/WindStreamletsRaceboardOverlay.java @@ -73,6 +73,7 @@ public class WindStreamletsRaceboardOverlay extends MovingCanvasOverlay implemen private final NumberFormat numberFormatOneDecimal = NumberFormatterFactory.getDecimalFormat(1); private ElementStyleMutationObserver observer; private boolean dragging = false; + private Double mapHeadingAtOrientationStart; private boolean isAttached = false, startObserverWhenAttached = false; private boolean timeChangedSinceLastUpdate = true; @@ -375,8 +376,21 @@ public class WindStreamletsRaceboardOverlay extends MovingCanvasOverlay implemen swarm.pause(500 / animationIntervalMillis); // pause animation for two seconds } + public void onMapHeadingChanged(double previousMapHeading, double mapHeading) { + if (mapHeadingAtOrientationStart == null) { + mapHeadingAtOrientationStart = previousMapHeading; + } + onDragStart(); + updateDrawingAngleAndSetCanvasRotation(mapHeadingAtOrientationStart - mapHeading); + } + public void onDragEnd() { dragging = false; + if (mapHeadingAtOrientationStart != null) { + mapHeadingAtOrientationStart = null; + updateDrawingAngleAndSetCanvasRotation(0); + swarm.onBoundsChanged(/* zoomChanged */ true, /* swarmPause */ 1); + } } public void onBoundsChanged(boolean zoomChanged) {