add moving variant of full-canvas, to support auto-zoom on raceboard;

This commit is contained in:
Christopher Ronnewinkel (D036654) committed 2014-08-04 22:52:54 +02:00
1 parent 419daa7a8e
commit 89426cb773
6 files changed
+111 -16

No files matched your search

@@ -268,6 +268,8 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
*/
private LatLngBounds currentMapBounds;
private int currentZoomLevel;
private WindStreamletsRaceboardOverlay streamletOverlay;
private final boolean showViewStreamlets;
private final RegattaAndRaceIdentifier raceIdentifier;
@@ -382,10 +384,12 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
infoOverlay.removeCanvasPositionAndRotationTransition();
}
}
if (streamletOverlay != null) {
streamletOverlay.onBoundsChanged();
int newZoomLevel = map.getZoom();
if ((streamletOverlay != null) && !map.getBounds().equals(currentMapBounds)) {
streamletOverlay.onBoundsChanged(newZoomLevel != currentZoomLevel);
}
currentMapBounds = map.getBounds();
currentZoomLevel = newZoomLevel;
}
});
@@ -21,7 +21,7 @@ import com.sap.sailing.gwt.ui.shared.WindDTO;
import com.sap.sailing.gwt.ui.shared.WindInfoForRaceDTO;
import com.sap.sailing.gwt.ui.shared.WindTrackInfoDTO;
import com.sap.sailing.gwt.ui.simulator.StreamletParameters;
import com.sap.sailing.gwt.ui.simulator.racemap.FullCanvasOverlay;
import com.sap.sailing.gwt.ui.simulator.racemap.MovingCanvasOverlay;
import com.sap.sailing.gwt.ui.simulator.streamlets.Swarm;
import com.sap.sailing.gwt.ui.simulator.streamlets.VectorField;
import com.sap.sailing.gwt.ui.simulator.streamlets.WindInfoForRaceVectorField;
@@ -38,7 +38,7 @@ import com.sap.sse.gwt.client.player.Timer;
* @author Axel Uhl (D043530)
*
*/
public class WindStreamletsRaceboardOverlay extends FullCanvasOverlay {
public class WindStreamletsRaceboardOverlay extends MovingCanvasOverlay {
public static final String LODA_WIND_STREAMLET_DATA_CATEGORY = "loadWindStreamletData";
private static final int animationIntervalMillis = 40;
private static final long RESOLUTION_IN_MILLIS = 5000;
@@ -220,9 +220,9 @@ public class WindStreamletsRaceboardOverlay extends FullCanvasOverlay {
protected void drawCenterChanged() {
}
public void onBoundsChanged() {
public void onBoundsChanged(boolean zoomChanged) {
if (swarm != null) {
swarm.onBoundsChanged();
swarm.onBoundsChanged(zoomChanged);
}
}
}
@@ -477,7 +477,7 @@ public class SimulatorMap extends AbsolutePanel implements RequiresDataInitializ
Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() {
public void execute() {
if (windStreamletsCanvasOverlay.getSwarm() != null) {
windStreamletsCanvasOverlay.getSwarm().onBoundsChanged();
windStreamletsCanvasOverlay.getSwarm().onBoundsChanged(true);
}
}
});
@@ -13,6 +13,7 @@ import com.google.gwt.user.client.ui.RequiresResize;
import com.sap.sailing.domain.common.dto.PositionDTO;
import com.sap.sailing.gwt.ui.shared.SimulatorWindDTO;
import com.sap.sailing.gwt.ui.shared.racemap.CanvasOverlayV3;
import com.sap.sailing.gwt.ui.simulator.streamlets.Vector;
/**
* This class extends @CanvasOverlayV3 to provide the functionality that the canvas always covers the
@@ -25,10 +26,12 @@ import com.sap.sailing.gwt.ui.shared.racemap.CanvasOverlayV3;
public abstract class FullCanvasOverlay extends CanvasOverlayV3 implements RequiresResize {
/** the x coordinate where the canvas is placed */
private double widgetPosLeft = 0;
protected double widgetPosLeft = 0;
/** the y coordinate where the canvas element is placed */
private double widgetPosTop = 0;
protected double widgetPosTop = 0;
protected Vector diffPx;
public String pointColor = "Red";
public String textColor = "Black";
@@ -43,6 +46,7 @@ public abstract class FullCanvasOverlay extends CanvasOverlayV3 implements Requi
drawCenterChanged();
};
});
diffPx = new Vector(0, 0);
}
/**
@@ -268,4 +272,8 @@ public abstract class FullCanvasOverlay extends CanvasOverlayV3 implements Requi
public void setWidgetPosTop(double widgetPosTop) {
this.widgetPosTop = widgetPosTop;
}
public Vector getDiffPx() {
return diffPx;
}
}
@@ -0,0 +1,66 @@
package com.sap.sailing.gwt.ui.simulator.racemap;
import com.google.gwt.canvas.dom.client.Context2d;
import com.google.gwt.canvas.dom.client.ImageData;
import com.google.gwt.maps.client.MapWidget;
import com.google.gwt.maps.client.base.LatLng;
import com.google.gwt.maps.client.base.Point;
import com.sap.sailing.gwt.ui.simulator.streamlets.Vector;
/**
* This class extends @FullCanvasOverlay to provide the functionality that the canvas covers the
* full viewable area of the map and moves previously drawn content according to drag and zoom
*
* @author Christopher Ronnewinkel (D036654)
*
*/
public abstract class MovingCanvasOverlay extends FullCanvasOverlay {
private LatLng ne;
private LatLng sw;
public MovingCanvasOverlay(MapWidget map, int zIndex) {
super(map, zIndex);
}
@Override
public void setCanvasSettings() {
int canvasWidth = getMap().getDiv().getClientWidth();
int canvasHeight = getMap().getDiv().getClientHeight();
Context2d ctxt = canvas.getContext2d();
ImageData canvasContent = ctxt.getImageData(0, 0, canvas.getElement().getClientWidth(), canvas.getElement().getClientHeight());
canvas.setWidth(String.valueOf(canvasWidth));
canvas.setHeight(String.valueOf(canvasHeight));
canvas.setCoordinateSpaceWidth(canvasWidth);
canvas.setCoordinateSpaceHeight(canvasHeight);
Point oldSWpx = mapProjection.fromLatLngToDivPixel(sw);
Point oldNEpx = mapProjection.fromLatLngToDivPixel(ne);
sw = getMap().getBounds().getSouthWest();
ne = getMap().getBounds().getNorthEast();
Point swPx = mapProjection.fromLatLngToDivPixel(sw);
Point nePx = mapProjection.fromLatLngToDivPixel(ne);
widgetPosLeft = Math.min(swPx.getX(), nePx.getX());
widgetPosTop = Math.min(swPx.getY(), nePx.getY());
double oldLeftpx;
double oldToppx;
if (oldSWpx == null) {
oldLeftpx = widgetPosLeft;
oldToppx = widgetPosTop;
} else {
oldLeftpx = Math.min(oldSWpx.getX(), oldNEpx.getX());
oldToppx = Math.min(oldSWpx.getY(), oldNEpx.getY());
}
diffPx = new Vector(oldLeftpx - widgetPosLeft, oldToppx - widgetPosTop);
ctxt = canvas.getContext2d();
ctxt.putImageData(canvasContent, diffPx.x, diffPx.y);
setCanvasPosition(getWidgetPosLeft(), getWidgetPosTop());
}
}
@@ -24,6 +24,9 @@ public class Swarm implements TimeListener {
private Mercator projection;
private final VectorField field;
private boolean zoomChanged = false;
private Vector diffPx;
/**
* The number of particles to show. After {@link #updateBounds()} has been run, this also reflects the size of the
* {@link #particles} array. Note that since elements in {@link #particles} can be <code>null</code>, this number
@@ -59,6 +62,7 @@ public class Swarm implements TimeListener {
this.parameters = streamletPars;
timePoint = timer.getTime();
cosineOfAverageLatitude = 1.0; // default to equator
diffPx = new Vector(0, 0);
}
public void start(int animationIntervalMillis) {
@@ -125,8 +129,11 @@ public class Swarm implements TimeListener {
return newParticles;
}
public void onBoundsChanged() {
projection.clearCanvas();
public void onBoundsChanged(boolean zoomChanged) {
this.zoomChanged |= zoomChanged;
if (this.zoomChanged) {
projection.clearCanvas();
}
swarmPause = 5;
}
@@ -141,8 +148,7 @@ public class Swarm implements TimeListener {
Vector boundsNEpx = this.projection.latlng2pixel(visibleBoundsOfField.getNorthEast());
double boundsWidthpx = Math.abs(boundsNEpx.x - boundsSWpx.x);
double boundsHeightpx = Math.abs(boundsSWpx.y - boundsNEpx.y);
this.nParticles = (int) Math.round(Math.sqrt(boundsWidthpx * boundsHeightpx) * this.field.getParticleFactor()
* this.parameters.swarmScale);
this.nParticles = (int)Math.round(Math.sqrt(boundsWidthpx * boundsHeightpx) * this.field.getParticleFactor() * this.parameters.swarmScale);
cosineOfAverageLatitude = Math.cos((visibleBoundsOfField.getSouthWest().getLatRad()+visibleBoundsOfField.getNorthEast().getLatRad())/2);
};
@@ -155,13 +161,18 @@ public class Swarm implements TimeListener {
swarmPause--;
} else if (swarmPause == 1) {
fullcanvas.setCanvasSettings();
diffPx = fullcanvas.getDiffPx();
projection.calibrate();
updateBounds();
particles = createParticles();
if (zoomChanged) {
particles = createParticles();
zoomChanged = false;
}
swarmPause = 0;
}
if ((!swarmOffScreen) && (swarmPause == 0)) {
execute();
execute(diffPx);
diffPx = new Vector(0, 0);
}
Date time1 = new Date();
if (swarmContinue) {
@@ -203,7 +214,7 @@ public class Swarm implements TimeListener {
* Moves each particle by its vector {@link Particle#v} multiplied by the speed which is 0.01 times the
* {@link VectorField#getMotionScale(int)} at the map's current zoom level.
*/
private boolean execute() {
private boolean execute(Vector diffPx) {
double speed = 0.01 * field.getMotionScale(map.getZoom());
for (int idx = 0; idx < particles.length; idx++) {
Particle particle = particles[idx];
@@ -212,6 +223,12 @@ public class Swarm implements TimeListener {
// update its currentPosition, currentPixelCoordinate and previousPixelCoordinate fields;
// also, its particle.v field is updated based on its new position from the vector field
particle.previousPixelCoordinate = particle.currentPixelCoordinate;
if (diffPx.x != 0) {
particle.previousPixelCoordinate.x += diffPx.x;
}
if (diffPx.y != 0) {
particle.previousPixelCoordinate.y += diffPx.y;
}
double latDeg = particle.currentPosition.getLatDeg() + speed * particle.v.y;
double lngDeg = particle.currentPosition.getLngDeg() + speed * particle.v.x / cosineOfAverageLatitude;
particle.currentPosition = new DegreePosition(latDeg, lngDeg);