Merge remote-tracking branch 'server/master' into leaderboard-refactoring

This commit is contained in:
Axel Uhl committed 2012-05-15 16:41:46 +02:00
commit 9d11b6e928
12 files changed
+271 -194

No files matched your search

@@ -50,6 +50,7 @@ import com.sap.sailing.gwt.ui.client.RaceSelectionModel;
import com.sap.sailing.gwt.ui.client.RaceSelectionProvider;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.client.TimeZoomModel;
import com.sap.sailing.gwt.ui.client.Timer;
import com.sap.sailing.gwt.ui.client.Timer.PlayModes;
import com.sap.sailing.gwt.ui.shared.RegattaDTO;
@@ -185,7 +186,7 @@ public class WindPanel extends FormPanel implements RegattaDisplayer, WindShower
windSourceSelectionPanel.add(showConfigAnchor);
grid.setWidget(1, 0, windSourceSelectionPanel);
WindChartSettings windChartSettings = new WindChartSettings(false, true, new HashSet<WindSourceType>(Arrays.asList(WindSourceType.values())));
windChart = new WindChart(sailingService, raceSelectionProvider, new Timer(PlayModes.Replay), windChartSettings, stringMessages, asyncActionsExecutor, errorReporter, false);
windChart = new WindChart(sailingService, raceSelectionProvider, new Timer(PlayModes.Replay), new TimeZoomModel(), windChartSettings, stringMessages, asyncActionsExecutor, errorReporter, false);
windChart.onResize();
grid.setWidget(2, 0, windChart.getEntryWidget());
grid.getCellFormatter().setVerticalAlignment(1, 1, HasVerticalAlignment.ALIGN_TOP);
@@ -0,0 +1,10 @@
package com.sap.sailing.gwt.ui.client;
import java.util.Date;
public interface TimeZoomChangeListener {
void onTimeZoom(Date zoomStartTimepoint, Date zoomEndTimepoint);
void onTimeZoomReset();
}
@@ -0,0 +1,59 @@
package com.sap.sailing.gwt.ui.client;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import com.sap.sailing.domain.common.impl.Util.Pair;
public class TimeZoomModel implements TimeZoomProvider {
private Date zoomStartTimepoint;
private Date zoomEndTimepoint;
private boolean isTimeZoomed;
private final Set<TimeZoomChangeListener> listeners;
public TimeZoomModel() {
isTimeZoomed = false;
listeners = new HashSet<TimeZoomChangeListener>();
}
@Override
public void addTimeZoomChangeListener(TimeZoomChangeListener listener) {
listeners.add(listener);
}
@Override
public void removeTimeZoomChangeListener(TimeZoomChangeListener listener) {
listeners.remove(listener);
}
public void setTimeZoom(Date zoomStartTimepoint, Date zoomEndTimepoint, TimeZoomChangeListener... listenersNotToNotify) {
this.zoomStartTimepoint = zoomStartTimepoint;
this.zoomEndTimepoint = zoomEndTimepoint;
this.isTimeZoomed = true;
for (TimeZoomChangeListener listener : listeners) {
if (listenersNotToNotify == null || !Arrays.asList(listenersNotToNotify).contains(listener)) {
listener.onTimeZoom(zoomStartTimepoint, zoomEndTimepoint);
}
}
}
public void resetTimeZoom(TimeZoomChangeListener... listenersNotToNotify) {
isTimeZoomed = false;
for (TimeZoomChangeListener listener : listeners) {
if (listenersNotToNotify == null || !Arrays.asList(listenersNotToNotify).contains(listener)) {
listener.onTimeZoomReset();
}
}
}
public Pair<Date, Date> getTimeZoom() {
return new Pair<Date, Date>(zoomStartTimepoint, zoomEndTimepoint);
}
public boolean isZoomed() {
return isTimeZoomed;
}
}
@@ -0,0 +1,20 @@
package com.sap.sailing.gwt.ui.client;
import java.util.Date;
import com.sap.sailing.domain.common.impl.Util.Pair;
public interface TimeZoomProvider {
public void addTimeZoomChangeListener(TimeZoomChangeListener listener);
public void removeTimeZoomChangeListener(TimeZoomChangeListener listener);
public void setTimeZoom(Date zoomStartTimepoint, Date zoomEndTimepoint, TimeZoomChangeListener... listenersNotToNotify);
public void resetTimeZoom(TimeZoomChangeListener... listenersNotToNotify);
public Pair<Date, Date> getTimeZoom();
public boolean isZoomed();
}
@@ -28,6 +28,7 @@ import com.sap.sailing.gwt.ui.client.RaceSelectionModel;
import com.sap.sailing.gwt.ui.client.RaceSelectionProvider;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.client.TimeZoomModel;
import com.sap.sailing.gwt.ui.client.Timer;
import com.sap.sailing.gwt.ui.shared.charts.MultiChartPanel;
import com.sap.sailing.gwt.ui.shared.charts.MultiChartSettings;
@@ -57,7 +58,7 @@ public class CompareCompetitorsChartDialog extends DialogBox {
raceSelectionProvider.setAllRaces(races);
multiChartPanel = new MultiChartPanel(sailingService, new AsyncActionsExecutor(), competitorSelectionProvider, raceSelectionProvider,
timer, stringConstants, errorReporter, false, false);
timer, new TimeZoomModel(), stringConstants, errorReporter, false, false);
multiChartPanel.setSize("100%", "100%");
FlowPanel contentPanel = new FlowPanel();
@@ -33,6 +33,7 @@ import com.sap.sailing.gwt.ui.client.RaceTimesInfoProvider;
import com.sap.sailing.gwt.ui.client.RegattaDisplayer;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.client.TimeZoomModel;
import com.sap.sailing.gwt.ui.client.Timer;
import com.sap.sailing.gwt.ui.client.UserAgentChecker.UserAgentTypes;
import com.sap.sailing.gwt.ui.leaderboard.LeaderboardPanel;
@@ -84,6 +85,7 @@ public class RaceBoardPanel extends FormPanel implements RegattaDisplayer, RaceS
private final RaceSelectionProvider raceSelectionProvider;
private final UserAgentTypes userAgentType;
private final CompetitorSelectionModel competitorSelectionModel;
private final TimeZoomModel timeZoomModel;
private final RegattaAndRaceIdentifier selectedRaceIdentifier;
private LeaderboardPanel leaderboardPanel;
@@ -122,6 +124,7 @@ public class RaceBoardPanel extends FormPanel implements RegattaDisplayer, RaceS
setWidget(mainPanel);
this.timer = timer;
timeZoomModel = new TimeZoomModel();
componentViewers = new ArrayList<ComponentViewer>();
competitorSelectionModel = new CompetitorSelectionModel(/* hasMultiSelection */ true);
@@ -155,7 +158,7 @@ public class RaceBoardPanel extends FormPanel implements RegattaDisplayer, RaceS
List<Component<?>> components = new ArrayList<Component<?>>();
competitorChart = new MultiChartPanel(sailingService, asyncActionsExecutor, competitorSelectionModel, raceSelectionProvider,
timer, stringMessages, errorReporter, true, true);
timer, timeZoomModel, stringMessages, errorReporter, true, true);
competitorChart.onRaceSelectionChange(raceSelectionProvider.getSelectedRaces());
components.add(competitorChart);
competitorChart.setVisible(false);
@@ -233,7 +236,7 @@ public class RaceBoardPanel extends FormPanel implements RegattaDisplayer, RaceS
private WindChart createWindChart(AsyncActionsExecutor asyncActionsExecutor) {
WindChartSettings windChartSettings = new WindChartSettings(false, true, new HashSet<WindSourceType>(Arrays.asList(WindSourceType.values())));
return new WindChart(sailingService, raceSelectionProvider, timer, windChartSettings,
return new WindChart(sailingService, raceSelectionProvider, timer, timeZoomModel, windChartSettings,
stringMessages, asyncActionsExecutor, errorReporter, viewMode == RaceBoardViewModes.ONESCREEN);
}
@@ -35,6 +35,7 @@ import org.osgi.framework.BundleContext;
import org.osgi.util.tracker.ServiceTracker;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Buoy;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Course;
@@ -423,6 +424,10 @@ public class SailingServiceImpl extends RemoteServiceServlet implements SailingS
List<CompetitorDTO> competitorList = getCompetitorDTOs(regatta.getCompetitors());
RegattaDTO regattaDTO = new RegattaDTO(regatta.getName(), competitorList);
regattaDTO.races = getRaceDTOs(regatta);
BoatClass boatClass = regatta.getBoatClass();
if(boatClass != null) {
regattaDTO.boatClass = new BoatClassDTO(boatClass.getName(), boatClass.getHullLength().getMeters());
}
if (!regattaDTO.races.isEmpty()) {
for (RaceDTO race : regattaDTO.races) {
race.setRegatta(regattaDTO);
@@ -11,7 +11,6 @@ import org.moxieapps.gwt.highcharts.client.Axis;
import org.moxieapps.gwt.highcharts.client.Chart;
import org.moxieapps.gwt.highcharts.client.ChartSubtitle;
import org.moxieapps.gwt.highcharts.client.ChartTitle;
import org.moxieapps.gwt.highcharts.client.Extremes;
import org.moxieapps.gwt.highcharts.client.Point;
import org.moxieapps.gwt.highcharts.client.Series;
import org.moxieapps.gwt.highcharts.client.ToolTip;
@@ -25,12 +24,8 @@ import org.moxieapps.gwt.highcharts.client.plotOptions.LinePlotOptions;
import org.moxieapps.gwt.highcharts.client.plotOptions.Marker;
import org.moxieapps.gwt.highcharts.client.plotOptions.ScatterPlotOptions;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.i18n.client.NumberFormat;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.AbsolutePanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RequiresResize;
import com.google.gwt.user.client.ui.Widget;
@@ -45,19 +40,16 @@ import com.sap.sailing.gwt.ui.client.CompetitorSelectionChangeListener;
import com.sap.sailing.gwt.ui.client.CompetitorSelectionProvider;
import com.sap.sailing.gwt.ui.client.DetailTypeFormatter;
import com.sap.sailing.gwt.ui.client.ErrorReporter;
import com.sap.sailing.gwt.ui.client.RaceSelectionChangeListener;
import com.sap.sailing.gwt.ui.client.RaceSelectionProvider;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.client.TimeListener;
import com.sap.sailing.gwt.ui.client.TimeZoomProvider;
import com.sap.sailing.gwt.ui.client.Timer;
import com.sap.sailing.gwt.ui.client.Timer.PlayModes;
import com.sap.sailing.gwt.ui.shared.CompetitorDTO;
import com.sap.sailing.gwt.ui.shared.CompetitorRaceDataDTO;
import com.sap.sailing.gwt.ui.shared.MultiCompetitorRaceDataDTO;
import com.sap.sailing.gwt.ui.shared.components.Component;
import com.sap.sailing.gwt.ui.shared.panels.BusyIndicator;
import com.sap.sailing.gwt.ui.shared.panels.SimpleBusyIndicator;
/**
* ChartPanel is a GWT panel that can show one sort of competitor data (e.g. current speed over ground, windward distance to
@@ -71,47 +63,32 @@ import com.sap.sailing.gwt.ui.shared.panels.SimpleBusyIndicator;
* @author Benjamin Ebling (D056866), Axel Uhl (d043530)
*
*/
public abstract class AbstractChartPanel<SettingsType extends ChartSettings> extends SimpleChartPanel
implements CompetitorSelectionChangeListener, RaceSelectionChangeListener, TimeListener, RequiresResize {
public abstract class AbstractChartPanel<SettingsType extends ChartSettings> extends RaceChart
implements CompetitorSelectionChangeListener, RequiresResize {
private static final int LINE_WIDTH = 1;
private MultiCompetitorRaceDataDTO chartData;
private final SailingServiceAsync sailingService;
private final AsyncActionsExecutor asyncActionsExecutor;
private final ErrorReporter errorReporter;
private Chart chart;
private boolean compactChart;
private final AbsolutePanel busyIndicatorPanel;
private final Label noCompetitorsSelectedLabel;
private final Map<CompetitorDTO, Series> dataSeriesByCompetitor;
private final Map<CompetitorDTO, Series> markPassingSeriesByCompetitor;
private Series timeLineSeries;
private boolean timeLineNeedsUpdate = true;
private final boolean allowTimeAdjust;
private boolean ignoreTimeAdjustOnce;
private final RaceSelectionProvider raceSelectionProvider;
private long stepSize = 5000;
protected final StringMessages stringMessages;
private final DateTimeFormat dateFormat = DateTimeFormat.getFormat("HH:mm:ss");
private DetailType dataToShow;
private final CompetitorSelectionProvider competitorSelectionProvider;
public AbstractChartPanel(SailingServiceAsync sailingService, AsyncActionsExecutor asyncActionsExecutor,
CompetitorSelectionProvider competitorSelectionProvider, RaceSelectionProvider raceSelectionProvider,
Timer timer, final StringMessages stringMessages, ErrorReporter errorReporter, DetailType dataToShow,
Timer timer, TimeZoomProvider timeZoomProvider, final StringMessages stringMessages, ErrorReporter errorReporter, DetailType dataToShow,
boolean compactChart, boolean allowTimeAdjust) {
super(timer);
this.stringMessages = stringMessages;
super(sailingService, timer, timeZoomProvider, stringMessages, asyncActionsExecutor, errorReporter);
dataSeriesByCompetitor = new HashMap<CompetitorDTO, Series>();
markPassingSeriesByCompetitor = new HashMap<CompetitorDTO, Series>();
this.timer.addTimeListener(this);
this.competitorSelectionProvider = competitorSelectionProvider;
competitorSelectionProvider.addCompetitorSelectionChangeListener(this);
this.errorReporter = errorReporter;
this.dataToShow = dataToShow;
chartData = null;
this.compactChart = compactChart;
this.sailingService = sailingService;
this.asyncActionsExecutor = asyncActionsExecutor;
this.raceSelectionProvider = raceSelectionProvider;
this.allowTimeAdjust = allowTimeAdjust;
raceSelectionProvider.addRaceSelectionChangeListener(this);
@@ -121,26 +98,14 @@ implements CompetitorSelectionChangeListener, RaceSelectionChangeListener, TimeL
noCompetitorsSelectedLabel.setStyleName("abstractChartPanel-importantMessageOfChart");
chart = createChart(dataToShow);
if (allowTimeAdjust) {
timeLineSeries = createTimeLineSeries();
}
busyIndicatorPanel = new AbsolutePanel();
final BusyIndicator busyIndicator = new SimpleBusyIndicator(/*busy*/ true, /*scale*/ 1);
//Adding the busyIndicator with an scheduler, to be sure that the busyIndicatorPanel has a width and a height
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
@Override
public void execute() {
busyIndicatorPanel.setSize("100%", "100%");
busyIndicatorPanel.add(busyIndicator, busyIndicatorPanel.getOffsetWidth() / 2, busyIndicatorPanel.getOffsetHeight() / 2);
}
});
List<RegattaAndRaceIdentifier> selectedRaces = raceSelectionProvider.getSelectedRaces();
if(!selectedRaces.isEmpty()) {
loadData(true);
}
timer.addTimeListener(this);
timeZoomProvider.addTimeZoomChangeListener(this);
}
protected void selectRace(final RaceIdentifier selectedRace) {
@@ -169,26 +134,14 @@ implements CompetitorSelectionChangeListener, RaceSelectionChangeListener, TimeL
chart.setClickEventHandler(new ChartClickEventHandler() {
@Override
public boolean onClick(ChartClickEvent chartClickEvent) {
if (ignoreTimeAdjustOnce) {
ignoreTimeAdjustOnce = false;
} else {
timer.setPlayMode(PlayModes.Replay);
timer.setTime(chartClickEvent.getXAxisValueAsLong());
}
AbstractChartPanel.this.onClick(chartClickEvent);
return true;
}
});
chart.setSelectionEventHandler(new ChartSelectionEventHandler() {
@Override
public boolean onSelection(ChartSelectionEvent chartSelectionEvent) {
try {
chartSelectionEvent.getXAxisMaxAsLong();
chartSelectionEvent.getXAxisMinAsLong();
ignoreTimeAdjustOnce = true;
} catch (Throwable t) {
// Redrawing, or the chart wouldn't rezoom
AbstractChartPanel.this.chart.redraw();
}
AbstractChartPanel.this.onSelectionChange(chartSelectionEvent);
return true;
}
});
@@ -256,7 +209,8 @@ implements CompetitorSelectionChangeListener, RaceSelectionChangeListener, TimeL
protected void loadData(boolean showBusyIndicator) {
if (needsDataLoading()) {
if (showBusyIndicator) {
setWidget(busyIndicatorPanel);
setWidget(chart);
chart.showLoading("Loading competitor data...");
}
if (chartData == null || chartData.getDetailType() != getDataToShow()) {
chartData = new MultiCompetitorRaceDataDTO(getDataToShow());
@@ -282,6 +236,7 @@ implements CompetitorSelectionChangeListener, RaceSelectionChangeListener, TimeL
public void onFailure(Throwable caught) {
errorReporter.reportError(getStringMessages().failedToLoadRaceData() + ": " + caught.toString(),
timer.getPlayMode() == PlayModes.Live);
chart.hideLoading();
}
@Override
@@ -297,7 +252,7 @@ implements CompetitorSelectionChangeListener, RaceSelectionChangeListener, TimeL
}
}
drawChartData();
setWidget(chart);
chart.hideLoading();
}
});
asyncActionsExecutor.execute(getCompetitorsRaceDataAction);
@@ -317,7 +272,6 @@ implements CompetitorSelectionChangeListener, RaceSelectionChangeListener, TimeL
@Override
public void addedToSelection(CompetitorDTO competitor) {
timeLineNeedsUpdate = true;
loadData(true);
}
@@ -400,9 +354,6 @@ implements CompetitorSelectionChangeListener, RaceSelectionChangeListener, TimeL
}
}
}
if (timeLineNeedsUpdate) {
forceTimeLineUpdate();
}
}
}
@@ -437,14 +388,6 @@ implements CompetitorSelectionChangeListener, RaceSelectionChangeListener, TimeL
return result;
}
private Series createTimeLineSeries() {
return chart
.createSeries()
.setType(Series.Type.LINE)
.setName(stringMessages.time())
.setPlotOptions(new LinePlotOptions().setShowInLegend(false).setHoverStateEnabled(false).setLineWidth(2));
}
private String getUnit() {
String unit = "";
switch (getDataToShow()) {
@@ -569,7 +512,6 @@ implements CompetitorSelectionChangeListener, RaceSelectionChangeListener, TimeL
public void onRaceSelectionChange(List<RegattaAndRaceIdentifier> selectedRaces) {
setChartData(null);
clearChart();
timeLineNeedsUpdate = true;
loadData(true);
}
@@ -613,48 +555,10 @@ implements CompetitorSelectionChangeListener, RaceSelectionChangeListener, TimeL
return new Pair<Boolean, Boolean>(everyPassingInRange, twoPassingsInRangeBeforeError);
}
/**
* Forces the chart to {@link #updateTimeLine(Date) update} the position and to {@link #ensureTimeLineIsVisible()
* ensure}, that the time line is visible.
*/
public void forceTimeLineUpdate() {
updateTimeLine(timer.getTime());
}
/**
* Updates the position of the time line for the given {@link Date}, if {@link #allowTimeAdjust} is <code>true</code>.<br />
* @param date Defines the x-Value of the line points
*/
private void updateTimeLine(Date date) {
if (allowTimeAdjust && chart != null) {
raceSelectionProvider.getSelectedRaces().get(0);
Long x = date.getTime();
Extremes extremes = chart.getYAxis(0).getExtremes();
Point[] points = new Point[2];
points[0] = new Point(x, extremes.getDataMin());
points[1] = new Point(x, extremes.getDataMax());
timeLineSeries.setPoints(points);
ensureTimeLineIsVisible();
timeLineNeedsUpdate = false;
}
}
/**
* Checks if the series of the chart contain the {@link #timeLineSeries}. If not, it is added to the chart.<br />
* Throws a NPE if the chart is <code>null</code>.
*/
private void ensureTimeLineIsVisible() {
if (!Arrays.asList(chart.getSeries()).contains(timeLineSeries)) {
chart.addSeries(timeLineSeries);
}
}
@Override
public void timeChanged(Date date) {
if (getChartData() != null) {
Date newestEvent = getChartData().getOldestDateOfNewestData();
updateTimeLine(date);
if ((newestEvent == null || (newestEvent.before(date) && (date.getTime() - newestEvent.getTime()) >= getStepSize()))) {
loadData(false);
}
@@ -7,6 +7,7 @@ import com.sap.sailing.gwt.ui.client.ErrorReporter;
import com.sap.sailing.gwt.ui.client.RaceSelectionProvider;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.client.TimeZoomProvider;
import com.sap.sailing.gwt.ui.client.Timer;
import com.sap.sailing.gwt.ui.shared.components.Component;
import com.sap.sailing.gwt.ui.shared.components.SettingsDialogComponent;
@@ -26,9 +27,9 @@ import com.sap.sailing.gwt.ui.shared.components.SettingsDialogComponent;
public class ChartPanel extends AbstractChartPanel<ChartSettings> implements Component<ChartSettings> {
public ChartPanel(SailingServiceAsync sailingService, AsyncActionsExecutor asyncActionsExecutor, CompetitorSelectionProvider competitorSelectionProvider,
RaceSelectionProvider raceSelectionProvider, Timer timer, DetailType dataToShow, StringMessages stringMessages,
RaceSelectionProvider raceSelectionProvider, Timer timer, TimeZoomProvider timeZoomProvider, DetailType dataToShow, StringMessages stringMessages,
ErrorReporter errorReporter, boolean compactChart, boolean allowTimeAdjust) {
super(sailingService, asyncActionsExecutor, competitorSelectionProvider, raceSelectionProvider, timer, stringMessages, errorReporter,
super(sailingService, asyncActionsExecutor, competitorSelectionProvider, raceSelectionProvider, timer, timeZoomProvider, stringMessages, errorReporter,
dataToShow, compactChart, allowTimeAdjust);
}
@@ -7,6 +7,7 @@ import com.sap.sailing.gwt.ui.client.ErrorReporter;
import com.sap.sailing.gwt.ui.client.RaceSelectionProvider;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.client.TimeZoomProvider;
import com.sap.sailing.gwt.ui.client.Timer;
import com.sap.sailing.gwt.ui.shared.components.Component;
import com.sap.sailing.gwt.ui.shared.components.SettingsDialogComponent;
@@ -26,10 +27,10 @@ import com.sap.sailing.gwt.ui.shared.components.SettingsDialogComponent;
public class MultiChartPanel extends AbstractChartPanel<MultiChartSettings> implements Component<MultiChartSettings> {
public MultiChartPanel(SailingServiceAsync sailingService, AsyncActionsExecutor asyncActionsExecutor,
CompetitorSelectionProvider competitorSelectionProvider, RaceSelectionProvider raceSelectionProvider,
Timer timer, final StringMessages stringMessages, ErrorReporter errorReporter, boolean compactChart,
Timer timer, TimeZoomProvider timeZoomProvider, final StringMessages stringMessages, ErrorReporter errorReporter, boolean compactChart,
boolean allowTimeAdjust) {
super(sailingService, asyncActionsExecutor, competitorSelectionProvider, raceSelectionProvider, timer, stringMessages, errorReporter,
/*show initially*/ DetailType.WINDWARD_DISTANCE_TO_OVERALL_LEADER, compactChart, allowTimeAdjust);
super(sailingService, asyncActionsExecutor, competitorSelectionProvider, raceSelectionProvider, timer, timeZoomProvider, stringMessages, errorReporter,
/*show initially*/ DetailType.DISTANCE_TRAVELED, compactChart, allowTimeAdjust);
}
@Override
@@ -0,0 +1,137 @@
package com.sap.sailing.gwt.ui.shared.charts;
import java.util.Date;
import java.util.Map;
import org.moxieapps.gwt.highcharts.client.Chart;
import org.moxieapps.gwt.highcharts.client.Legend;
import org.moxieapps.gwt.highcharts.client.events.ChartClickEvent;
import org.moxieapps.gwt.highcharts.client.events.ChartSelectionEvent;
import org.moxieapps.gwt.highcharts.client.events.SeriesCheckboxClickEvent;
import org.moxieapps.gwt.highcharts.client.events.SeriesCheckboxClickEventHandler;
import org.moxieapps.gwt.highcharts.client.events.SeriesLegendItemClickEvent;
import org.moxieapps.gwt.highcharts.client.events.SeriesLegendItemClickEventHandler;
import org.moxieapps.gwt.highcharts.client.plotOptions.PlotOptions;
import org.moxieapps.gwt.highcharts.client.plotOptions.SeriesPlotOptions;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.user.client.ui.SimplePanel;
import com.sap.sailing.domain.common.RaceIdentifier;
import com.sap.sailing.domain.common.impl.Util.Pair;
import com.sap.sailing.gwt.ui.actions.AsyncActionsExecutor;
import com.sap.sailing.gwt.ui.client.ErrorReporter;
import com.sap.sailing.gwt.ui.client.RaceSelectionChangeListener;
import com.sap.sailing.gwt.ui.client.RaceTimesCalculationUtil;
import com.sap.sailing.gwt.ui.client.RaceTimesInfoProviderListener;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.client.TimeListener;
import com.sap.sailing.gwt.ui.client.TimeZoomChangeListener;
import com.sap.sailing.gwt.ui.client.TimeZoomProvider;
import com.sap.sailing.gwt.ui.client.Timer;
import com.sap.sailing.gwt.ui.client.Timer.PlayModes;
import com.sap.sailing.gwt.ui.shared.RaceTimesInfoDTO;
public abstract class RaceChart extends SimplePanel implements RaceTimesInfoProviderListener, RaceSelectionChangeListener,
TimeListener, TimeZoomChangeListener {
protected Chart chart;
protected final Timer timer;
protected final TimeZoomProvider timeZoomProvider;
protected Date minTimepoint;
protected Date maxTimepoint;
protected boolean ignoreClickOnce;
protected RaceIdentifier selectedRaceIdentifier;
protected RaceTimesInfoDTO lastRaceTimesInfo;
protected final DateTimeFormat dateFormat = DateTimeFormat.getFormat("HH:mm:ss");
protected final StringMessages stringMessages;
protected final ErrorReporter errorReporter;
protected final AsyncActionsExecutor asyncActionsExecutor;
protected final SailingServiceAsync sailingService;
public RaceChart(SailingServiceAsync sailingService, Timer timer, TimeZoomProvider timeZoomProvider, final StringMessages stringMessages,
AsyncActionsExecutor asyncActionsExecutor, ErrorReporter errorReporter) {
this.sailingService = sailingService;
this.timer = timer;
this.timeZoomProvider = timeZoomProvider;
this.stringMessages = stringMessages;
this.asyncActionsExecutor = asyncActionsExecutor;
this.errorReporter = errorReporter;
}
@Override
public void raceTimesInfosReceived(Map<RaceIdentifier, RaceTimesInfoDTO> raceTimesInfos) {
this.lastRaceTimesInfo = raceTimesInfos.get(selectedRaceIdentifier);
Pair<Date, Date> raceMinMax = RaceTimesCalculationUtil.caluclateRaceMinMax(timer, this.lastRaceTimesInfo);
this.minTimepoint = raceMinMax.getA();
this.maxTimepoint = raceMinMax.getB();
}
protected void onSelectionChange(ChartSelectionEvent chartSelectionEvent) {
try {
long xAxisMin = chartSelectionEvent.getXAxisMinAsLong();
long xAxisMax = chartSelectionEvent.getXAxisMaxAsLong();
timeZoomProvider.setTimeZoom(new Date(xAxisMin), new Date(xAxisMax), this);
ignoreClickOnce = true;
} catch (Throwable t) {
timeZoomProvider.resetTimeZoom(this);
//Redrawing, or the chart wouldn't rezoom
chart.redraw();
}
}
protected void onClick(ChartClickEvent chartClickEvent) {
if (ignoreClickOnce) {
ignoreClickOnce = false;
} else {
timer.setPlayMode(PlayModes.Replay);
timer.setTime(chartClickEvent.getXAxisValueAsLong());
}
}
public void onTimeZoom(Date zoomStartTimepoint, Date zoomEndTimepoint) {
chart.getXAxis().setExtremes(zoomStartTimepoint.getTime(), zoomEndTimepoint.getTime(), true, true);
// Probably there is a function for this in a newer version of highcharts: http://jsfiddle.net/mqz3N/1071/
// chart.showResetZoom();
}
public void onTimeZoomReset() {
// chart.getXAxis().setExtremes(minTimepoint.getTime(), maxTimepoint.getTime(), true, true);
}
/**
* When using this method to enable the use of checkboxes only for hiding / showing a series, callers need to ensure
* that all series have {@link PlotOptions#setSelected(boolean)} set to <code>true</code> for all series that are
* added to the chart and hence visible. Otherwise, the checkbox won't initially be in sync with the series'
* visibility state.
*/
protected void useCheckboxesToShowAndHide(final Chart chart) {
chart.setLegend(new Legend().setEnabled(true).setBorderWidth(0).setSymbolPadding(20)); // make room for checkbox
chart.setSeriesPlotOptions(new SeriesPlotOptions().setSeriesCheckboxClickEventHandler(new SeriesCheckboxClickEventHandler() {
@Override
public boolean onClick(SeriesCheckboxClickEvent seriesCheckboxClickEvent) {
if (seriesCheckboxClickEvent.isChecked()) {
chart.getSeries(seriesCheckboxClickEvent.getSeriesId()).show();
} else {
chart.getSeries(seriesCheckboxClickEvent.getSeriesId()).hide();
}
return false; // don't toggle the select state of the series
}
}).setShowCheckbox(true).
setSeriesLegendItemClickEventHandler(new SeriesLegendItemClickEventHandler() {
@Override
public boolean onClick(SeriesLegendItemClickEvent seriesLegendItemClickEvent) {
// disable toggling visibility by clicking the legend item; force user to use checkbox instead
return false;
}
}));
}
}
@@ -30,7 +30,6 @@ import org.moxieapps.gwt.highcharts.client.labels.YAxisLabels;
import org.moxieapps.gwt.highcharts.client.plotOptions.LinePlotOptions;
import org.moxieapps.gwt.highcharts.client.plotOptions.Marker;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.i18n.client.NumberFormat;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.RequiresResize;
@@ -39,34 +38,27 @@ import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.domain.common.RaceIdentifier;
import com.sap.sailing.domain.common.WindSource;
import com.sap.sailing.domain.common.WindSourceType;
import com.sap.sailing.domain.common.impl.Util.Pair;
import com.sap.sailing.gwt.ui.actions.AsyncActionsExecutor;
import com.sap.sailing.gwt.ui.actions.GetWindInfoAction;
import com.sap.sailing.gwt.ui.client.ColorMap;
import com.sap.sailing.gwt.ui.client.ErrorReporter;
import com.sap.sailing.gwt.ui.client.RaceSelectionChangeListener;
import com.sap.sailing.gwt.ui.client.RaceSelectionProvider;
import com.sap.sailing.gwt.ui.client.RaceTimesCalculationUtil;
import com.sap.sailing.gwt.ui.client.RaceTimesInfoProviderListener;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.client.TimeListener;
import com.sap.sailing.gwt.ui.client.TimeZoomProvider;
import com.sap.sailing.gwt.ui.client.Timer;
import com.sap.sailing.gwt.ui.client.Timer.PlayModes;
import com.sap.sailing.gwt.ui.client.WindSourceTypeFormatter;
import com.sap.sailing.gwt.ui.shared.RaceTimesInfoDTO;
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.shared.components.Component;
import com.sap.sailing.gwt.ui.shared.components.SettingsDialogComponent;
public class WindChart extends SimpleChartPanel implements Component<WindChartSettings>, RaceSelectionChangeListener,
RaceTimesInfoProviderListener, TimeListener, RequiresResize {
public class WindChart extends RaceChart implements Component<WindChartSettings>, RequiresResize {
public static final long DEFAULT_RESOLUTION_IN_MILLISECONDS = 10000;
private static final int LINE_WIDTH = 1;
private final StringMessages stringMessages;
private final Set<WindSourceType> windSourceTypesToDisplay;
private long resolutionInMilliseconds;
private boolean showWindSpeedSeries;
@@ -78,26 +70,10 @@ public class WindChart extends SimpleChartPanel implements Component<WindChartSe
private final Map<WindSource, Series> windSourceDirectionSeries;
private final Map<WindSource, Series> windSourceSpeedSeries;
private final ErrorReporter errorReporter;
private final AsyncActionsExecutor asyncActionsExecutor;
private final SailingServiceAsync sailingService;
private final Chart chart;
private boolean ignoreClickOnce;
private final DateTimeFormat dateFormat = DateTimeFormat.getFormat("HH:mm:ss");
private Long timeOfEarliestRequestInMillis;
private Long timeOfLatestRequestInMillis;
private Date minTimepoint;
private Date maxTimepoint;
private Date minSelectedTimepoint;
private Date maxSelectedTimepoint;
private RaceIdentifier selectedRaceIdentifier;
private RaceTimesInfoDTO lastRaceTimesInfo;
private final ColorMap<WindSource> colorMap;
private boolean isZoomed = false;
/**
* @param raceSelectionProvider
@@ -106,13 +82,9 @@ public class WindChart extends SimpleChartPanel implements Component<WindChartSe
* server and displayed in this chart. If no race is selected, the chart is cleared.
*/
public WindChart(SailingServiceAsync sailingService, RaceSelectionProvider raceSelectionProvider, Timer timer,
WindChartSettings settings, final StringMessages stringMessages, AsyncActionsExecutor asyncActionsExecutor,
ErrorReporter errorReporter, boolean compactChart) {
super(timer);
this.sailingService = sailingService;
this.asyncActionsExecutor = asyncActionsExecutor;
this.stringMessages = stringMessages;
this.errorReporter = errorReporter;
TimeZoomProvider timeZoomProvider, WindChartSettings settings, final StringMessages stringMessages,
AsyncActionsExecutor asyncActionsExecutor, ErrorReporter errorReporter, boolean compactChart) {
super(sailingService, timer, timeZoomProvider, stringMessages, asyncActionsExecutor, errorReporter);
this.windSourceDirectionSeries = new HashMap<WindSource, Series>();
this.windSourceSpeedSeries = new HashMap<WindSource, Series>();
this.colorMap = new ColorMap<WindSource>();
@@ -160,12 +132,7 @@ public class WindChart extends SimpleChartPanel implements Component<WindChartSe
chart.setClickEventHandler(new ChartClickEventHandler() {
@Override
public boolean onClick(ChartClickEvent chartClickEvent) {
if (ignoreClickOnce) {
ignoreClickOnce = false;
} else {
WindChart.this.timer.setPlayMode(PlayModes.Replay);
WindChart.this.timer.setTime(chartClickEvent.getXAxisValueAsLong());
}
WindChart.this.onClick(chartClickEvent);
return true;
}
});
@@ -173,20 +140,7 @@ public class WindChart extends SimpleChartPanel implements Component<WindChartSe
chart.setSelectionEventHandler(new ChartSelectionEventHandler() {
@Override
public boolean onSelection(ChartSelectionEvent chartSelectionEvent) {
try {
long xAxisMin = chartSelectionEvent.getXAxisMinAsLong();
long xAxisMax = chartSelectionEvent.getXAxisMaxAsLong();
WindChart.this.minSelectedTimepoint = new Date(xAxisMin);
WindChart.this.maxSelectedTimepoint = new Date(xAxisMax);
WindChart.this.isZoomed = true;
ignoreClickOnce = true;
} catch (Throwable t) {
WindChart.this.minSelectedTimepoint = null;
WindChart.this.maxSelectedTimepoint = null;
WindChart.this.isZoomed = false;
//Redrawing, or the chart wouldn't rezoom
chart.redraw();
}
WindChart.this.onSelectionChange(chartSelectionEvent);
return true;
}
});
@@ -222,6 +176,7 @@ public class WindChart extends SimpleChartPanel implements Component<WindChartSe
}
showVisibleSeries();
timer.addTimeListener(this);
timeZoomProvider.addTimeZoomChangeListener(this);
}
@Override
@@ -486,6 +441,8 @@ public class WindChart extends SimpleChartPanel implements Component<WindChartSe
xAxis.setMax(maxTimepoint.getTime());
xAxis.setStartOnTick(false);
xAxis.setEndOnTick(false);
long tickInterval = (maxTimepoint.getTime() - minTimepoint.getTime()) / 10;
xAxis.setTickInterval(tickInterval);
updateStripChartSeries(result, append);
} else {
@@ -522,16 +479,6 @@ public class WindChart extends SimpleChartPanel implements Component<WindChartSe
}
}
@Override
public void raceTimesInfosReceived(Map<RaceIdentifier, RaceTimesInfoDTO> raceTimesInfos) {
this.lastRaceTimesInfo = raceTimesInfos.get(selectedRaceIdentifier);
Pair<Date, Date> raceMinMax = RaceTimesCalculationUtil.caluclateRaceMinMax(timer, this.lastRaceTimesInfo);
this.minTimepoint = raceMinMax.getA();
this.maxTimepoint = raceMinMax.getB();
}
/**
* If in live mode, fetches what's missing since the last fix and <code>date</code>. If nothing has been loaded yet,
* loads from the beginning up to <code>date</code>. If in replay mode, checks if anything has been loaded at all. If not,
@@ -566,16 +513,4 @@ public class WindChart extends SimpleChartPanel implements Component<WindChartSe
return isVisible();
}
public Date getMinSelectedTimepoint() {
return minSelectedTimepoint;
}
public Date getMaxSelectedTimepoint() {
return maxSelectedTimepoint;
}
public boolean isZoomed() {
return isZoomed;
}
}