Source: widget/TideChart.js

/**
 * Widget that creates a chart of storm surge and tide data
 * @module app/widget/TideChart
 * @author David Kristiansen <david.kristiansen@nscc.ca>
 * @copyright Nova Scotia Community College 2017
 */
define([
    "dojo/_base/declare",
    "dojo/_base/lang",
    "dojo/on",
    "dojo/topic",
    "dojo/Evented",
    "dojo/dom",
    "dojo/dom-construct",
    "dijit/_WidgetBase",
    "dijit/_OnDijitClickMixin",
    "dijit/Tooltip",

    "moment/moment",

    "dstore/charting/StoreSeries",

    "dojox/charting/Chart",
    "dojox/charting/axis2d/Default",
    "dojox/charting/plot2d/Areas",
    "dojox/charting/plot2d/Grid",
    "dojox/charting/plot2d/Columns",
    "dojox/charting/plot2d/Lines",
//    "dojox/charting/plot2d/Indicator",
    "dojox/charting/action2d/MouseZoomAndPan",
    "dojox/charting/action2d/Highlight",
    "dojox/charting/themes/Wetland",
    "dojox/charting/widget/Legend",
    "dojox/charting/widget/SelectableLegend"
],
    function (
        declare,
        lang,
        on,
        topic,
        Evented,
        dom,
        domConstruct,
        _WidgetBase,
        _OnDijitClickMixin,
        Tooltip,

        moment,

        StoreSeries,

        Chart,
        Default,
        Areas,
        Grid,
        Columns,
        Lines,
        //        Indicator,
        MouseZoomAndPan,
        Highlight,
        Theme,
        Legend,
        SelectableLegend
    ) {

        return declare([_WidgetBase, _OnDijitClickMixin, Evented], {

            chart: null,
            gridStore: null,
            selectedTideStore: null,
            nowTideStore: null,
            xLabels: null,
            yLabels: null,
            options: {
                dataStore: null,
                title: null
            },
            /** @constructor
             * @param {object} args Object of properties to mixin
             * @param {object} srcRefNode Dom node for the widget to attach to
             **/
            constructor: function (param, srcRefNode) {
//                console.log("Chart::constructor");
                /** mix in settings and defaults
                 * @mixin args
                 */
                declare.safeMixin(this.options, param);
               /** Dom widget node */
                this.domNode = srcRefNode;
                // properties
                this.set("dataStore", this.options.dataStore);
                this.title = this.options.title || "";
            },
            /**
            * Creates the dom elements used by the chart.
            **/
            postCreate: function () {
//                console.log("Chart::postCreate");
                //                <div id='chart'></div><div id='chartLegend'></div>
                var divChart = dom.byId(this.domNode);
                domConstruct.create("div", {
                    id: "tooltipChart"
                }, divChart);
                domConstruct.create("div", {
                    id: "chart"
                }, divChart);
            },
            /**
             * Starts the widget after it has been constructed.
             * Checks to make sure the required data is loaded.
             * @public
             *
             **/
            startup: function () {
//                console.log("Chart::startup");
                /* Data not defined*/
                if (!this.dataStore.memDStore) {
                    this.destroy();
                    console.warn("Chart::Tide data required");
                }
                /* When data is loaded*/
                if (typeof this.dataStore.memDStore.data !== "undefined" && this.dataStore.memDStore.data !== null && this.dataStore.memDStore.data.length > 0) {
                    this._init();
                } else {
                    console.warn("Chart::Waiting to load chart..");
                    on(this.dataStore, "tideData_ready", lang.hitch(this, function () {
                        this._init();
                    }));
                }
            },
            /**
             * Destroys widget and any lingering tooltips.
             * @public
             *
             **/
            destroy: function () {
                Tooltip.show("", dom.byId('dijit__MasterTooltip_0'));
                Tooltip.hide(dom.byId('dijit__MasterTooltip_0'));
                this.inherited(arguments);
//                console.log("Chart::destroyed");
            },
            /**
             * Calls the createChart method.
             * @private
             *
             **/
            _init: function () {
//                console.log("Chart::_init");
                this.createChart();
            },
            /**
            * Creates the tide and storm surge chart for a single tide station.
            * @public
            * @todo Compartmentalize parts of the chart to handled sepearately
            **/
            createChart: function () {
//                console.log("Chart::createChart");
                //                this.thresLabels = function (text, value, precision) {
                //                    var thresholds = ["Stage 1 Flood", "Stage 2 Flood", "Stage 3 Flood", "Record Water Level"];
                //                    return thresholds[text];
                //                };
                this.xLabels = function (text, value, precision) {
                    return new Date(this.data[value - 1].fulldate).getHours().toString();
                };
                //                this.markerLabels = function (args, plot) {
                //                    var surgeVal = plot.series[1].data[args.index] - plot.series[0].data[args.index]
                //                    var strTip = "TWL: " + plot.series[1].data[args.index] + "</br> Tide: " + plot.series[0].data[args.index] + "</br> Surge: " + surgeVal.toFixed(3); //To Fix floating point error hopefully
                //                    return strTip;
                //                }
                var startDt = new Date(this.dataStore.memDStore.data[0].fulldate);
                var lenDt = this.dataStore.memDStore.data.length - 1;
                var endDt = new Date(this.dataStore.memDStore.data[lenDt].fulldate);
                var momentLocale = moment.localeData();
                var xTitle = "<b>Local Time (hours)</b> (" + momentLocale.longDateFormat('L') + ")</br>From: " + moment(startDt).format('L LT') + " To: " + moment(endDt).format('L LT');
                //                console.log(momentLocale.longDateFormat('L'));
                //////////////////
                /* Chart Begins */
                //////////////////
                var chart = new Chart("chart", {
                    title: this.title,
                    titlePos: "top",
                    titleGap: 5,
                    titleFont: "normal normal normal 15pt Arial"
                });
                chart.addPlot("default", {
                    type: Areas,
                    line: true,
                    markers: true,
                    tension: "X"
                });
                chart.addPlot("surge", {
                    type: Lines,
                    tension: "X"
                });
                chart.addPlot("grids", {
                    type: Grid,
                    vMajorLines: false,
                    vMinorLines: false,
                    hAxis: "x",
                    vAxis: "y"
                });
                //                chart.addPlot("nowPlot", {
                //                    type: "Columns",
                //                    gap: 1,
                //                    minBarSize: 1,
                //                    maxBarSize: 1,
                //                    vAxis: "y2"
                //                });
                chart.addPlot("bargraph", {
                    type: "Columns",
                    gap: 0,
                    //                    minBarSize: 1,
                    //                    maxBarSize: 1,
                    vAxis: "y2"
                });
                //                chart.addPlot("threshold", {
                //                    type: Indicator,
                //                    vertical: false,
                //                    //        values: [2.992,3.092,3.292,2.822,3.592],
                //                    values: [-1.592, -0.092, 1.292, 1.822, 2.92],
                //                    lineStroke: {
                //                        color: "navy",
                //                        style: "dash"
                //                    },
                //                    stroke: "transparent",
                //                    outline: "transparent",
                //                    fill: "transparent",
                //                    fontColor: "rgba(0, 0, 128, 0.8)",
                //                    labelStyle: 'inside',
                //
                //                    labelFunc: this.thresLabels //lang.hitch(this.dataStore.memDStore, this.xLabels)
                //                });
                chart.addAxis("x", {
                    title: xTitle, //"Time (hours) Start: End",
                    titleOrientation: "away",
                    titleFont: "normal normal normal 11pt Arial",
                    minorTicks: false,
                    majorTickStep: 1,
                    min: 1,
                    labelFunc: lang.hitch(this.dataStore.memDStore, this.xLabels)
                });
                chart.addAxis("y", {
                    title: "Water Level CGVD28 (m)",
                    titleFont: "normal normal bold 11pt Arial",
                    vertical: true,
                    fixLower: "major",
                    fixUpper: "major",
                });
                chart.addAxis("y2", {
                    vertical: true,
                    type: "Invisible",
                    fixLower: "major",
                    fixUpper: "major",
                    min: 0,
                    max: 1.0
                });
                chart.addSeries("Predicted Storm Surge", new StoreSeries(this.dataStore.memDStore, "surge"), {
                    stroke: {
                        color: "#3655ff",
                        width: 2
                    },
                    plot: "surge",
                    enableCache: true
                });
                chart.addSeries("Predicted Total Water Level (TWL)", new StoreSeries(this.dataStore.memDStore, "twl"), {
                    stroke: {
                        color: "#d32626",
                        width: 2
                    },
                    fill: "rgba(255, 11, 0, 0.2)",
                    plot: "default",
                    enableCache: true
                });
                chart.addSeries("Predicted Tide", new StoreSeries(this.dataStore.memDStore, "tide"), {
                    stroke: {
                        color: "rgb(255, 165, 0)",
                        width: 2
                    },
                    fill: "rgba(255, 245, 0, 0.3)",
                    plot: "default",
                    marker: "m-0",
                    enableCache: true
                });

                //                chart.addSeries("Current Time", new StoreSeries(this.dataStore.chartTrack, "now"), {
                //                    stroke: {
                //                        color: "rgb(0, 11, 149)"
                //                    },
                //                    fill: "rgb(0, 11, 149)",
                //                    plot: "nowPlot",
                //                    enableCache: true
                //                });
                chart.addSeries("Hover", new StoreSeries(this.dataStore.chartTrack, "clk"), {
                    stroke: {
                        color: "transparent"
                    },
                    fill: "transparent",
                    plot: "bargraph",
                    enableCache: true
                });

                //                chart.movePlotToFront("nowPlot");
                chart.movePlotToFront("surge");
                chart.movePlotToFront("bargraph");

                var hilite = new Highlight(chart, "bargraph", {
                    highlight: "rgba(0, 157, 6, 0.48)",
                    duration: 10
                });
                chart.setTheme(Theme);

                //                                chart.setAxisWindow("x", 3, 2);
                //                chart.setWindow(1, 1, 0, 0);
                //                new MouseZoomAndPan(chart, "default", {
                //                    axis: "x",
                //                    enableScroll: false
                //                });
                chart.render();

                var legend = new SelectableLegend({
                    chart: chart,
                    horizontal: false
                }, "chartLegend");

                var tooltip = new Tooltip({
                    style: "opacity:1;"
                });

                chart.connectToPlot("bargraph", lang.hitch(this.dataStore.chartTrack, function (evt) {
                    var surgeVal = chart.getPlot("surge").series[0].data[evt.x]; //surge
                    var tideVal = chart.getPlot("default").series[1].data[evt.x]; //Tide
                    var twlVal = chart.getPlot("default").series[0].data[evt.x]; //twl
//                    console.log("Surge:", surgeVal, " Tide:", tideVal, " TWL:", twlVal);

                    if (evt.type === "onmouseover") {
                        var dtVal = new Date(this.data[evt.x].dt);

                        var around = chart.getPlot("default").toPage({
                            x: evt.x + 1,
                            y: maxVertical
                        });
                        around.w = 1;
                        around.h = 1;
                        tooltip.label = "<div class='ttChart'><p class='ttText'>" + moment(dtVal).format('LT') + "</p><p class='ttText'>" + moment(dtVal).format('L') + "</p><table class='ttTable'><tbody><tr><td>TWL:</td><td>" + twlVal.toFixed(2) + "</td></tr><tr><td>Tide:</td><td>" + tideVal.toFixed(2) + "</td></tr><tr><td>Surge:</td><td>" + surgeVal.toFixed(2) + "</td></tr></tbody></table><div>";
                        tooltip.position = ["above-centered"];
                        tooltip.open(around);
                    } else if (evt.type == "onmouseout") {
                        tooltip.close();
                    } else if (evt.type === "onclick") {
                        //                        console.log(twlVal); //twl
                        //emit event of twlVal value to be heard by the other modules
                        topic.publish("selection", twlVal);
                    }
                }));
                var maxVertical = chart.getAxis("y").getScaler().bounds.to;
            }
        });
    });