Make sure that canvasx and canvasy properties are initialized from the start (#896)
[dygraphs.git] / src / datahandler / datahandler.js
CommitLineData
a49c164a
DE
1/**
2 * @license
3 * Copyright 2013 David Eberlein (david.eberlein@ch.sauter-bc.com)
4 * MIT-licensed (http://opensource.org/licenses/MIT)
5 */
6
7/**
8 * @fileoverview This file contains the managment of data handlers
9 * @author David Eberlein (david.eberlein@ch.sauter-bc.com)
c76d4b2a 10 *
a49c164a
DE
11 * The idea is to define a common, generic data format that works for all data
12 * structures supported by dygraphs. To make this possible, the DataHandler
13 * interface is introduced. This makes it possible, that dygraph itself can work
14 * with the same logic for every data type independent of the actual format and
c76d4b2a 15 * the DataHandler takes care of the data format specific jobs.
a49c164a
DE
16 * DataHandlers are implemented for all data types supported by Dygraphs and
17 * return Dygraphs compliant formats.
18 * By default the correct DataHandler is chosen based on the options set.
19 * Optionally the user may use his own DataHandler (similar to the plugin
20 * system).
c76d4b2a
DV
21 *
22 *
23 * The unified data format returend by each handler is defined as so:
24 * series[n][point] = [x,y,(extras)]
25 *
a49c164a
DE
26 * This format contains the common basis that is needed to draw a simple line
27 * series extended by optional extras for more complex graphing types. It
28 * contains a primitive x value as first array entry, a primitive y value as
29 * second array entry and an optional extras object for additional data needed.
c76d4b2a 30 *
a49c164a
DE
31 * x must always be a number.
32 * y must always be a number, NaN of type number or null.
33 * extras is optional and must be interpreted by the DataHandler. It may be of
c76d4b2a
DV
34 * any type.
35 *
a49c164a
DE
36 * In practice this might look something like this:
37 * default: [x, yVal]
38 * errorBar / customBar: [x, yVal, [yTopVariance, yBottomVariance] ]
c76d4b2a 39 *
a49c164a 40 */
a49c164a
DE
41/*global Dygraph:false */
42/*global DygraphLayout:false */
3ea41d86 43
6ecc0739
DV
44"use strict";
45
a49c164a 46/**
c76d4b2a 47 *
a49c164a
DE
48 * The data handler is responsible for all data specific operations. All of the
49 * series data it receives and returns is always in the unified data format.
50 * Initially the unified data is created by the extractSeries method
749281f8 51 * @constructor
a49c164a 52 */
6ecc0739 53var DygraphDataHandler = function () {
749281f8
DV
54};
55
6ecc0739 56var handler = DygraphDataHandler;
a49c164a 57
749281f8
DV
58/**
59 * X-value array index constant for unified data samples.
60 * @const
61 * @type {number}
62 */
63handler.X = 0;
a49c164a 64
749281f8
DV
65/**
66 * Y-value array index constant for unified data samples.
67 * @const
68 * @type {number}
69 */
70handler.Y = 1;
71
72/**
73 * Extras-value array index constant for unified data samples.
74 * @const
75 * @type {number}
76 */
77handler.EXTRAS = 2;
78
79/**
80 * Extracts one series from the raw data (a 2D array) into an array of the
81 * unified data format.
82 * This is where undesirable points (i.e. negative values on log scales and
83 * missing values through which we wish to connect lines) are dropped.
84 * TODO(danvk): the "missing values" bit above doesn't seem right.
c76d4b2a
DV
85 *
86 * @param {!Array.<Array>} rawData The raw data passed into dygraphs where
749281f8
DV
87 * rawData[i] = [x,ySeries1,...,ySeriesN].
88 * @param {!number} seriesIndex Index of the series to extract. All other
89 * series should be ignored.
90 * @param {!DygraphOptions} options Dygraph options.
91 * @return {Array.<[!number,?number,?]>} The series in the unified data format
c76d4b2a 92 * where series[i] = [x,y,{extras}].
749281f8
DV
93 */
94handler.prototype.extractSeries = function(rawData, seriesIndex, options) {
95};
a49c164a 96
749281f8 97/**
ad7785b8
AV
98 * Converts a series to a Point array. The resulting point array must be
99 * returned in increasing order of idx property.
c76d4b2a
DV
100 *
101 * @param {!Array.<[!number,?number,?]>} series The series in the unified
749281f8
DV
102 * data format where series[i] = [x,y,{extras}].
103 * @param {!string} setName Name of the series.
104 * @param {!number} boundaryIdStart Index offset of the first point, equal to the
105 * number of skipped points left of the date window minimum (if any).
106 * @return {!Array.<Dygraph.PointType>} List of points for this series.
107 */
108handler.prototype.seriesToPoints = function(series, setName, boundaryIdStart) {
109 // TODO(bhs): these loops are a hot-spot for high-point-count charts. In
110 // fact,
111 // on chrome+linux, they are 6 times more expensive than iterating through
112 // the
113 // points and drawing the lines. The brunt of the cost comes from allocating
114 // the |point| structures.
115 var points = [];
116 for ( var i = 0; i < series.length; ++i) {
117 var item = series[i];
118 var yraw = item[1];
66c95356 119 var yval = yraw === null ? null : handler.parseFloat(yraw);
749281f8
DV
120 var point = {
121 x : NaN,
122 y : NaN,
66c95356 123 xval : handler.parseFloat(item[0]),
749281f8
DV
124 yval : yval,
125 name : setName, // TODO(danvk): is this really necessary?
61767ef7
JF
126 idx : i + boundaryIdStart,
127 canvasx: NaN, // add these so we do not alter the structure later, which slows Chrome
128 canvasy: NaN,
749281f8
DV
129 };
130 points.push(point);
131 }
132 this.onPointsCreated_(series, points);
133 return points;
134};
a49c164a 135
749281f8
DV
136/**
137 * Callback called for each series after the series points have been generated
138 * which will later be used by the plotters to draw the graph.
139 * Here data may be added to the seriesPoints which is needed by the plotters.
140 * The indexes of series and points are in sync meaning the original data
141 * sample for series[i] is points[i].
c76d4b2a
DV
142 *
143 * @param {!Array.<[!number,?number,?]>} series The series in the unified
749281f8 144 * data format where series[i] = [x,y,{extras}].
c76d4b2a 145 * @param {!Array.<Dygraph.PointType>} points The corresponding points passed
749281f8
DV
146 * to the plotter.
147 * @protected
148 */
149handler.prototype.onPointsCreated_ = function(series, points) {
150};
a49c164a 151
749281f8
DV
152/**
153 * Calculates the rolling average of a data set.
c76d4b2a
DV
154 *
155 * @param {!Array.<[!number,?number,?]>} series The series in the unified
749281f8
DV
156 * data format where series[i] = [x,y,{extras}].
157 * @param {!number} rollPeriod The number of points over which to average the data
158 * @param {!DygraphOptions} options The dygraph options.
749281f8
DV
159 * @return {!Array.<[!number,?number,?]>} the rolled series.
160 */
161handler.prototype.rollingAverage = function(series, rollPeriod, options) {
162};
a49c164a 163
749281f8
DV
164/**
165 * Computes the range of the data series (including confidence intervals).
c76d4b2a
DV
166 *
167 * @param {!Array.<[!number,?number,?]>} series The series in the unified
749281f8 168 * data format where series[i] = [x, y, {extras}].
c76d4b2a 169 * @param {!Array.<number>} dateWindow The x-value range to display with
749281f8
DV
170 * the format: [min, max].
171 * @param {!DygraphOptions} options The dygraph options.
172 * @return {Array.<number>} The low and high extremes of the series in the
173 * given window with the format: [low, high].
174 */
175handler.prototype.getExtremeYValues = function(series, dateWindow, options) {
176};
a49c164a 177
749281f8
DV
178/**
179 * Callback called for each series after the layouting data has been
180 * calculated before the series is drawn. Here normalized positioning data
181 * should be calculated for the extras of each point.
c76d4b2a
DV
182 *
183 * @param {!Array.<Dygraph.PointType>} points The points passed to
749281f8
DV
184 * the plotter.
185 * @param {!Object} axis The axis on which the series will be plotted.
186 * @param {!boolean} logscale Weather or not to use a logscale.
187 */
188handler.prototype.onLineEvaluated = function(points, axis, logscale) {
189};
a49c164a 190
749281f8 191/**
66c95356
DV
192 * Optimized replacement for parseFloat, which was way too slow when almost
193 * all values were type number, with few edge cases, none of which were strings.
194 * @param {?number} val
195 * @return {number}
20eac9a9 196 * @protected
66c95356
DV
197 */
198handler.parseFloat = function(val) {
199 // parseFloat(null) is NaN
200 if (val === null) {
201 return NaN;
202 }
203
204 // Assume it's a number or NaN. If it's something else, I'll be shocked.
205 return val;
206};
207
6ecc0739 208export default DygraphDataHandler;