Package com.vaadin.addon.timeline.gwt.client

Source Code of com.vaadin.addon.timeline.gwt.client.VTimelineDisplay

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>&#183;</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;
    }
}
TOP

Related Classes of com.vaadin.addon.timeline.gwt.client.VTimelineDisplay

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.