1 | /**
|
2 | * @license
|
3 | * Copyright 2013 David Eberlein (david.eberlein@ch.sauter-bc.com)
|
4 | * MIT-licenced: https://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)
|
10 | *
|
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
|
15 | * the DataHandler takes care of the data format specific jobs.
|
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).
|
21 | *
|
22 | *
|
23 | * The unified data format returend by each handler is defined as so:
|
24 | * series[n][point] = [x,y,(extras)]
|
25 | *
|
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.
|
30 | *
|
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
|
34 | * any type.
|
35 | *
|
36 | * In practice this might look something like this:
|
37 | * default: [x, yVal]
|
38 | * errorBar / customBar: [x, yVal, [yTopVariance, yBottomVariance] ]
|
39 | *
|
40 | */
|
41 | /*global Dygraph:false */
|
42 | /*global DygraphLayout:false */
|
43 |
|
44 | ;
|
45 |
|
46 | /**
|
47 | *
|
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
|
51 | * @constructor
|
52 | */
|
53 | var DygraphDataHandler = function () {
|
54 | };
|
55 |
|
56 | var handler = DygraphDataHandler;
|
57 |
|
58 | /**
|
59 | * X-value array index constant for unified data samples.
|
60 | * @const
|
61 | * @type {number}
|
62 | */
|
63 | handler.X = 0;
|
64 |
|
65 | /**
|
66 | * Y-value array index constant for unified data samples.
|
67 | * @const
|
68 | * @type {number}
|
69 | */
|
70 | handler.Y = 1;
|
71 |
|
72 | /**
|
73 | * Extras-value array index constant for unified data samples.
|
74 | * @const
|
75 | * @type {number}
|
76 | */
|
77 | handler.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.
|
85 | *
|
86 | * @param {!Array.<Array>} rawData The raw data passed into dygraphs where
|
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
|
92 | * where series[i] = [x,y,{extras}].
|
93 | */
|
94 | handler.prototype.extractSeries = function(rawData, seriesIndex, options) {
|
95 | };
|
96 |
|
97 | /**
|
98 | * Converts a series to a Point array. The resulting point array must be
|
99 | * returned in increasing order of idx property.
|
100 | *
|
101 | * @param {!Array.<[!number,?number,?]>} series The series in the unified
|
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 | */
|
108 | handler.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];
|
119 | var yval = yraw === null ? null : handler.parseFloat(yraw);
|
120 | var point = {
|
121 | x : NaN,
|
122 | y : NaN,
|
123 | xval : handler.parseFloat(item[0]),
|
124 | yval : yval,
|
125 | name : setName, // TODO(danvk): is this really necessary?
|
126 | idx : i + boundaryIdStart,
|
127 | canvasx: NaN, // add these so we do not alter the structure later, which slows Chrome
|
128 | canvasy: NaN,
|
129 | };
|
130 | points.push(point);
|
131 | }
|
132 | this.onPointsCreated_(series, points);
|
133 | return points;
|
134 | };
|
135 |
|
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].
|
142 | *
|
143 | * @param {!Array.<[!number,?number,?]>} series The series in the unified
|
144 | * data format where series[i] = [x,y,{extras}].
|
145 | * @param {!Array.<Dygraph.PointType>} points The corresponding points passed
|
146 | * to the plotter.
|
147 | * @protected
|
148 | */
|
149 | handler.prototype.onPointsCreated_ = function(series, points) {
|
150 | };
|
151 |
|
152 | /**
|
153 | * Calculates the rolling average of a data set.
|
154 | *
|
155 | * @param {!Array.<[!number,?number,?]>} series The series in the unified
|
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.
|
159 | * @param {!number} seriesIndex Index of the series this was extracted from.
|
160 | * @return {!Array.<[!number,?number,?]>} the rolled series.
|
161 | */
|
162 | handler.prototype.rollingAverage = function(series, rollPeriod, options, seriesIndex) {
|
163 | };
|
164 |
|
165 | /**
|
166 | * Computes the range of the data series (including confidence intervals).
|
167 | *
|
168 | * @param {!Array.<[!number,?number,?]>} series The series in the unified
|
169 | * data format where series[i] = [x, y, {extras}].
|
170 | * @param {!Array.<number>} dateWindow The x-value range to display with
|
171 | * the format: [min, max].
|
172 | * @param {boolean} stepPlot Whether the stepPlot option is set.
|
173 | * @return {Array.<number>} The low and high extremes of the series in the
|
174 | * given window with the format: [low, high].
|
175 | */
|
176 | handler.prototype.getExtremeYValues = function(series, dateWindow, stepPlot) {
|
177 | };
|
178 |
|
179 | /**
|
180 | * Callback called for each series after the layouting data has been
|
181 | * calculated before the series is drawn. Here normalized positioning data
|
182 | * should be calculated for the extras of each point.
|
183 | *
|
184 | * @param {!Array.<Dygraph.PointType>} points The points passed to
|
185 | * the plotter.
|
186 | * @param {!Object} axis The axis on which the series will be plotted.
|
187 | * @param {!boolean} logscale Whether or not to use a logscale.
|
188 | */
|
189 | handler.prototype.onLineEvaluated = function(points, axis, logscale) {
|
190 | };
|
191 |
|
192 | /**
|
193 | * Optimized replacement for parseFloat, which was way too slow when almost
|
194 | * all values were type number, with few edge cases, none of which were strings.
|
195 | * @param {?number} val
|
196 | * @return {number}
|
197 | * @protected
|
198 | */
|
199 | handler.parseFloat = function(val) {
|
200 | // parseFloat(null) is NaN
|
201 | if (val === null) {
|
202 | return NaN;
|
203 | }
|
204 |
|
205 | // Assume it's a number or NaN. If it's something else, I'll be shocked.
|
206 | return val;
|
207 | };
|
208 |
|
209 | export default DygraphDataHandler;
|