dojo charting - Date as X Axis - Dates plotted are incorrect and not related to those retrieved from the backend

666 Views Asked by At

We are working on a stock related application involving charting using dojo 10.0.3. Due to the nature of the application, we need to use date as the X-Axis.

And both the date (X-Axis) and various prices (Y-Axis) are from a backend database retrieved via a Restful web service call:

var jsonStore   = new JsonStore({"target": "/blah1/blah2", "idProperty": "date" });

The following is the code snippet for charting:

   function dateLabel (dateString) {

   // While date in the backend is integer, what is passed to this function is strangely
   // a string in the format of "1,415,232,000,000", irrelevant to the backend data.

       var dateInt = parseInt( ( dateString.replace(/,/g, "") ) );
       var dt = new Date(dateInt);
       return (dt.getMonth() + 1) + "/" + dt.getDate() + "/" + dt.getFullYear();       
   }

   var xOpts = {
                 "title"           : "Date",
                 "titleOrientation": "away",  // or "axis"
                 "titleGap"        : 10,                 

                 "majorLabels"     : true, 
                 "majorTicks"      : true, 
                 "majorTick"       : {"length": 10},
                 "majorTickStep"   : 31536000000,       /** 1 year  in milliseconds **/

                 "minorLabels"     : true, 
                 "minorTicks"      : true, 
                 "minorTick"       : {"length": 6},
                 "minorTickStep"   : 2419200000,        /** 4 weeks in milliseconds **/

                 "microTicks"      : true, 
                 "microTick"       : {"length": 3},
                 "microTickStep"   : 86400000,          /** 1 day   in milliseconds **/

                 "labelFunc"       : dateLabel
               }

   var chart = new Chart("chartNode"); 
   chart.addPlot("default", { "type": Lines,  "markers": true,  hAxis: "x",  vAxis: "y" } );
   chart.addAxis("x", xOpts);
   chart.addAxis("y", { vertical: true, fixLower: "major", fixUpper: "major" });   

   var tip = new Tooltip(chart,"default");
   var mag = new Magnify(chart,"default");

   var storeSeries = new StoreSeries(jsonStore, { query: { } }, {"x": "date", "y": "close"} );
   chart.addSeries("Close", storeSeries, strokeAndFill1 );

   chart.render();

While the graph is correct as far as Y-Axis is concerned, the dates plotted on the X-Axis is rather strange and they does not align with the markers.

From Firebug, the json objects returned from the backend are:

[{"date":1414990800000,"open":164.25,"high":164.54,"low":163.38,"close":164.36,...},
 {"date":1415077200000,"open":164.34,"high":164.36,"low":162.24,"close":162.65,...},
 {"date":1415163600000,"open":163.13,"high":163.54,"low":161.56,"close":161.82,...},
 {"date":1415250000000,"open":161.28,"high":161.53,"low":160.05,"close":161.46,...},
 {"date":1415336400000,"open":161.42,"high":162.21,"low":160.85,"close":162.07,...}]

(The above "date" data correspond to Nov 3 ~ Nov 7, 2014, all at 0:00 AM GMT-5.) 

However, the date passed to the X-Axis calculation function, dateLabel, is a string: "1,415,232,000,000" (i.e., Nov 5, 2014 at 19:00 GMT-5), which is irrelevant to the backend data.

The questions are:

1) Why X-Axis behaves so strange? Why the data passed to the dateLabel function is not the date 
   returned from the web service call as defined in the StoreSeries? 

2) Currently in the plot, when the "marker" is clicked, it only shows the price. Is it possible
   to customize it to show both the date and the price? 

Thank you very much for helping!

Tel

1

There are 1 best solutions below

0
On

To answer my own question:

Have traced into the dojox source code and found the answer. The source code related to Axis - tick calculation is as follows:


    var lowerBound = findString(kwArgs.fixLower, ["major"]) ?
            Math.floor(kwArgs.min / majorTick) * majorTick :
                findString(kwArgs.fixLower, ["minor"]) ?
                    Math.floor(kwArgs.min / minorTick) * minorTick :
                        findString(kwArgs.fixLower, ["micro"]) ?
                            Math.floor(kwArgs.min / microTick) * microTick : kwArgs.min,
        upperBound = findString(kwArgs.fixUpper, ["major"]) ?
            Math.ceil(kwArgs.max / majorTick) * majorTick :
                findString(kwArgs.fixUpper, ["minor"]) ?
                    Math.ceil(kwArgs.max / minorTick) * minorTick :
                        findString(kwArgs.fixUpper, ["micro"]) ?
                            Math.ceil(kwArgs.max / microTick) * microTick : kwArgs.max;

    if(kwArgs.useMin){ min = lowerBound; }
    if(kwArgs.useMax){ max = upperBound; }      

    var majorStart = (!majorTick || kwArgs.useMin && findString(kwArgs.fixLower, ["major"])) ?
            min : Math.ceil(min / majorTick) * majorTick,
        minorStart = (!minorTick || kwArgs.useMin && findString(kwArgs.fixLower, ["major", "minor"])) ?
            min : Math.ceil(min / minorTick) * minorTick,
        microStart = (! microTick || kwArgs.useMin && findString(kwArgs.fixLower, ["major", "minor", "micro"])) ?
            min : Math.ceil(min / microTick) * microTick,
        majorCount = !majorTick ? 0 : (kwArgs.useMax && findString(kwArgs.fixUpper, ["major"]) ?
            Math.round((max - majorStart) / majorTick) :
            Math.floor((max - majorStart) / majorTick)) + 1,
        minorCount = !minorTick ? 0 : (kwArgs.useMax && findString(kwArgs.fixUpper, ["major", "minor"]) ?
            Math.round((max - minorStart) / minorTick) :
            Math.floor((max - minorStart) / minorTick)) + 1,
        microCount = !microTick ? 0 : (kwArgs.useMax && findString(kwArgs.fixUpper, ["major", "minor", "micro"]) ?
            Math.round((max - microStart) / microTick) :
            Math.floor((max - microStart) / microTick)) + 1,
        minorPerMajor  = minorTick ? Math.round(majorTick / minorTick) : 0,
        microPerMinor  = microTick ? Math.round(minorTick / microTick) : 0,
        majorPrecision = majorTick ? Math.floor(Math.log(majorTick) / Math.LN10) : 0,
        minorPrecision = minorTick ? Math.floor(Math.log(minorTick) / Math.LN10) : 0,

where the initial kwArgs.min (e.g., 1415250000000) and initial kwArgs.max (e.g., 1415336400000) are the min and max time point (in milliseconds since the epoch) from the backend data source;

and majorTick, minorTick & microTick are the respective tick steps. (In my troubleshooting case, I set majorTick to 86400000 which is one day expressed in milliseconds, and disabled minor and micro ticks for simplicity.)

From the above source code, it seems that whatever I configure the X-Axis, dojox charting will not do the right thing for my simple and common business case where date need to be used as X-Axis. The ticks plotted on the X-Axis do not align well with the markers on the graph. I have to either provide my own code, or use some other charting framework such as D3.

Thanks!