mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-08 13:20:57 +00:00
Merge remote-tracking branch 'origin/master' into newhome
This commit is contained in:
commit
9635c95551
11 files changed
+151
-84
No files matched your search
-4
@@ -9,7 +9,6 @@ import com.google.gwt.user.client.ui.SimplePanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.gwt.home.client.shared.footer.Footer;
|
||||
import com.sap.sailing.gwt.home.client.shared.header.Header;
|
||||
import com.sap.sailing.gwt.home.client.shared.placeholder.Placeholder;
|
||||
|
||||
/**
|
||||
* This is the top-level view of the application. Every time another presenter wants to reveal itself,
|
||||
@@ -33,9 +32,6 @@ public class TabletAndDesktopApplicationView extends Composite implements Applic
|
||||
public TabletAndDesktopApplicationView(PlaceNavigator navigator) {
|
||||
headerPanel = new Header(navigator);
|
||||
initWidget(uiBinder.createAndBindUi(this));
|
||||
|
||||
Placeholder placeHolder = new Placeholder();
|
||||
mainContentPanel.setWidget(placeHolder);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+12
-10
@@ -84,7 +84,7 @@ public class EventRegattaRacesRace extends UIObject {
|
||||
setElement(uiBinder.createAndBindUi(this));
|
||||
|
||||
allConditionalElements = new Element[] {raceWinnerDiv, raceLeaderDiv, watchRaceDiv, analyzeRaceDiv, raceNotTrackedDiv,
|
||||
raceFeaturesDiv, legProgressDiv, raceFlagDiv, windStatusDiv, currentLegNo, totalLegsCount };
|
||||
raceFeaturesDiv, legProgressDiv, raceFlagDiv, windStatusDiv };
|
||||
|
||||
if(fleet.getColor() != null) {
|
||||
fleetColor.getStyle().setBackgroundColor(fleet.getColor().getAsHtml());
|
||||
@@ -149,14 +149,15 @@ public class EventRegattaRacesRace extends UIObject {
|
||||
break;
|
||||
case TRACKED_AND_LIVE:
|
||||
showElement(watchRaceDiv);
|
||||
showElement(legProgressDiv);
|
||||
showElement(currentLegNo);
|
||||
showElement(totalLegsCount);
|
||||
|
||||
raceTime.setInnerText(raceTimeFormat.format(race.startOfRace));
|
||||
currentLegNo.setInnerText(String.valueOf(race.trackedRaceStatistics.currentLegNo));
|
||||
totalLegsCount.setInnerText(String.valueOf(race.trackedRaceStatistics.totalLegsCount));
|
||||
|
||||
if(race.startOfRace != null) {
|
||||
raceTime.setInnerText(raceTimeFormat.format(race.startOfRace));
|
||||
}
|
||||
if(race.trackedRaceStatistics.hasLegProgressData) {
|
||||
showElement(legProgressDiv);
|
||||
currentLegNo.setInnerText(String.valueOf(race.trackedRaceStatistics.currentLegNo));
|
||||
totalLegsCount.setInnerText(String.valueOf(race.trackedRaceStatistics.totalLegsCount));
|
||||
}
|
||||
if(race.trackedRaceStatistics.hasLeaderData && race.trackedRaceStatistics.leaderOrWinner != null) {
|
||||
showElement(raceLeaderDiv);
|
||||
updateWinnerOrLeader(raceLeader, race.trackedRaceStatistics.leaderOrWinner);
|
||||
@@ -170,9 +171,10 @@ public class EventRegattaRacesRace extends UIObject {
|
||||
showElement(raceWinnerDiv);
|
||||
updateWinnerOrLeader(raceWinner, race.trackedRaceStatistics.leaderOrWinner);
|
||||
}
|
||||
if(race.startOfRace != null) {
|
||||
raceTime.setInnerText(raceTimeFormat.format(race.startOfRace));
|
||||
}
|
||||
showElement(raceFeaturesDiv);
|
||||
|
||||
raceTime.setInnerText(raceTimeFormat.format(race.startOfRace));
|
||||
updateRaceFeatures();
|
||||
|
||||
break;
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@
|
||||
<div ui:field="raceLeaderDiv" class="{local_res.css.eventregattarace_details} {local_res.css.eventregattarace_leader}">
|
||||
<ui:text from="{i18n.eventRegattaRaceLeader}"/><br></br><span ui:field="raceLeader" class="{local_res.css.eventregattarace_leader_name}"></span>
|
||||
</div>
|
||||
<div ui:field="legProgressDiv" class="{local_res.css.eventregattarace_details} {local_res.css.eventregattarace_legs}"><ui:text from='{i18n.leg}'/>&nbps;<span ui:field="currentLegNo" />/<span ui:field="totalLegsCount" />
|
||||
<div ui:field="legProgressDiv" class="{local_res.css.eventregattarace_details} {local_res.css.eventregattarace_legs}"><ui:text from='{i18n.leg}'/> <span ui:field="currentLegNo" />/<span ui:field="totalLegsCount" />
|
||||
<div class="{local_res.css.eventregattarace_legs_list}">
|
||||
<div data-status="r" class="{local_res.css.eventregattarace_legs_leg}"></div>
|
||||
</div>
|
||||
|
||||
+13
-12
@@ -67,22 +67,23 @@ public class Stage extends Composite {
|
||||
stageTeaserComposites.add(stageTeaser);
|
||||
}
|
||||
|
||||
this.swiper = Swiper.createWithoutLoopOption(StageResources.INSTANCE.css().stage_teasers(),
|
||||
StageResources.INSTANCE.css().swiperwrapper(),
|
||||
StageResources.INSTANCE.css().swiperslide(), new Swiper.PageChangeListener() {
|
||||
|
||||
@Override
|
||||
public void pageChanged(int newPageIndex, int pageCount) {
|
||||
boolean isFirstSlide = newPageIndex == 0;
|
||||
boolean isLastSlide = newPageIndex == pageCount - 1;
|
||||
nextStageTeaserLink.setVisible(!isLastSlide);
|
||||
prevStageTeaserLink.setVisible(!isFirstSlide);
|
||||
}
|
||||
});
|
||||
if (featuredEvents.size() <= 1) {
|
||||
prevStageTeaserLink.setVisible(false);
|
||||
nextStageTeaserLink.setVisible(false);
|
||||
} else {
|
||||
swiper = Swiper.createWithoutLoopOption(StageResources.INSTANCE.css().stage_teasers(),
|
||||
StageResources.INSTANCE.css().swiperwrapper(),
|
||||
StageResources.INSTANCE.css().swiperslide(), new Swiper.PageChangeListener() {
|
||||
|
||||
@Override
|
||||
public void pageChanged(int newPageIndex, int pageCount) {
|
||||
boolean isFirstSlide = newPageIndex == 0;
|
||||
boolean isLastSlide = newPageIndex == pageCount - 1;
|
||||
nextStageTeaserLink.setVisible(!isLastSlide);
|
||||
prevStageTeaserLink.setVisible(!isFirstSlide);
|
||||
}
|
||||
});
|
||||
|
||||
prevStageTeaserLink.setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
+32
-24
@@ -278,13 +278,13 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
/**
|
||||
* The map bounds as last received by map callbacks; used to determine whether to suppress the boat animation during zoom/pan
|
||||
*/
|
||||
private LatLngBounds currentMapBounds;
|
||||
private LatLngBounds currentMapBounds; // bounds to which bounds-changed-handler compares
|
||||
private int currentZoomLevel; // zoom-level to which bounds-changed-handler compares
|
||||
|
||||
private int currentZoomLevel;
|
||||
private boolean autoZoomIn = false;
|
||||
private boolean autoZoomOut = false;
|
||||
private int autoZoomLevel;
|
||||
LatLngBounds autoZoomLatLngBounds;
|
||||
private boolean autoZoomIn = false; // flags auto-zoom-in in progress
|
||||
private boolean autoZoomOut = false; // flags auto-zoom-out in progress
|
||||
private int autoZoomLevel; // zoom-level to which auto-zoom-in/-out is zooming
|
||||
LatLngBounds autoZoomLatLngBounds; // bounds to which auto-zoom-in/-out is panning&zooming
|
||||
|
||||
private WindStreamletsRaceboardOverlay streamletOverlay;
|
||||
private final boolean showViewStreamlets;
|
||||
@@ -385,6 +385,8 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
@Override
|
||||
public void onEvent(DragEndMapEvent event) {
|
||||
// stop automatic zoom after a manual drag event
|
||||
autoZoomIn = false;
|
||||
autoZoomOut = false;
|
||||
final List<RaceMapZoomSettings.ZoomTypes> emptyList = Collections.emptyList();
|
||||
settings.getZoomSettings().setTypesToConsiderOnZoom(emptyList);
|
||||
}
|
||||
@@ -392,11 +394,14 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
map.addIdleHandler(new IdleMapHandler() {
|
||||
@Override
|
||||
public void onEvent(IdleMapEvent event) {
|
||||
// the "idle"-event is raised at the end of map-animations
|
||||
if (autoZoomIn) {
|
||||
// finalize zoom-in that was started with panTo() in zoomMapToNewBounds()
|
||||
map.setZoom(autoZoomLevel);
|
||||
autoZoomIn = false;
|
||||
}
|
||||
if (autoZoomOut) {
|
||||
// finalize zoom-out that was started with setZoom() in zoomMapToNewBounds()
|
||||
map.panTo(autoZoomLatLngBounds.getCenter());
|
||||
autoZoomOut = false;
|
||||
}
|
||||
@@ -407,14 +412,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
public void onEvent(BoundsChangeMapEvent event) {
|
||||
int newZoomLevel = map.getZoom();
|
||||
if (!isAutoZoomInProgress() && (newZoomLevel != currentZoomLevel)) {
|
||||
// remove the canvas animations for boats
|
||||
for (BoatOverlay boatOverlay : RaceMap.this.getBoatOverlays().values()) {
|
||||
boatOverlay.removeCanvasPositionAndRotationTransition();
|
||||
}
|
||||
// remove the canvas animations for the info overlays of the selected boats
|
||||
for (CompetitorInfoOverlay infoOverlay : competitorInfoOverlays.values()) {
|
||||
infoOverlay.removeCanvasPositionAndRotationTransition();
|
||||
}
|
||||
removeTransitions();
|
||||
}
|
||||
if ((streamletOverlay != null) && !map.getBounds().equals(currentMapBounds)) {
|
||||
streamletOverlay.onBoundsChanged(newZoomLevel != currentZoomLevel);
|
||||
@@ -444,7 +442,18 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
|
||||
LoadApi.go(onLoad, loadLibraries, sensor, "key="+GoogleMapAPIKey.V3_APIKey);
|
||||
}
|
||||
|
||||
|
||||
private void removeTransitions() {
|
||||
// remove the canvas animations for boats
|
||||
for (BoatOverlay boatOverlay : RaceMap.this.getBoatOverlays().values()) {
|
||||
boatOverlay.removeCanvasPositionAndRotationTransition();
|
||||
}
|
||||
// remove the canvas animations for the info overlays of the selected boats
|
||||
for (CompetitorInfoOverlay infoOverlay : competitorInfoOverlays.values()) {
|
||||
infoOverlay.removeCanvasPositionAndRotationTransition();
|
||||
}
|
||||
}
|
||||
|
||||
public void redraw() {
|
||||
timeChanged(timer.getTime(), null);
|
||||
}
|
||||
@@ -1235,17 +1244,15 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
autoZoomLatLngBounds = BoundsUtil.getAsLatLngBounds(newBounds);
|
||||
int newZoomLevel = getZoomLevel(autoZoomLatLngBounds);
|
||||
if (newZoomLevel != map.getZoom()) {
|
||||
// remove the canvas animations for boats
|
||||
for (BoatOverlay boatOverlay : RaceMap.this.getBoatOverlays().values()) {
|
||||
boatOverlay.removeCanvasPositionAndRotationTransition();
|
||||
}
|
||||
// remove the canvas animations for the info overlays of the selected boats
|
||||
for(CompetitorInfoOverlay infoOverlay: competitorInfoOverlays.values()) {
|
||||
infoOverlay.removeCanvasPositionAndRotationTransition();
|
||||
}
|
||||
// distinguish between zoom-in and zoom-out, because the sequence of panTo() and setZoom()
|
||||
// appears different on the screen due to map-animations
|
||||
// following sequences keep the selected boats allways visible:
|
||||
// zoom-in : 1. panTo(), 2. setZoom()
|
||||
// zoom-out: 1. setZoom(), 2. panTo()
|
||||
autoZoomIn = newZoomLevel > map.getZoom();
|
||||
autoZoomOut = !autoZoomIn;
|
||||
autoZoomLevel = newZoomLevel;
|
||||
removeTransitions();
|
||||
if (autoZoomIn) {
|
||||
map.panTo(autoZoomLatLngBounds.getCenter());
|
||||
} else {
|
||||
@@ -1847,8 +1854,9 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
|
||||
requiredRedraw = true;
|
||||
}
|
||||
if (!newSettings.getZoomSettings().equals(settings.getZoomSettings())) {
|
||||
settings.setZoomSettings(newSettings.getZoomSettings());
|
||||
settings.setZoomSettings(newSettings.getZoomSettings());
|
||||
if (!settings.getZoomSettings().containsZoomType(ZoomTypes.NONE)) {
|
||||
removeTransitions();
|
||||
zoomMapToNewBounds(settings.getZoomSettings().getNewBounds(this));
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -102,6 +102,7 @@ public class WindStreamletsRaceboardOverlay extends MovingCanvasOverlay {
|
||||
setCanvasSettings();
|
||||
this.swarm = new Swarm(this, map, timer, windField, new StreamletParameters());
|
||||
}
|
||||
initCanvasOrigin();
|
||||
this.swarm.start(animationIntervalMillis);
|
||||
}
|
||||
|
||||
|
||||
+38
-27
@@ -16,8 +16,7 @@ import com.sap.sailing.gwt.ui.simulator.streamlets.Vector;
|
||||
*/
|
||||
public abstract class MovingCanvasOverlay extends FullCanvasOverlay {
|
||||
|
||||
private LatLng ne;
|
||||
private LatLng sw;
|
||||
private LatLng nw;
|
||||
|
||||
public MovingCanvasOverlay(MapWidget map, int zIndex) {
|
||||
super(map, zIndex);
|
||||
@@ -25,45 +24,57 @@ public abstract class MovingCanvasOverlay extends FullCanvasOverlay {
|
||||
|
||||
@Override
|
||||
public void setCanvasSettings() {
|
||||
|
||||
// do nothing, if mapProjection is not available
|
||||
if (mapProjection == null)
|
||||
return;
|
||||
|
||||
int canvasWidth = getMap().getDiv().getClientWidth();
|
||||
int canvasHeight = getMap().getDiv().getClientHeight();
|
||||
|
||||
|
||||
// calculate pixel-positions of old and new canvas-bounds using the same, current mapProjection
|
||||
// start from LatLng, as the canvas might have jumped to new bounds that do not intersect with the old bounds
|
||||
Point nwOldPx;
|
||||
if (nw == null) {
|
||||
nwOldPx = null;
|
||||
} else {
|
||||
nwOldPx = mapProjection.fromLatLngToDivPixel(nw);
|
||||
}
|
||||
nw = LatLng.newInstance(getMap().getBounds().getNorthEast().getLatitude(), getMap().getBounds().getSouthWest().getLongitude());
|
||||
Point nwNewPx = mapProjection.fromLatLngToDivPixel(nw);
|
||||
widgetPosLeft = Math.round(nwNewPx.getX());
|
||||
widgetPosTop = Math.round(nwNewPx.getY());
|
||||
|
||||
// calculate the translation-vector between old and new origin in pixels
|
||||
if (nwOldPx == null) {
|
||||
diffPx = new Vector(0, 0);
|
||||
} else {
|
||||
double oldPosLeft = Math.round(nwOldPx.getX());
|
||||
double oldPosTop = Math.round(nwOldPx.getY());
|
||||
diffPx = new Vector(oldPosLeft - widgetPosLeft, oldPosTop - widgetPosTop);
|
||||
}
|
||||
|
||||
// store canvas-content, because setWidth() and setHeight() will clear canvas and change Context2d
|
||||
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);
|
||||
|
||||
// get updated Context2d and restore canvas-content moved by translation-vector
|
||||
ctxt = canvas.getContext2d();
|
||||
ctxt.putImageData(canvasContent, diffPx.x, diffPx.y);
|
||||
|
||||
setCanvasPosition(getWidgetPosLeft(), getWidgetPosTop());
|
||||
// update canvas position
|
||||
setCanvasPosition(widgetPosLeft, widgetPosTop);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void draw() {
|
||||
// do nothing; setCanvasSettings() is called directly
|
||||
}
|
||||
|
||||
public void initCanvasOrigin() {
|
||||
nw = null;
|
||||
}
|
||||
}
|
||||
+4
-5
@@ -66,18 +66,17 @@ public class Swarm implements TimeListener {
|
||||
}
|
||||
|
||||
public void start(int animationIntervalMillis) {
|
||||
fullcanvas.setCanvasSettings();
|
||||
projection = new Mercator(fullcanvas, map);
|
||||
projection.calibrate();
|
||||
this.updateBounds();
|
||||
Context2d ctxt = canvas.getContext2d();
|
||||
ctxt.setFillStyle("red");
|
||||
updateBounds();
|
||||
particles = this.createParticles();
|
||||
this.swarmContinue = true;
|
||||
swarmContinue = true;
|
||||
startLoop(animationIntervalMillis);
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
this.swarmContinue = false;
|
||||
swarmContinue = false;
|
||||
}
|
||||
|
||||
private Particle createParticle() {
|
||||
|
||||
@@ -45,6 +45,27 @@
|
||||
<h2 class='articleSubheadline'>Upcoming and Live</h2>
|
||||
<br/>
|
||||
<div class="timeBar">
|
||||
<div class='raceSection'>
|
||||
<h5 class='date'>
|
||||
505 Worlds 2014
|
||||
</h5>
|
||||
<div class='raceTimepoint'></div>
|
||||
<a href='http://505worlds2014.sapsailing.com' target='_blank'>
|
||||
<ul class='racePanel'>
|
||||
<li class='raceName'>
|
||||
505 Worlds 2014
|
||||
</li>
|
||||
<li class='raceLocation'>
|
||||
Kiel, Germany
|
||||
</li>
|
||||
</ul>
|
||||
</a>
|
||||
<div class='raceDescription'>
|
||||
<p>505 Worlds 2014</p>
|
||||
<a href='http://505worlds2014.sapsailing.com' target='_blank'>SAP Sailing Analytics</a><br/>
|
||||
<a href='http://505worlds.com' target='_blank'>Official website</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class='raceSection'>
|
||||
<h5 class='date'>
|
||||
2014 Season
|
||||
|
||||
@@ -1,4 +1,30 @@
|
||||
# 505 worlds Kiel 2014
|
||||
# 505 Worlds 2014, Kiel
|
||||
|
||||
## Server Landscape
|
||||
|
||||
We run two servers for the event, A and B, for fast and available switching. The DB they use is called 505WORLDS2014, and so is the replication channel. The git branch we use to merge the features we want to deploy to the event servers is called `505worlds2014` and the git tag used to build a release for it is called `505worlds2014-release`. See http://hudson.sapsailing.com/job/SAPSailingAnalytics-505worlds2014/ and http://hudson.sapsailing.com/job/SAPSailingAnalytics-505worlds2014-release/, respectively, for their Hudson jobs.
|
||||
|
||||
Regatta Overview: http://505worlds2014ro.sapsailing.com
|
||||
|
||||
Manage2Sail Event URL: http://manage2sail.com/api/public/links/event/d70bee3e-9f65-46f4-96a1-9fd467712ce0?accesstoken=bDAv8CwsTM94ujZ&mediaType=json
|
||||
|
||||
Event Page (newhome): http://505worlds2014.sapsailing.com/gwt/Home.html#EventPlace:eventId=94e1e240-8a3d-466b-9f39-419f311eaace
|
||||
|
||||
### A server
|
||||
|
||||
Admin Console at http://ec2-54-77-58-65.eu-west-1.compute.amazonaws.com:8888/gwt/AdminConsole.html
|
||||
External IP: 54.77.58.65
|
||||
Internal IP: 172.31.30.45
|
||||
|
||||
### B server
|
||||
|
||||
Admin Console at http://ec2-54-77-33-52.eu-west-1.compute.amazonaws.com:8888/gwt/AdminConsole.html
|
||||
External IP: 54.77.33.52
|
||||
Internal IP: 172.31.31.62
|
||||
|
||||
## TracTrac URL
|
||||
|
||||
http://secondary.traclive.dk/events/event_20140813_Worlds/jsonservice.php
|
||||
|
||||
### Touch Computer (Lenovo) Setup
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
This document describes the onboarding process for a new team member (developer)
|
||||
|
||||
First of all, make sure you've looked at http://www.amazon.de/Patterns-Elements-Reusable-Object-Oriented-Software/dp/0201633612. That's a great book, and knowing at least some of it will help you a great deal finding your way around our solution.
|
||||
|
||||
### Race Analysis Development Setup
|
||||
|
||||
#### Installations
|
||||
|
||||
Reference in new issue
Block a user