package com.vaadin.addon.timeline.gwt.client;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.AbsolutePanel;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.addon.timeline.gwt.canvas.client.Canvas;
/**
* VTimelineDisplay
*
* @author John Ahlroos / IT Mill Oy Ltd
*
*/
public class VTimelineDisplay extends Widget implements VMouseMoveListener,
VMouseClickListener, VDataListener, VMouseScrollListener {
private static final String CLASSNAME_BOTTOMBAR = VTimelineWidget.DISPLAY_CLASSNAME+"-bottombar";
private static final String CLASSNAME_CANVAS = VTimelineWidget.DISPLAY_CLASSNAME+"-canvas";
private static final String CLASSNAME_CANVASDRAG = CLASSNAME_CANVAS+"-drag";
private static final String CLASSNAME_MARKER = VTimelineWidget.CLASSNAME+"-marker";
private static final String CLASSNAME_MARKERTOOLTIP = CLASSNAME_MARKER+"-tooltip";
private static final String CLASSNAME_LOADINGCURTAIN = VTimelineWidget.DISPLAY_CLASSNAME+"-curtain";
private static final String CLASSNAME_EVENT = VTimelineWidget.CLASSNAME+"-event";
private static final String CLASSNAME_SCALEVALUE = VTimelineWidget.DISPLAY_CLASSNAME+"-vscale";
private static final String CLASSNAME_SCALEVALUEDRAG = CLASSNAME_SCALEVALUE + "-drag";
private static final String CLASSNAME_SCALEDATE = VTimelineWidget.DISPLAY_CLASSNAME+"-hscale";
private static final String CLASSNAME_PRELOADER = VTimelineWidget.DISPLAY_CLASSNAME+"-preloader";
private static final String CLASSNAME_DOT = VTimelineWidget.DISPLAY_CLASSNAME+"-dot";
private static final String CLASSNAME_BAR = VTimelineWidget.DISPLAY_CLASSNAME+"-bar";
public static final Long HOUR = 3600000L;
public static final Long DAY = 86400000L;
public static final Long WEEK = 604800000L;
public static final Long MONTH = 2629743830L;
public static final Long YEAR = 31556926000L;
private final List<HTML> dots = new ArrayList<HTML>();
private final List<HTML> bars = new ArrayList<HTML>();
private final VTimelineWidget widget;
private final Element browserRoot;
private final AbsolutePanel displayComponentPanel;
private final Canvas canvas;
private final VCanvasPlotter plotter;
private final HTML bottomBar;
private final Map<Integer, List<Float>> currentValues = new HashMap<Integer, List<Float>>();
private final Map<Integer, List<Float>> currentNormalizedValues = new HashMap<Integer, List<Float>>();
private final Map<Integer, List<Date>> currentDates = new HashMap<Integer, List<Date>>();
private final Map<Integer, Float> currentMax = new HashMap<Integer, Float>();
private final Map<Integer, Float> currentMin = new HashMap<Integer, Float>();
private final Map<Integer, List<Float>> currentXCoordinates = new HashMap<Integer, List<Float>>();
private final Map<Integer, List<Float>> currentYCoordinates = new HashMap<Integer, List<Float>>();
private final Set<String> currentEvents = new HashSet<String>();
private final Map<Button, List<Integer>> currentEventMap = new HashMap<Button, List<Integer>>();
private final Map<Button, List<Date>> currentEventDates = new HashMap<Button, List<Date>>();
private final Map<String, Label> markerMap = new HashMap<String, Label>();
private final Map<String, FlexTable> markerTooltipMap = new HashMap<String, FlexTable>();
private final List<Button> events = new ArrayList<Button>();
private final List<Integer> eventCoordinates = new ArrayList<Integer>();
private float currentTotalMin = 0f;
private float currentTotalMax = 0f;
// The selected date range
private Date currentStartDate = null;
private Date currentEndDate = null;
private Date previousStartDate = null;
private Date previousEndDate = null;
// The date range returned from server when
// the above was requested
private Date currentRealStartDate = null;
private Date currentRealEndDate = null;
// Request mapping
private final Map<Long, Integer> requestGraphMap = new HashMap<Long, Integer>();
// Mouse actions
private boolean mouseIsDown = false;
private int mouseDownX = 0;
// States
private boolean waitingForData = false;
private boolean enabled = true;
private PlotMode currentMode;
private boolean forcePlot = false;
private float currentZeroCoordinate = 0f;
private float currentBarWidth = 0f;
// Counters
private int graphDataRecievedCounter = 0;
private long plotCounter = 0L;
// Dragging
private Date currentStartDragDate = null;
private Date currentEndDragDate = null;
// Vertical scale
private Float verticalScaleMin = null;
private Float verticalScaleMax = null;
// Curtains
private final HTML loadingCurtain;
private final HTML disabledCurtain;
// Scale components lists
private final List<Label> horizontalScaleComponents = new ArrayList<Label>();
private final List<Label> verticalScaleComponents = new ArrayList<Label>();
// Error and loading messages
private final Label noDataLabel = new Label("No data source.");
private HTML preloadingStatus = new HTML();
// Graph formatting
private boolean useLineCaps = false;
private double lineGraphThickness = 1.0;
private String gridColor = "rgb(200,200,200)";
public enum PlotMode{
LINE, SCATTER, BAR
}
public VTimelineDisplay(VTimelineWidget w) {
widget = w;
currentMode = PlotMode.LINE;
browserRoot = DOM.createDiv();
setElement(browserRoot);
setStyleName(VTimelineWidget.DISPLAY_CLASSNAME);
// Add the components
displayComponentPanel = new AbsolutePanel();
browserRoot.appendChild(displayComponentPanel.getElement());
DOM.setStyleAttribute(displayComponentPanel.getElement(), "position", "relative");
DOM.setStyleAttribute(displayComponentPanel.getElement(), "zIndex",
"999999");
// Add the canvas
canvas = new Canvas(100, 100);
canvas.setStyleName(CLASSNAME_CANVAS);
displayComponentPanel.add(canvas,0,0);
// Add the plotter
plotter = new VCanvasPlotter(canvas);
// Create the loading indicator
loadingCurtain = new HTML("");
loadingCurtain.setStyleName("v-app-loading");
loadingCurtain.addStyleName(CLASSNAME_LOADINGCURTAIN);
loadingCurtain.setWidth("100%");
loadingCurtain.setHeight("100%");
displayComponentPanel.add(loadingCurtain);
// Create the bottom bar
bottomBar = new HTML();
bottomBar.setWidth("100%");
bottomBar.setStyleName(CLASSNAME_BOTTOMBAR);
displayComponentPanel.add(bottomBar);
// Add the preloading indicator
if(widget.usePreloading()){
preloadingStatus = new HTML("0%");
preloadingStatus.setStyleName(CLASSNAME_PRELOADER);
displayComponentPanel.add(preloadingStatus, 10, 10);
}
// Add no data source label
noDataLabel.setVisible(false);
displayComponentPanel.add(noDataLabel, 10, 10);
// Create the disabled curtain
disabledCurtain = new HTML("");
disabledCurtain.setVisible(false);
disabledCurtain.setStyleName(CLASSNAME_LOADINGCURTAIN);
disabledCurtain.setWidth("100%");
disabledCurtain.setHeight("100%");
displayComponentPanel.add(disabledCurtain);
}
/**
* Resets the display cache
*/
public void resetDisplayCache(){
currentValues.clear();
currentDates.clear();
currentMin.clear();
currentMax.clear();
currentNormalizedValues.clear();
currentTotalMin = 99999f;
currentTotalMax = -99999;
currentXCoordinates.clear();
currentYCoordinates.clear();
}
/**
* Add a value label
* @param y
* The y-coordinate
* @param val
* The value
* @param diff
* The time difference
*/
private void addValueLabel(int y, float val, int diff) {
val = Math.round(val*10f)/10f;
String str = String.valueOf(val);
Label lbl = new Label(str);
lbl.setStyleName(CLASSNAME_SCALEVALUE);
displayComponentPanel.add(lbl,0, y);
verticalScaleComponents.add(lbl);
}
/**
* <p>
* Plots the horizontal scale using day resolution.
* </p>
* Deprecation warnings removed since Date class is used because of GWT
* missing Calendar.
*
* @param startTime
* The time when the scale start
* @param endTime
* The time when the scale ends
* @param xUnit
* The unit of the x-coordinate in canvas space
* @param paddingLeft
* The left padding
*/
@SuppressWarnings("deprecation")
private void plotHorizontalScaleDay(long startTime, long endTime,
float xUnit,
float paddingLeft) {
Date currentStartDate = new Date(startTime);
Date currentEndDate = new Date(endTime);
// Find closest monday to the start date
int startDay = 1 - currentStartDate.getDay();
float width = (2 * HOUR * xUnit);
Date monday;
if (startDay > 0) {
monday = new Date(startTime - DAY);
} else if (startDay == 0) {
monday = new Date(startTime);
} else {
monday = new Date(startTime + Long.valueOf(startDay) * DAY);
}
monday.setHours(0);
monday.setMinutes(0);
monday.setSeconds(0);
Long timeFromStart = 0L;
if (gridColor != null) {
canvas.setStrokeStyle(gridColor);
canvas.setLineWidth(0.8);
canvas.beginPath();
}
DateTimeFormat formatter = DateTimeFormat.getFormat("MMM d y");
DateTimeFormat formatter2 = DateTimeFormat.getFormat("hh:mm a");
if (monday.before(currentEndDate)) {
while (monday.before(currentEndDate)) {
Label lbl = new Label();
lbl.setStyleName(CLASSNAME_SCALEDATE);
lbl.setWidth(width + "px");
if (monday.getHours() == 0) {
lbl.setText(formatter.format(monday));
} else {
lbl.setText(formatter2.format(monday));
}
timeFromStart = monday.getTime() - currentStartDate.getTime();
float x = timeFromStart * xUnit + paddingLeft;
if (gridColor != null) {
canvas.moveTo(x, 0);
canvas.lineTo(x, canvas.getHeight());
}
displayComponentPanel.add(lbl, (int) x, displayComponentPanel
.getOffsetHeight() - 15);
horizontalScaleComponents.add(lbl);
monday = new Date(monday.getTime() + 2 * HOUR);
}
} else {
while (monday.after(currentStartDate)) {
Label lbl = new Label();
lbl.setStyleName(CLASSNAME_SCALEDATE);
lbl.setWidth(width + "px");
if (monday.getHours() == 0) {
lbl.setText(formatter.format(monday));
} else {
lbl.setText(formatter2.format(monday));
}
timeFromStart = monday.getTime() - currentStartDate.getTime();
float x = timeFromStart * xUnit + paddingLeft;
if (gridColor != null) {
canvas.moveTo(x, 0);
canvas.lineTo(x, canvas.getHeight());
}
displayComponentPanel.add(lbl, (int) x, displayComponentPanel
.getOffsetHeight() - 15);
horizontalScaleComponents.add(lbl);
monday = new Date(monday.getTime() - 2 * HOUR);
}
}
if (gridColor != null) {
canvas.closePath();
canvas.stroke();
}
}
/**
* <p>
* Plots the horizontal scale using a 3 day resolution.
* </p>
* Deprecation warnings removed since Date class is used because of GWT
* missing Calendar.
*
* @param startTime
* The time when the scale start
* @param endTime
* The time when the scale ends
* @param xUnit
* The unit of the x-coordinate in canvas space
* @param paddingLeft
* The left padding
*/
@SuppressWarnings("deprecation")
private void plotHorizontalScale3Day(long startTime, long endTime,
float xUnit,
float paddingLeft) {
Date currentStartDate = new Date(startTime);
Date currentEndDate = new Date(endTime);
// Find closest monday to the start date
int startDay = 1 - currentStartDate.getDay();
float width = (6 * HOUR * xUnit);
Date monday;
if (startDay > 0) {
monday = new Date(currentStartDate.getTime() - DAY);
} else if (startDay == 0) {
monday = new Date(startTime);
} else {
monday = new Date(currentStartDate.getTime() + startDay * DAY);
}
monday.setHours(0);
monday.setMinutes(0);
monday.setSeconds(0);
Long timeFromStart = 0L;
if (gridColor != null) {
canvas.setStrokeStyle(gridColor);
canvas.setLineWidth(0.8);
canvas.beginPath();
}
DateTimeFormat formatter = DateTimeFormat.getFormat("MMM d y");
DateTimeFormat formatter2 = DateTimeFormat.getFormat("hh:mm a");
if (monday.before(currentEndDate)) {
while (monday.before(currentEndDate)) {
Label lbl = new Label();
lbl.setStyleName(CLASSNAME_SCALEDATE);
lbl.setWidth(width + "px");
if (monday.getHours() == 0) {
lbl.setText(formatter.format(monday));
} else {
lbl.setText(formatter2.format(monday));
}
timeFromStart = monday.getTime() - currentStartDate.getTime();
float x = timeFromStart * xUnit + paddingLeft;
if (gridColor != null) {
canvas.moveTo(x, 0);
canvas.lineTo(x, canvas.getHeight());
}
displayComponentPanel.add(lbl, (int) x, displayComponentPanel
.getOffsetHeight() - 15);
horizontalScaleComponents.add(lbl);
monday = new Date(monday.getTime() + 6 * HOUR);
}
} else {
while (monday.after(currentStartDate)) {
Label lbl = new Label();
lbl.setStyleName(CLASSNAME_SCALEDATE);
lbl.setWidth(width + "px");
if (monday.getHours() == 0) {
lbl.setText(formatter.format(monday));
} else {
lbl.setText(formatter2.format(monday));
}
timeFromStart = monday.getTime() - currentStartDate.getTime();
float x = timeFromStart * xUnit + paddingLeft;
if (gridColor != null) {
canvas.moveTo(x, 0);
canvas.lineTo(x, canvas.getHeight());
}
// bottomBar.add(lbl, (int)x, 0);
displayComponentPanel.add(lbl, (int) x, displayComponentPanel
.getOffsetHeight() - 15);
horizontalScaleComponents.add(lbl);
monday = new Date(monday.getTime() - 6 * HOUR);
}
}
if (gridColor != null) {
canvas.closePath();
canvas.stroke();
}
}
/**
* <p>
* Plots the horizontal scale using a week resolution.
* </p>
* Deprecation warnings removed since Date class is used because of GWT
* missing Calendar.
*
* @param startTime
* The time when the scale start
* @param endTime
* The time when the scale ends
* @param xUnit
* The unit of the x-coordinate in canvas space
* @param paddingLeft
* The left padding
*/
@SuppressWarnings("deprecation")
private void plotHorizontalScaleWeek(long startTime, long endTime,
float xUnit, float paddingLeft) {
Date currentStartDate = new Date(startTime);
Date currentEndDate = new Date(endTime);
// Find closest monday to the start date
int startDay = 1 - currentStartDate.getDay();
Date monday;
if (startDay > 0) {
monday = new Date(currentStartDate.getTime() + DAY);
} else if (startDay == 0) {
monday = new Date(currentStartDate.getTime());
} else {
monday = new Date(currentStartDate.getTime() + startDay * DAY);
}
monday.setHours(0);
monday.setMinutes(0);
monday.setSeconds(0);
long timeFromStart = 0L;
Float width = DAY * xUnit;
if (gridColor != null) {
canvas.setStrokeStyle(gridColor);
canvas.setLineWidth(0.8);
canvas.beginPath();
}
DateTimeFormat formatter = DateTimeFormat.getFormat("MMM d y");
while (monday.before(currentEndDate)) {
Label lbl = new Label();
lbl.setWidth(width + "px");
lbl.setText(formatter.format(monday));
lbl.setStyleName(CLASSNAME_SCALEDATE);
timeFromStart = monday.getTime() - currentStartDate.getTime();
float x = timeFromStart * xUnit + paddingLeft;
canvas.moveTo(x, 0);
canvas.lineTo(x, canvas.getHeight());
// bottomBar.add(lbl, (int)x, 0);
displayComponentPanel.add(lbl, (int) x, displayComponentPanel
.getOffsetHeight() - 15);
horizontalScaleComponents.add(lbl);
monday = new Date(monday.getTime() + DAY);
}
if (gridColor != null) {
canvas.closePath();
canvas.stroke();
}
}
/**
* <p>
* Plots the horizontal scale using a 2 week resolution.
* </p>
* Deprecation warnings removed since Date class is used because of GWT
* missing Calendar.
*
* @param startTime
* The time when the scale start
* @param endTime
* The time when the scale ends
* @param xUnit
* The unit of the x-coordinate in canvas space
* @param paddingLeft
* The left padding
*/
@SuppressWarnings("deprecation")
private void plotHorizontalScale2Weeks(long startTime, long endTime,
float xUnit, float paddingLeft) {
Date currentStartDate = new Date(startTime);
Date currentEndDate = new Date(endTime);
// Find closest monday to the start date
int startDay = 1 - currentStartDate.getDay();
float width = 3 * DAY;
Date monday;
if (startDay > 0) {
monday = new Date(currentStartDate.getTime() + DAY);
} else if (startDay == 0) {
monday = new Date(currentStartDate.getTime());
} else {
monday = new Date(currentStartDate.getTime() + startDay * DAY);
}
monday.setHours(0);
monday.setMinutes(0);
monday.setSeconds(0);
Long timeFromStart = 0L;
if (gridColor != null) {
canvas.setStrokeStyle(gridColor);
canvas.setLineWidth(0.8);
canvas.beginPath();
}
DateTimeFormat formatter = DateTimeFormat.getFormat("MMM d y");
while (monday.before(currentEndDate)) {
Label lbl = new Label();
lbl.setWidth(width + "px");
lbl.setStyleName(CLASSNAME_SCALEDATE);
lbl.setText(formatter.format(monday));
timeFromStart = monday.getTime() - currentStartDate.getTime();
float x = timeFromStart * xUnit + paddingLeft;
canvas.moveTo(x, 0);
canvas.lineTo(x, canvas.getHeight());
displayComponentPanel.add(lbl, (int) x, displayComponentPanel
.getOffsetHeight() - 15);
horizontalScaleComponents.add(lbl);
monday = new Date(monday.getTime() + 3 * DAY);
}
if (gridColor != null) {
canvas.closePath();
canvas.stroke();
}
}
/**
* <p>
* Plots the horizontal scale using a 2 month resolution.
* </p>
* Deprecation warnings removed since Date class is used because of GWT
* missing Calendar.
*
* @param startTime
* The time when the scale start
* @param endTime
* The time when the scale ends
* @param xUnit
* The unit of the x-coordinate in canvas space
* @param paddingLeft
* The left padding
*/
@SuppressWarnings("deprecation")
private void plotHorizontalScale2Months(long startTime, long endTime,
float xUnit, float paddingLeft) {
Date currentStartDate = new Date(startTime);
Date currentEndDate = new Date(endTime);
// Find closest monday to the start date
int startDay = 1 - currentStartDate.getDay();
Date monday;
if (startDay > 0) {
monday = new Date(currentStartDate.getTime() + DAY);
} else if (startDay == 0) {
monday = new Date(currentStartDate.getTime());
} else {
monday = new Date(currentStartDate.getTime() + startDay * DAY);
}
monday.setHours(0);
monday.setMinutes(0);
monday.setSeconds(0);
Long timeFromStart = 0L;
Float width = WEEK * xUnit;
if (gridColor != null) {
canvas.setStrokeStyle(gridColor);
canvas.setLineWidth(0.8);
canvas.beginPath();
}
int canvasHeight = canvas.getHeight();
while (monday.before(currentEndDate)) {
Label lbl = new Label();
lbl.setStyleName(CLASSNAME_SCALEDATE);
lbl.setWidth(width + "px");
int week = VTimelineWidget.getWeek(monday);
lbl.setText("Week " + week);
timeFromStart = monday.getTime() - currentStartDate.getTime();
float x = timeFromStart * xUnit + paddingLeft;
if (gridColor != null) {
canvas.moveTo(x, 0);
canvas.lineTo(x, canvasHeight);
}
displayComponentPanel.add(lbl, (int) x, displayComponentPanel
.getOffsetHeight() - 15);
horizontalScaleComponents.add(lbl);
monday = new Date(monday.getTime() + WEEK);
}
if (gridColor != null) {
canvas.closePath();
canvas.stroke();
}
}
/**
* <p>
* Plots the horizontal scale using a year resolution.
* </p>
* Deprecation warnings removed since Date class is used because of GWT
* missing Calendar.
*
* @param startTime
* The time when the scale start
* @param endTime
* The time when the scale ends
* @param xUnit
* The unit of the x-coordinate in canvas space
* @param paddingLeft
* The left padding
*/
@SuppressWarnings("deprecation")
private void plotHorizontalScaleYear(long startTime, long endTime,
float xUnit, float paddingLeft) {
Date currentStartDate = new Date(startTime);
Date currentEndDate = new Date(endTime);
// Get the first day of the month
Date first = new Date(currentStartDate.getYear(), currentStartDate
.getMonth(), 1);
Long timeFromStart = 0L;
if (gridColor != null) {
canvas.setStrokeStyle(gridColor);
canvas.setLineWidth(0.8);
canvas.beginPath();
}
DateTimeFormat formatter = DateTimeFormat.getFormat("MMM y");
int currentMonth = currentStartDate.getMonth();
int currentYear = currentStartDate.getYear();
Float width = VTimelineWidget.getDaysInMonth(currentMonth, currentYear)
* DAY * xUnit;
while (first.before(currentEndDate)) {
Label lbl = new Label();
lbl.setStyleName(CLASSNAME_SCALEDATE);
lbl.setWidth(width + "px");
lbl.setText(formatter.format(first));
timeFromStart = first.getTime() - currentStartDate.getTime();
float x = timeFromStart * xUnit + paddingLeft;
if (gridColor != null) {
canvas.moveTo(x, 0);
canvas.lineTo(x, canvas.getHeight());
}
displayComponentPanel.add(lbl, (int) x, displayComponentPanel
.getOffsetHeight() - 15);
horizontalScaleComponents.add(lbl);
// Calculate the next months values
first = new Date(first.getTime()
+ VTimelineWidget.getDaysInMonth(currentMonth, currentYear)
* DAY);
currentMonth = first.getMonth();
currentYear = first.getYear();
width = VTimelineWidget.getDaysInMonth(currentMonth, currentYear)
* DAY * xUnit;
}
if (gridColor != null) {
canvas.closePath();
canvas.stroke();
}
}
/**
* <p>
* Plots the horizontal scale using above year resolution.
* </p>
* Deprecation warnings removed since Date class is used because of GWT
* missing Calendar.
*
* @param startTime
* The time when the scale start
* @param endTime
* The time when the scale ends
* @param xUnit
* The unit of the x-coordinate in canvas space
* @param paddingLeft
* The left padding
*/
@SuppressWarnings("deprecation")
private void plotHorizontalScaleOther(long startTime, long endTime,
float xUnit, float paddingLeft) {
Date currentStartDate = new Date(startTime);
Date currentEndDate = new Date(endTime);
// Get the first day of the year
Date first = new Date(currentStartDate.getYear(), 0, 1);
Float width = YEAR * xUnit;
Long timeFromStart = 0L;
if (gridColor != null) {
canvas.setStrokeStyle(gridColor);
canvas.setLineWidth(0.8);
canvas.beginPath();
}
DateTimeFormat formatter = DateTimeFormat.getFormat("yyyy");
while (first.before(currentEndDate)) {
Label lbl = new Label();
lbl.setWidth(width + "px");
lbl.setText(formatter.format(first));
lbl.setStyleName(CLASSNAME_SCALEDATE);
timeFromStart = first.getTime() - currentStartDate.getTime();
float x = timeFromStart * xUnit + paddingLeft;
canvas.moveTo(x, 0);
canvas.lineTo(x, canvas.getHeight());
displayComponentPanel.add(lbl, (int) x, displayComponentPanel
.getOffsetHeight() - 15);
horizontalScaleComponents.add(lbl);
first = new Date(first.getYear() + 1, 0, 1);
}
if (gridColor != null) {
canvas.closePath();
canvas.stroke();
}
}
/**
* Plots the horizontal scale
*/
private void plotHorizontalScale(Float xUnit, Long timeDiff,
Long startTime, Long endTime, float paddingLeft, float paddingRight) {
// If one of the needed values is not given then abort
if (xUnit == null || timeDiff == null || startTime == null
|| endTime == null) {
return;
}
for (Label lbl : horizontalScaleComponents) {
displayComponentPanel.remove(lbl);
}
horizontalScaleComponents.clear();
// Selection is less than a day
if (timeDiff <= DAY) {
plotHorizontalScaleDay(startTime, endTime, xUnit, paddingLeft);
}
// Selection is less than 3 days
else if (timeDiff <= 3 * DAY) {
plotHorizontalScale3Day(startTime, endTime, xUnit, paddingLeft);
}
// Selection is less than a week. Show dayly view
else if (timeDiff <= WEEK) {
plotHorizontalScaleWeek(startTime, endTime, xUnit, paddingLeft);
}
// Selection is less than two weeks
else if (timeDiff <= 2 * WEEK) {
plotHorizontalScale2Weeks(startTime, endTime, xUnit, paddingLeft);
}
// Selection is less than a month. Show weekly view
else if (timeDiff <= 2 * MONTH) {
plotHorizontalScale2Months(startTime, endTime, xUnit, paddingLeft);
}
// Selection is less than 4 months. Show month view
else if (timeDiff <= YEAR) {
plotHorizontalScaleYear(startTime, endTime, xUnit, paddingLeft);
}
// Selection is more than two years
else{
plotHorizontalScaleOther(startTime, endTime, xUnit, paddingLeft);
}
}
/**
* Plots the vertical scale
* @return
* Returns the y-coordinate of the zero line
*/
private float plotVerticalScale(float yUnit, float canvasHeight) {
for(Label lbl : verticalScaleComponents) {
displayComponentPanel.remove(lbl);
}
verticalScaleComponents.clear();
if (gridColor != null) {
canvas.setStrokeStyle(gridColor);
canvas.setLineWidth(0.8);
canvas.beginPath();
}
float scaleStart = 0f;
float scaleEnd = 0f;
if (verticalScaleMax == null || verticalScaleMin == null) {
if (currentTotalMin == currentTotalMax) {
scaleStart = currentTotalMin - 5;
scaleEnd = currentTotalMax + 5;
} else {
scaleStart = currentTotalMin;
scaleEnd = currentTotalMax;
}
} else {
scaleStart = verticalScaleMin;
scaleEnd = verticalScaleMax;
}
float valueDiff = Math.abs(scaleEnd - scaleStart);
int counter = 0;
float last = scaleStart;
float zeroYCoordinate = canvasHeight + scaleStart * yUnit;
float y = 0f;
float iNorm = 0f;
for (float i = scaleStart; i <= scaleEnd; i += valueDiff / 5f) {
iNorm = i-scaleStart;
y = canvasHeight - iNorm * yUnit;
if (gridColor != null) {
canvas.moveTo(0, y);
canvas.lineTo(canvas.getWidth(), y);
}
addValueLabel(Math.round(y-13), i, 0);
// Catch the zero coordinate
if (last < 0 && i > 0 || i == 0) {
zeroYCoordinate = canvasHeight - (iNorm - i) * yUnit;
}
last = i;
counter++;
}
if (gridColor != null) {
canvas.closePath();
canvas.stroke();
}
// Draw the zero line
if (zeroYCoordinate > 0) {
canvas.setStrokeStyle("rgb(0,0,0)");
canvas.setLineWidth(1);
canvas.beginPath();
canvas.moveTo(0, zeroYCoordinate);
canvas.lineTo(canvas.getWidth(), zeroYCoordinate);
canvas.closePath();
canvas.stroke();
addValueLabel(Math.round(zeroYCoordinate-13), 0f, 0);
}
return zeroYCoordinate;
}
/**
* Plots the data on to the canvas
*
* @param mouseX
* The mouse x-coordinate position
* @param mouseY
* The mouse y-coordinate position
* @param force
* Forces the plotting of the same range already displayed on t
* the screen
*/
private void plotData(boolean force) {
// Abort if drawing the same range
if(!force && currentStartDate == previousStartDate && currentEndDate == previousEndDate) {
return;
}
// Set plotting number
long currentPlotCount = plotCounter;
plotCounter++;
// Hide dots
for(HTML dot : dots){
dot.setVisible(false);
}
// Hide bars
for(HTML bar: bars){
bar.setVisible(false);
}
//Set the text fields with the correct date
widget.setFromDateTextField(currentStartDate);
widget.setToDateTextField(currentEndDate);
// Get start and end times
Long startTime = currentStartDate.getTime();
Long endTime = currentEndDate.getTime();
// The currently selected time
Long timeDiff = endTime - startTime;
float paddingLeft = 2;
float paddingRight = 2;
Float canvasWidth = new Float(canvas.getWidth() - paddingLeft
- paddingRight);
Float canvasHeight = new Float(canvas.getHeight() - 10);
//Calculate the horizontal scale
Float xUnit = canvasWidth / timeDiff.floatValue();
// Calculate the vertical scale
Float yUnit = 0f;
Float diff = 0f;
if (verticalScaleMax == null || verticalScaleMin == null) {
// Vertical fitting
diff = new Float(currentTotalMax - currentTotalMin);
if (diff == 0) {
diff = 10f;
}
} else {
// Static vertical limits
diff = new Float(verticalScaleMax - verticalScaleMin);
}
yUnit = canvasHeight / diff;
// Clear old drawings
canvas.clear();
// Plot the vertical scale
currentZeroCoordinate = plotVerticalScale(yUnit, canvasHeight);
// Check for cancel drawing
if(currentPlotCount != plotCounter-1) {
return;
}
// Plot the horizontal scale
try {
plotHorizontalScale(xUnit, timeDiff, startTime, endTime,
paddingLeft, paddingRight);
} catch (Exception e) {
e.printStackTrace();
}
// Check for cancel drawing
if(currentPlotCount != plotCounter-1) {
return;
}
// Draw the graphs
currentXCoordinates.clear();
currentYCoordinates.clear();
// Set the zero coordinate
plotter.setZeroLevel(currentZeroCoordinate);
for(int g=0; g<widget.getNumGraphs(); g++){
// Check for cancel drawing
if (currentPlotCount != plotCounter - 1) {
return;
}
// Keep track of the x-coordinates
List<Float> xCoordinates = new ArrayList<Float>();
currentXCoordinates.put(g, xCoordinates );
// Keep track of the y-coordinates
List<Float> yCoordinates = new ArrayList<Float>();
currentYCoordinates.put(g, yCoordinates);
// Only render visible graphs
if (!widget.graphIsVisible(g)) {
continue;
}
// Normalize values
List<Float> normalizedValues = currentNormalizedValues.get(g);
if(normalizedValues == null || normalizedValues.size() == 0){
continue;
}
// Set Fill color
List<Integer> fillcolors = widget.getFillColorMap().get(g);
double fillalpha = fillcolors.get(3) / 255.0;
plotter.setFillColor("rgba("+fillcolors.get(0)+","+fillcolors.get(1)+","+fillcolors.get(2)+","+fillalpha+")");
// Set color
List<Integer> colors = widget.getColorMap().get(g);
plotter.setColor("rgb("+colors.get(0)+","+colors.get(1)+","+colors.get(2)+")");
List<Date> dates = currentDates.get(g);
if(dates == null || dates.size() == 0){
continue;
}
// Get the pre-point
Date startDate = dates.get(0);
Long timeFromStart = startDate.getTime() - startTime;
float x = timeFromStart * xUnit + paddingLeft;
float y = (currentZeroCoordinate > canvasHeight ? canvasHeight
: currentZeroCoordinate)
- normalizedValues.get(0)
* yUnit;
/*
* Fixes issue with rendering when value both over and above zero
*
* TODO REMOVE THIS HACK WHEN YOU GET THE CHANCE!!!
*/
if (currentTotalMin < 0) {
y += (canvasHeight - currentZeroCoordinate);
}
xCoordinates.add(x);
yCoordinates.add(y);
//Creates the plotting coordinates
for (int i = 1; i < normalizedValues.size(); i++) {
Float value = normalizedValues.get(i);
Date date = dates.get(i);
timeFromStart = date.getTime() - startTime;
y = (currentZeroCoordinate > canvasHeight ? canvasHeight
: currentZeroCoordinate)
- value * yUnit;
/*
* Fixes issue with rendering when value both over and above
* zero
*
* TODO REMOVE THIS HACK WHEN YOU GET THE CHANCE!!!
*/
if (currentTotalMin < 0) {
y += (canvasHeight - currentZeroCoordinate);
}
x = timeFromStart * xUnit + paddingLeft;
xCoordinates.add(x);
yCoordinates.add(y);
}
// Render the graph
if(currentMode == PlotMode.LINE) {
plotter.plotLineGraph(xCoordinates, yCoordinates, useLineCaps,
lineGraphThickness);
} else if (currentMode == PlotMode.BAR) {
currentBarWidth = plotter.plotFilledBarGraphByMinimums(
xCoordinates, yCoordinates);
} else if(currentMode == PlotMode.SCATTER) {
plotter.plotScatterGraph(xCoordinates, yCoordinates);
}
// Set the legend value to the last vale
List<Float> values = currentValues.get(g);
String value = values.get(values.size() - 1).toString();
widget.setLegendValue(g, value);
}
// Check for cancel drawing
if(currentPlotCount != plotCounter-1) {
return;
}
// Add markers
Set<String> removableMarkers = new HashSet<String>();
for(String markStr : markerMap.keySet()){
// Check for cancel drawing
if(currentPlotCount != plotCounter-1) {
return;
}
String m[] = markStr.split("_");
Long time = Long.parseLong(m[0]);
if(time >= startTime && time <= endTime){
Long timeFromStart = time - startTime;
float x = timeFromStart * xUnit + paddingLeft;
float y = canvas.getHeight();
plotMarker(markStr, x, y);
} else {
removableMarkers.add(markStr);
}
}
// Remove old markers
for(String m : removableMarkers) {
removeMarker(m);
}
// Remove old events
for(Button btn : events){
displayComponentPanel.remove(btn);
}
events.clear();
eventCoordinates.clear();
currentEventMap.clear();
currentEventDates.clear();
// Add events
List<String> eventList = new ArrayList<String>(currentEvents);
for(int e=eventList.size()-1; e>=0; e--){
if(currentPlotCount != plotCounter-1) {
return;
}
String eventStr = eventList.get(e);
String m[] = eventStr.split("_");
Long time = Long.parseLong(m[0]);
String caption = m[1];
int i = Integer.parseInt(m[2]);
Long timeFromStart = time - startTime;
float x = timeFromStart * xUnit + paddingLeft;
float y = 10;
plotEvent(caption, new Date(time), i, x, y);
}
// Set previous plotting data
previousStartDate = currentStartDate;
previousEndDate = currentEndDate;
}
/**
* Removes a marker from the display and memory
* @param markString
* The id of the marker
*/
private void removeMarker(String markString){
Label lbl = markerMap.get(markString);
if(lbl != null) {
displayComponentPanel.remove(lbl);
}
markerMap.remove(markString);
FlexTable tooltip = markerTooltipMap.get(markString);
if(tooltip != null) {
displayComponentPanel.remove(tooltip);
}
markerTooltipMap.remove(markString);
}
/**
* Plots a marker to a gived position
* @param caption
* The short caption to be displayed in the graph
* @param description
* The tooltip
* @param x
* The x-coordinate
* @param y
* The y-coordinate
*/
private void plotMarker(String markString, float x, float y){
// Check if marker exists on display
if(markerMap.get(markString) != null){
Label lbl = markerMap.get(markString);
lbl.setVisible(true);
displayComponentPanel.setWidgetPosition(lbl, (int)x-lbl.getOffsetWidth()/2, (int)y-lbl.getOffsetHeight());
FlexTable tooltip = markerTooltipMap.get(markString);
tooltip.setVisible(true);
int posX = (int)x-lbl.getOffsetWidth()-10;
int posY = (int)y-tooltip.getOffsetHeight()-lbl.getOffsetHeight()-10;
//Check if right border is reached, if so, the move the tooltip left
if(posX+tooltip.getOffsetWidth() > displayComponentPanel.getOffsetWidth()) {
posX -= tooltip.getOffsetWidth()-50;
}
displayComponentPanel.setWidgetPosition(tooltip, posX, posY);
tooltip.setVisible(false);
} else {
String m[] = markString.split("_");
Long time = Long.parseLong(m[0]);
String caption = m[1];
String description = m[2];
Label lbl = new Label(caption);
lbl.setStyleName(CLASSNAME_MARKER);
lbl.addStyleName(CLASSNAME_MARKER+"-"+caption);
displayComponentPanel.add(lbl);
displayComponentPanel.setWidgetPosition(lbl, (int)x-lbl.getOffsetWidth()/2, (int)y-lbl.getOffsetHeight());
markerMap.put(markString, lbl);
DateTimeFormat formatter = DateTimeFormat.getFormat("MMM d, ''yy");
FlexTable tooltip = new FlexTable();
tooltip.setVisible(true);
tooltip.setStyleName(CLASSNAME_MARKERTOOLTIP);
tooltip.setBorderWidth(0);
tooltip.setCellSpacing(0);
tooltip.setCellPadding(0);
tooltip.getRowFormatter().setStyleName(0, "top");
tooltip.getCellFormatter().setStyleName(0, 0, "topLeft");
tooltip.getCellFormatter().setStyleName(0, 1, "topMiddle");
tooltip.getCellFormatter().setStyleName(0, 2, "topRight");
tooltip.getRowFormatter().setStyleName(1, "middle");
tooltip.getCellFormatter().setStyleName(1, 0, "middleLeft");
tooltip.getCellFormatter().setStyleName(1, 1, "content");
tooltip.getCellFormatter().setStyleName(1, 2, "middleRight");
tooltip.getRowFormatter().setStyleName(2, "bottom");
tooltip.getCellFormatter().setStyleName(2, 0, "bottomLeft");
tooltip.getCellFormatter().setStyleName(2, 1, "bottomMiddle");
tooltip.getCellFormatter().setStyleName(2, 2, "bottomRight");
HTML content = new HTML(
"<span class=date>"+formatter.format(new Date(time))+"</span> <br/>"+
"<span class=text>"+description+"</span>"
);
tooltip.setWidget(1, 1, content);
displayComponentPanel.add(tooltip);
markerTooltipMap.put(markString, tooltip);
int posX = (int)x-lbl.getOffsetWidth()-10;
int posY = (int)y-tooltip.getOffsetHeight()-lbl.getOffsetHeight()-10;
//Check if right border is reached, if so, the move the tooltip left
if(posX+tooltip.getOffsetWidth() > displayComponentPanel.getOffsetWidth()) {
posX -= tooltip.getOffsetWidth()-50;
}
displayComponentPanel.setWidgetPosition(tooltip, posX, posY);
tooltip.setVisible(false);
}
}
/**
* Plots an event onto the display
* @param caption
* The caption that shows on the screen
* @param date
* The date the event happend
* @param index
* The server index of the event
* @param x
* The X-coordinate
* @param y
* The Y-coordinate
*/
private void plotEvent(String caption, Date date, int index, float x, float y){
Button event = new Button(caption);
event.setWidth((caption.length() * 30) + "px");
event.setStyleName(CLASSNAME_EVENT);
//Does an event with the same coordinate exist
boolean exists = false;
for(Integer i : eventCoordinates){
if ((i >= x && i <= x + 30) || (i >= x - 30 && i <= x)) {
event = events.get(eventCoordinates.indexOf(i));
event.setText("*");
event.setWidth("30px");
if (x < i) {
displayComponentPanel.setWidgetPosition(event, (int) x,
displayComponentPanel.getWidgetTop(event));
eventCoordinates.set(eventCoordinates.indexOf(i), (int) x);
}
currentEventMap.get(event).add(index);
currentEventDates.get(event).add(date);
exists = true;
break;
}
}
// Else add the event to the display
if(!exists){
displayComponentPanel.add(event, (int)x, (int)y);
events.add(event);
eventCoordinates.add((int)x);
List<Integer> indexes = new ArrayList<Integer>();
indexes.add(index);
currentEventMap.put(event, indexes);
List<Date> dates = new ArrayList<Date>();
dates.add(date);
currentEventDates.put(event, dates);
}
}
/*
* (non-Javadoc)
* @see com.vaadin.trends.ws.client.VDataListener#dataRecieved(java.lang.Long, java.util.List, java.util.List, java.util.Set)
*/
@Override
public void dataRecieved(Long requestId, List<Float> values, List<Date> dates, Set<String> markers, Set<String> events) {
Integer g = requestGraphMap.get(requestId);
// Check if we have new markers
if(markers != null){
for (String marker : markers) {
if (!markerMap.containsKey(marker)) {
markerMap.put(marker, null);
markerTooltipMap.put(marker, null);
}
}
}
//Check if we ahve events
if(events != null) {
currentEvents.addAll(events);
}
//Check that we have some values
if(values.size() > 0){
currentValues.put(g, values);
currentDates.put(g, dates);
currentMin.put(g, VTimelineWidget.getMinValue(values));
currentMax.put(g, VTimelineWidget.getMaxValue(values));
if (currentRealStartDate == null
|| currentRealStartDate.after(dates.get(0))) {
currentRealStartDate = dates.get(0);
}
if (currentRealEndDate == null
|| currentRealEndDate.before(dates
.get(dates.size() - 1))) {
currentRealEndDate = dates.get(dates.size() - 1);
}
if(currentMin.get(g) < currentTotalMin) {
currentTotalMin = currentMin.get(g);
}
if(currentMax.get(g) > currentTotalMax) {
currentTotalMax = currentMax.get(g);
}
if (verticalScaleMin != null) {
currentNormalizedValues.put(g, VTimelineWidget.normalizeValues(
values, verticalScaleMin));
} else {
if (values.size() > 1) {
currentNormalizedValues.put(g, VTimelineWidget.normalizeValues(values, currentTotalMin));
} else {
currentNormalizedValues.put(g, VTimelineWidget.normalizeValues(values, 0));
}
}
}
// If all graphs data has been recieved then plot the graph so the graphs
// does not appear one by one
if (graphDataRecievedCounter == widget.getNumGraphs() - 1) {
graphDataRecievedCounter = 0;
waitingForData = false;
if(dots.size() != widget.getNumGraphs()){
// Remove old dots
for (HTML dot : dots) {
displayComponentPanel.remove(dot);
}
dots.clear();
// Create the dots
for (int dg = 0; dg < widget.getNumGraphs(); dg++) {
HTML dot = new HTML("<B>·</B>");
dot.setStyleName(CLASSNAME_DOT);
dots.add(dot);
displayComponentPanel.add(dot);
List<Integer> colors = widget.getColorMap().get(dg);
DOM.setStyleAttribute(dot.getElement(), "color", "rgb("
+ colors.get(0) + "," + colors.get(1) + ","
+ colors.get(2) + ")");
}
}
if (bars.size() != widget.getNumGraphs()) {
// Remove old bars
for (HTML bar : bars) {
displayComponentPanel.remove(bar);
}
bars.clear();
// Create the bars
for (int dg = 0; dg < widget.getNumGraphs(); dg++) {
HTML bar = new HTML("");
bar.setStyleName(CLASSNAME_BAR);
bars.add(bar);
displayComponentPanel.add(bar);
}
}
// Plot the data to the screen
plotData(forcePlot);
// Forced plotting is always turned off after a forced plot. To
// force it again you have to set it on again be
// before the next plot.
forcePlot = false;
// Hide curtain
DOM.setStyleAttribute(loadingCurtain.getElement(), "display",
"none");
} else {
graphDataRecievedCounter++;
}
}
@Override
public void dataRecievedAll(List<Long> requestID,
Map<Integer, List<Float>> values, Map<Integer, List<Date>> dates,
Set<String> markers, Set<String> events, Map<Integer, Float> min,
Map<Integer, Float> max, Float totalMinimum, Float totalMaximum) {
// Check if we have new markers
if(markers != null){
for(String marker : markers){
if(!markerMap.containsKey(marker)){
markerMap.put(marker, null);
markerTooltipMap.put(marker, null);
}
}
}
//Check if we ahve events
if(events != null) {
currentEvents.addAll(events);
}
// Clear previous data
resetDisplayCache();
// Get total minimum / maximum
currentTotalMin = totalMinimum;
currentTotalMax = totalMaximum;
for (Entry<Integer, List<Float>> entry : values.entrySet()) {
Integer graph = entry.getKey();
List<Float> fvalues = entry.getValue();
List<Date> dvalues = dates.get(graph);
Float minval = min.get(graph);
Float maxval = max.get(graph);
// Sanity check 1
if (fvalues == null || dvalues == null) {
continue;
}
// Sanity check 2
if (dvalues.size() != fvalues.size()) {
continue;
}
// Sanity check 3
if (minval == null || maxval == null) {
continue;
}
currentValues.put(graph, fvalues);
currentDates.put(graph, dvalues);
currentMin.put(graph, minval);
currentMax.put(graph, maxval);
currentRealStartDate = dvalues.get(0);
currentRealEndDate = dvalues.get(dvalues.size() - 1);
if (verticalScaleMin != null) {
currentNormalizedValues.put(graph, VTimelineWidget
.normalizeValues(fvalues, verticalScaleMin));
} else {
currentNormalizedValues.put(graph, VTimelineWidget
.normalizeValues(fvalues, currentTotalMin));
}
}
// Plot the data
plotData(forcePlot);
graphDataRecievedCounter = 0;
DOM.setStyleAttribute(loadingCurtain.getElement(), "display", "none");
waitingForData = false;
}
/**
* Returns TRUE if the given x- and y- coordinate is over a marker
*
* @param x
* The x coordinate relative to the display component
* @param y
* The y coordinate relative to the display component
* @return Returns the marker it is over, else null
*/
private String coordinateIsOverMarker(int x, int y) {
int left, top, width, height;
int padding = 0;
for (String markerId : markerMap.keySet()) {
Label marker = markerMap.get(markerId);
left = displayComponentPanel.getWidgetLeft(marker);
top = displayComponentPanel.getWidgetTop(marker);
width = marker.getOffsetWidth();
height = marker.getOffsetHeight();
if (x >= left - padding && x <= left + width + padding
&& y >= top - padding && y <= top + height + padding) {
return markerId;
}
}
return null;
}
/**
* Hides all marker tooltips
*/
private void hideAllMarkerTooltips() {
for (FlexTable tooltip : markerTooltipMap.values()) {
tooltip.setVisible(false);
}
}
/*
* (non-Javadoc)
* @see com.vaadin.trends.ws.client.VMouseMoveListener#mouseMoved(com.google.gwt.user.client.Event)
*/
@Override
public void mouseMoved(Event mouseEvent) {
com.google.gwt.dom.client.Element mouseOver = Element.as(mouseEvent.getEventTarget());
if(hasElement(mouseOver)){
// Dragging action occurring..
if(mouseIsDown && enabled){
DOM.eventPreventDefault(mouseEvent);
for(HTML dot : dots){
dot.setVisible(false);
}
for(HTML bar : bars) {
bar.setVisible(false);
}
Long timeDiff = currentEndDragDate.getTime() - currentStartDragDate.getTime();
float xdiff = (mouseEvent.getClientX() - mouseDownX)/2f;
float canvasWidth = canvas.getWidth();
float widthUnit = xdiff/canvasWidth;
Float time = timeDiff*widthUnit;
Long start = currentStartDate.getTime() - time.longValue();
Long end = currentEndDate.getTime() - time.longValue();
Date startDate = new Date(start);
Date endDate = new Date(end);
if(startDate.compareTo(widget.getStartDate()) >= 0 && endDate.compareTo(widget.getEndDate()) <=0){
if(setRange(startDate, endDate, false, false, false)){
widget.setBrowserRange(startDate, endDate);
mouseDownX = mouseEvent.getClientX();
}
}
// Mouse is hovering over the display area
} else if(enabled){
DOM.eventPreventDefault(mouseEvent);
int x = mouseEvent.getClientX() - getAbsoluteLeft();
int y = mouseEvent.getClientY() - getAbsoluteTop();
hideAllMarkerTooltips();
// Over a marker
String markerId = coordinateIsOverMarker(x, y);
if (markerId != null) {
FlexTable markerTooltip = markerTooltipMap.get(markerId);
markerTooltip.setVisible(true);
return;
}
// Handle graph selectors
for(int g=0; g<widget.getNumGraphs(); g++){
if(!widget.graphIsVisible(g)) {
continue;
}
if(currentXCoordinates.size() <= g || currentYCoordinates.size() <= g) {
continue;
}
List<Float> xCoordinates = currentXCoordinates.get(g);
if(xCoordinates.size() == 0) {
continue;
}
List<Float> yCoordinates = currentYCoordinates.get(g);
if(yCoordinates.size() == 0) {
continue;
}
float minDiff = 10000000f;
int diffIndex = 0;
for(int i=0; i<xCoordinates.size(); i++){
if(xCoordinates.get(i) < 0 || xCoordinates.get(i) > canvas.getWidth()) {
continue;
}
float diff = Math.abs(x - xCoordinates.get(i));
if(diff < minDiff){
minDiff = diff;
diffIndex = i;
}
}
if(currentMode == PlotMode.LINE || currentMode == PlotMode.SCATTER){
dots.get(g).setVisible(true);
displayComponentPanel.setWidgetPosition(dots.get(g),
xCoordinates.get(diffIndex).intValue()-dots.get(g).getOffsetWidth()/2,
yCoordinates.get(diffIndex).intValue()-dots.get(g).getOffsetHeight()/2);
}
else if(currentMode == PlotMode.BAR){
setSelectedBarGraphBarVisible(g, xCoordinates,
yCoordinates, diffIndex);
}
List<Float>values = currentValues.get(g);
widget.setLegendValue(g, values.get(diffIndex).toString());
}
}
}
}
private void setSelectedBarGraphBarVisible(int graph,
List<Float> xCoordinates, List<Float> yCoordinates,
int coordinateIndex) {
int barX = xCoordinates.get(coordinateIndex).intValue()
- Math.round(currentBarWidth / 2f) + 1;
int barY = yCoordinates.get(coordinateIndex).intValue();
int barWidth = Math.round(currentBarWidth);
int barHeight = Math.round(currentZeroCoordinate
- yCoordinates.get(coordinateIndex).intValue());
HTML bar = bars.get(graph);
bar.setWidth(barWidth + "px");
bar.setHeight(barHeight + "px");
bar.setVisible(true);
displayComponentPanel.setWidgetPosition(bar, barX, barY);
}
/*
* (non-Javadoc)
* @see com.vaadin.trends.ws.client.VMouseClickListener#mouseDown(com.google.gwt.user.client.Event)
*/
@Override
public void mouseDown(Event mouseEvent) {
com.google.gwt.dom.client.Element mouseOver = Element.as(mouseEvent.getEventTarget());
if(!enabled && hasElement(mouseOver)){
DOM.eventPreventDefault(mouseEvent);
}
else if (hasElement(mouseOver)) {
DOM.eventPreventDefault(mouseEvent);
mouseIsDown = true;
mouseDownX = mouseEvent.getClientX();
canvas.setStyleName(CLASSNAME_CANVASDRAG);
for(Label lbl : verticalScaleComponents) {
lbl.setStyleName(CLASSNAME_SCALEVALUEDRAG);
}
DOM.setCapture(canvas.getElement());
currentStartDragDate = new Date(currentStartDate.getTime());
currentEndDragDate = new Date(currentEndDate.getTime());
}
// Check if element is a event button
for(Button btn : events){
if(Element.as(mouseEvent.getEventTarget()) == btn.getElement()){
eventClick(btn);
break;
}
}
}
/*
* (non-Javadoc)
* @see com.vaadin.trends.ws.client.VMouseClickListener#mouseUp(com.google.gwt.user.client.Event)
*/
@Override
public void mouseUp(Event mouseEvent) {
if (mouseIsDown && enabled) {
DOM.eventPreventDefault(mouseEvent);
mouseIsDown = false;
for(HTML dot : dots){
dot.setVisible(false);
}
for(HTML bar : bars) {
bar.setVisible(false);
}
Long timeDiff = currentEndDragDate.getTime() - currentStartDragDate.getTime();
float xdiff = (mouseEvent.getClientX() - mouseDownX)/2f;
float canvasWidth = canvas.getWidth();
float widthUnit = xdiff/canvasWidth;
Float time = timeDiff*widthUnit;
Long start = currentStartDate.getTime() - time.longValue();
Long end = currentEndDate.getTime() - time.longValue();
Date startDate = new Date(start);
Date endDate = new Date(end);
if(startDate.compareTo(widget.getStartDate()) >= 0 && endDate.compareTo(widget.getEndDate()) <=0){
if(setRange(startDate, endDate, false, true, false)){
widget.setBrowserRange(startDate, endDate);
mouseDownX = mouseEvent.getClientX();
widget.fireDateRangeChangedEvent();
}
}
for(Label lbl : verticalScaleComponents) {
lbl.setStyleName(CLASSNAME_SCALEVALUEDRAG);
}
canvas.setStyleName(CLASSNAME_CANVAS);
DOM.releaseCapture(canvas.getElement());
currentStartDragDate = null;
currentEndDragDate = null;
}
}
/**
* Set the range to display
* @param start
* The start date
* @param end
* The end date
* @return
*/
public boolean setRange(Date start, Date end, Boolean useCurtain, boolean loadAllPoints, boolean forceServer){
if (waitingForData) {
return false;
}
if(start == null || end == null) {
return false;
}
currentStartDate = start;
currentEndDate = end;
currentRealStartDate = null;
currentRealEndDate = null;
graphDataRecievedCounter = 0;
currentTotalMax = -9999999f;
currentTotalMin = 99999999f;
waitingForData = true;
resetDisplayCache();
// Try to get the data from the cache
Long timeDiff = currentEndDate.getTime() - currentStartDate.getTime();
// Calculate point density
Long density = timeDiff / (120L*86400000L) +1L;
if(loadAllPoints) {
density = 1L;
}
// Get the date data
boolean cached = false;
if(forceServer){
// Some data not found in cache, get it from the server
for(int g=0; g<widget.getNumGraphs(); g++) {
widget.getDateData(this, g, start, end, density.intValue());
}
// Issue request
widget.getFromServer();
} else {
cached = widget.getDateDataAll(this, start, end, density.intValue());
}
waitingForData = !cached;
if(useCurtain && !cached){
// Show loading icon if loading from the server
DOM.setStyleAttribute(loadingCurtain.getElement(), "display", "block");
} else {
DOM.setStyleAttribute(loadingCurtain.getElement(), "display", "none");
}
return true;
}
/**
* Sets the chart plotting mode
* @param mode
* The plotting mode
*/
public void setChartMode(PlotMode mode, boolean doPlotting) {
if (mode != null) {
currentMode = mode;
if (doPlotting) {
plotData(true);
}
}
}
/**
* Sets the canvas width
* @param width
* The width in pixels
*/
public void setCanvasWidth(int width){
canvas.setWidth(width);
displayComponentPanel.setWidth(width + "px");
}
/**
* Setst the canvas height
*
* @param height
* The height in pixels
*/
public void setCanvasHeight(int height) {
canvas.setHeight(height - bottomBar.getOffsetHeight());
displayComponentPanel.setHeight(height + "px");
displayComponentPanel.setWidgetPosition(bottomBar, 0, height
- bottomBar.getOffsetHeight());
}
/**
* Returns the canvas width
* @return
* The width in pixels
*/
public int getCanvasWidth(){
return canvas.getWidth();
}
/**
* Get the current starting date
* @return
* The date
*/
public Date getSelectionStartDate(){
return currentStartDate;
}
/**
* Get the current ending date
* @return
* The date
*/
public Date getSelectionEndDate(){
return currentEndDate;
}
/**
* Get the total minimal value of the graphs
* @return
* The minimum
*/
public Float getMin(){
return currentTotalMin;
}
/**
* Get the total maximal value of the graphs
* @return
* The maximum
*/
public Float getMax(){
return currentTotalMax;
}
/**
* Set the state of the vertical fitting. If vertical fitting is enabled then
* the vertical scale is made depending on the maximal and minimal values in
* the graphs. If min and max is given then the scale is made using them.
* @param auto
* Enable automatic scale fitting
* @param min
* The minimal value of the scale
* @param max
* The maximal value of the scale
*/
public void setVerticalFitting(boolean auto, float min, float max){
if(auto){
verticalScaleMax = null;
verticalScaleMin = null;
} else {
verticalScaleMin = min;
verticalScaleMax = max;
}
}
/**
* Removes a graph from the cache so it will not be rendered when plotData
* is called
* @param graph
* The index of the graph to be removed
*/
public void removeGraph(int graph){
currentValues.put(graph, new ArrayList<Float>());
currentDates.put(graph, new ArrayList<Date>());
currentNormalizedValues.put(graph, new ArrayList<Float>());
}
/*
* (non-Javadoc)
* @see com.vaadin.trends.ws.client.VMouseScrollListener#scroll(com.google.gwt.user.client.Event)
*/
@Override
public void scroll(Event mouseEvent) {
if (hasElement(Element.as(mouseEvent.getEventTarget()))) {
DOM.eventPreventDefault(mouseEvent);
float x = DOM.eventGetClientX(mouseEvent);
boolean up = DOM.eventGetMouseWheelVelocityY(mouseEvent) > 0;
float canvasWidth = canvas.getWidth();
float ratio = x / canvasWidth;
Float startRatio = ratio * DAY;
Float endRatio = (1f - ratio) * DAY;
if (up) {
Date start = new Date(currentStartDate.getTime()
- startRatio.longValue());
Date end = new Date(currentEndDate.getTime()
+ endRatio.longValue());
if (end.getTime() - start.getTime() > DAY) {
if (setRange(start, end, false, true, false)) {
widget.setBrowserRange(start, end);
}
}
} else {
Date start = new Date(currentStartDate.getTime()
+ startRatio.longValue());
Date end = new Date(currentEndDate.getTime()
- endRatio.longValue());
if (end.getTime() - start.getTime() > DAY) {
if (setRange(start, end, false, true, false)) {
widget.setBrowserRange(start, end);
}
}
}
}
}
/**
* Triggered when an event button is pressed
*
* @param eventButton
*/
private void eventClick(Button eventButton) {
List<Integer> indexes = currentEventMap.get(eventButton);
widget.fireEventButtonClickEvent(indexes);
if (indexes.size() > 1) {
// Resolve first and last date
List<Date> dates = currentEventDates.get(eventButton);
Date start = dates.get(0);
Date end = dates.get(0);
for (Date d : dates) {
if (start.after(d)) {
start = d;
}
if (end.before(d)) {
end = d;
}
}
Long timeDiff = end.getTime() - start.getTime();
Date leftEdge = new Date(start.getTime() - timeDiff * 2L);
Date rightEdge = new Date(end.getTime() + timeDiff * 2L);
widget.setBrowserRange(leftEdge, rightEdge);
setRange(leftEdge, rightEdge, true, true, false);
}
}
/*
* (non-Javadoc)
*
* @see
* com.vaadin.trends.ws.client.VDataListener#setCurrentRequestId(java.lang
* .Long, int)
*/
@Override
public void setCurrentRequestId(Long requestID, Integer graphIndex) {
requestGraphMap.put(requestID, graphIndex);
}
/**
* Does the component have an specific element
*
* @param elem
* The element
* @return True if the component has the element
*/
public boolean hasElement(com.google.gwt.dom.client.Element elem) {
for (Label lbl : horizontalScaleComponents) {
if (lbl.getElement() == elem) {
return true;
}
}
for (Label lbl : verticalScaleComponents) {
if (lbl.getElement() == elem) {
return true;
}
}
for (String marker : markerMap.keySet()) {
if (markerMap.get(marker) != null
&& markerMap.get(marker).getElement() == elem) {
return true;
}
}
for (Button eventBtn : events) {
if (eventBtn.getElement() == elem) {
return true;
}
}
if (elem == displayComponentPanel.getElement() || elem == getElement()
|| elem == canvas.getElement()
|| elem == loadingCurtain.getElement() || elem == browserRoot
|| elem == bottomBar.getElement()
|| elem == disabledCurtain.getElement()) {
return true;
} else {
return false;
}
}
/**
* Set the loading percentage of the cache
*
* @param percent
* Percentage
*/
public void setCacheLoadingPercentage(int percent) {
preloadingStatus.setText(String.valueOf(percent) + "%");
if (percent == 0) {
preloadingStatus.setVisible(true);
}
if (percent == 100) {
preloadingStatus.setVisible(false);
}
}
/**
* Displays the no data found message
*
* @param enabled
* Is the message displayed
*/
public void displayNoDataMessage(boolean enabled) {
noDataLabel.setVisible(enabled);
loadingCurtain.setVisible(!enabled);
}
/**
* Is the display enabled
*
* @param enabled
* True if enabled
*/
public void setEnabled(boolean enabled) {
this.enabled = enabled;
disabledCurtain.setVisible(!enabled);
}
/**
* This turns on the line caps use in drawing the line graph
*
* @param enabled
* Are line caps used
*/
public void setLineCaps(boolean enabled, boolean redraw) {
useLineCaps = enabled;
if (redraw) {
plotData(true);
}
}
/**
* Sets the thickness of the line graphs
*
* @param thickness
* The thickness in pixels
* @param redraw
* Shoulw the plot be redrawn
*/
public void setLineThickness(double thickness, boolean redraw) {
lineGraphThickness = thickness;
if (redraw) {
plotData(true);
}
}
/**
* Force plotting the the data even if it is the same time range. Forced
* plotting is always turned off after a forced plot so you will have to
* turn on forced plotting again before the next plot.
*
* @param enabled
* The plotting is forced
*/
public void setForcedPlotting(boolean enabled) {
forcePlot = enabled;
}
/**
* Sets the scale grid color, set to null to not draw the grid
*
* @param color
* The color
*/
public void setGridColor(String color) {
gridColor = color;
}
}