1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 | "use strict";
|
14 |
|
15 | import * as utils from './dygraph-utils';
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 | var DygraphLayout = function(dygraph) {
|
34 | this.dygraph_ = dygraph;
|
35 | |
36 |
|
37 |
|
38 |
|
39 |
|
40 |
|
41 |
|
42 |
|
43 |
|
44 |
|
45 |
|
46 | this.points = [];
|
47 | this.setNames = [];
|
48 | this.annotations = [];
|
49 | this.yAxes_ = null;
|
50 |
|
51 |
|
52 |
|
53 | this.xTicks_ = null;
|
54 | this.yTicks_ = null;
|
55 | };
|
56 |
|
57 |
|
58 |
|
59 |
|
60 |
|
61 |
|
62 |
|
63 | DygraphLayout.prototype.addDataset = function(setname, set_xy) {
|
64 | this.points.push(set_xy);
|
65 | this.setNames.push(setname);
|
66 | };
|
67 |
|
68 |
|
69 |
|
70 |
|
71 |
|
72 |
|
73 |
|
74 | DygraphLayout.prototype.getPlotArea = function() {
|
75 | return this.area_;
|
76 | };
|
77 |
|
78 |
|
79 |
|
80 |
|
81 | DygraphLayout.prototype.computePlotArea = function() {
|
82 | var area = {
|
83 |
|
84 | x: 0,
|
85 | y: 0
|
86 | };
|
87 |
|
88 | area.w = this.dygraph_.width_ - area.x - this.dygraph_.getOption('rightGap');
|
89 | area.h = this.dygraph_.height_;
|
90 |
|
91 |
|
92 | var e = {
|
93 | chart_div: this.dygraph_.graphDiv,
|
94 | reserveSpaceLeft: function(px) {
|
95 | var r = {
|
96 | x: area.x,
|
97 | y: area.y,
|
98 | w: px,
|
99 | h: area.h
|
100 | };
|
101 | area.x += px;
|
102 | area.w -= px;
|
103 | return r;
|
104 | },
|
105 | reserveSpaceRight: function(px) {
|
106 | var r = {
|
107 | x: area.x + area.w - px,
|
108 | y: area.y,
|
109 | w: px,
|
110 | h: area.h
|
111 | };
|
112 | area.w -= px;
|
113 | return r;
|
114 | },
|
115 | reserveSpaceTop: function(px) {
|
116 | var r = {
|
117 | x: area.x,
|
118 | y: area.y,
|
119 | w: area.w,
|
120 | h: px
|
121 | };
|
122 | area.y += px;
|
123 | area.h -= px;
|
124 | return r;
|
125 | },
|
126 | reserveSpaceBottom: function(px) {
|
127 | var r = {
|
128 | x: area.x,
|
129 | y: area.y + area.h - px,
|
130 | w: area.w,
|
131 | h: px
|
132 | };
|
133 | area.h -= px;
|
134 | return r;
|
135 | },
|
136 | chartRect: function() {
|
137 | return {x:area.x, y:area.y, w:area.w, h:area.h};
|
138 | }
|
139 | };
|
140 | this.dygraph_.cascadeEvents_('layout', e);
|
141 |
|
142 | this.area_ = area;
|
143 | };
|
144 |
|
145 | DygraphLayout.prototype.setAnnotations = function(ann) {
|
146 |
|
147 |
|
148 | this.annotations = [];
|
149 | var parse = this.dygraph_.getOption('xValueParser') || function(x) { return x; };
|
150 | for (var i = 0; i < ann.length; i++) {
|
151 | var a = {};
|
152 | if (!ann[i].xval && ann[i].x === undefined) {
|
153 | console.error("Annotations must have an 'x' property");
|
154 | return;
|
155 | }
|
156 | if (ann[i].icon &&
|
157 | !(ann[i].hasOwnProperty('width') &&
|
158 | ann[i].hasOwnProperty('height'))) {
|
159 | console.error("Must set width and height when setting " +
|
160 | "annotation.icon property");
|
161 | return;
|
162 | }
|
163 | utils.update(a, ann[i]);
|
164 | if (!a.xval) a.xval = parse(a.x);
|
165 | this.annotations.push(a);
|
166 | }
|
167 | };
|
168 |
|
169 | DygraphLayout.prototype.setXTicks = function(xTicks) {
|
170 | this.xTicks_ = xTicks;
|
171 | };
|
172 |
|
173 |
|
174 | DygraphLayout.prototype.setYAxes = function (yAxes) {
|
175 | this.yAxes_ = yAxes;
|
176 | };
|
177 |
|
178 | DygraphLayout.prototype.evaluate = function() {
|
179 | this._xAxis = {};
|
180 | this._evaluateLimits();
|
181 | this._evaluateLineCharts();
|
182 | this._evaluateLineTicks();
|
183 | this._evaluateAnnotations();
|
184 | };
|
185 |
|
186 | DygraphLayout.prototype._evaluateLimits = function() {
|
187 | var xlimits = this.dygraph_.xAxisRange();
|
188 | this._xAxis.minval = xlimits[0];
|
189 | this._xAxis.maxval = xlimits[1];
|
190 | var xrange = xlimits[1] - xlimits[0];
|
191 | this._xAxis.scale = (xrange !== 0 ? 1 / xrange : 1.0);
|
192 |
|
193 | if (this.dygraph_.getOptionForAxis("logscale", 'x')) {
|
194 | this._xAxis.xlogrange = utils.log10(this._xAxis.maxval) - utils.log10(this._xAxis.minval);
|
195 | this._xAxis.xlogscale = (this._xAxis.xlogrange !== 0 ? 1.0 / this._xAxis.xlogrange : 1.0);
|
196 | }
|
197 | for (var i = 0; i < this.yAxes_.length; i++) {
|
198 | var axis = this.yAxes_[i];
|
199 | axis.minyval = axis.computedValueRange[0];
|
200 | axis.maxyval = axis.computedValueRange[1];
|
201 | axis.yrange = axis.maxyval - axis.minyval;
|
202 | axis.yscale = (axis.yrange !== 0 ? 1.0 / axis.yrange : 1.0);
|
203 |
|
204 | if (this.dygraph_.getOption("logscale") || axis.logscale) {
|
205 | axis.ylogrange = utils.log10(axis.maxyval) - utils.log10(axis.minyval);
|
206 | axis.ylogscale = (axis.ylogrange !== 0 ? 1.0 / axis.ylogrange : 1.0);
|
207 | if (!isFinite(axis.ylogrange) || isNaN(axis.ylogrange)) {
|
208 | console.error('axis ' + i + ' of graph at ' + axis.g +
|
209 | ' can\'t be displayed in log scale for range [' +
|
210 | axis.minyval + ' - ' + axis.maxyval + ']');
|
211 | }
|
212 | }
|
213 | }
|
214 | };
|
215 |
|
216 | DygraphLayout.calcXNormal_ = function(value, xAxis, logscale) {
|
217 | if (logscale) {
|
218 | return ((utils.log10(value) - utils.log10(xAxis.minval)) * xAxis.xlogscale);
|
219 | } else {
|
220 | return (value - xAxis.minval) * xAxis.scale;
|
221 | }
|
222 | };
|
223 |
|
224 |
|
225 |
|
226 |
|
227 |
|
228 |
|
229 |
|
230 | DygraphLayout.calcYNormal_ = function(axis, value, logscale) {
|
231 | if (logscale) {
|
232 | var x = 1.0 - ((utils.log10(value) - utils.log10(axis.minyval)) * axis.ylogscale);
|
233 | return isFinite(x) ? x : NaN;
|
234 | } else {
|
235 | return 1.0 - ((value - axis.minyval) * axis.yscale);
|
236 | }
|
237 | };
|
238 |
|
239 | DygraphLayout.prototype._evaluateLineCharts = function() {
|
240 | var isStacked = this.dygraph_.getOption("stackedGraph");
|
241 | var isLogscaleForX = this.dygraph_.getOptionForAxis("logscale", 'x');
|
242 |
|
243 | for (var setIdx = 0; setIdx < this.points.length; setIdx++) {
|
244 | var points = this.points[setIdx];
|
245 | var setName = this.setNames[setIdx];
|
246 | var connectSeparated = this.dygraph_.getOption('connectSeparatedPoints', setName);
|
247 | var axis = this.dygraph_.axisPropertiesForSeries(setName);
|
248 |
|
249 | var logscale = this.dygraph_.attributes_.getForSeries("logscale", setName);
|
250 |
|
251 | for (var j = 0; j < points.length; j++) {
|
252 | var point = points[j];
|
253 |
|
254 |
|
255 | point.x = DygraphLayout.calcXNormal_(point.xval, this._xAxis, isLogscaleForX);
|
256 |
|
257 | var yval = point.yval;
|
258 | if (isStacked) {
|
259 | point.y_stacked = DygraphLayout.calcYNormal_(
|
260 | axis, point.yval_stacked, logscale);
|
261 | if (yval !== null && !isNaN(yval)) {
|
262 | yval = point.yval_stacked;
|
263 | }
|
264 | }
|
265 | if (yval === null) {
|
266 | yval = NaN;
|
267 | if (!connectSeparated) {
|
268 | point.yval = NaN;
|
269 | }
|
270 | }
|
271 | point.y = DygraphLayout.calcYNormal_(axis, yval, logscale);
|
272 | }
|
273 |
|
274 | this.dygraph_.dataHandler_.onLineEvaluated(points, axis, logscale);
|
275 | }
|
276 | };
|
277 |
|
278 | DygraphLayout.prototype._evaluateLineTicks = function() {
|
279 | var i, tick, label, pos, v, has_tick;
|
280 | this.xticks = [];
|
281 | for (i = 0; i < this.xTicks_.length; i++) {
|
282 | tick = this.xTicks_[i];
|
283 | label = tick.label;
|
284 | has_tick = !('label_v' in tick);
|
285 | v = has_tick ? tick.v : tick.label_v;
|
286 | pos = this.dygraph_.toPercentXCoord(v);
|
287 | if ((pos >= 0.0) && (pos < 1.0)) {
|
288 | this.xticks.push({pos, label, has_tick});
|
289 | }
|
290 | }
|
291 |
|
292 | this.yticks = [];
|
293 | for (i = 0; i < this.yAxes_.length; i++ ) {
|
294 | var axis = this.yAxes_[i];
|
295 | for (var j = 0; j < axis.ticks.length; j++) {
|
296 | tick = axis.ticks[j];
|
297 | label = tick.label;
|
298 | has_tick = !('label_v' in tick);
|
299 | v = has_tick ? tick.v : tick.label_v;
|
300 | pos = this.dygraph_.toPercentYCoord(v, i);
|
301 | if ((pos > 0.0) && (pos <= 1.0)) {
|
302 | this.yticks.push({axis: i, pos, label, has_tick});
|
303 | }
|
304 | }
|
305 | }
|
306 | };
|
307 |
|
308 | DygraphLayout.prototype._evaluateAnnotations = function() {
|
309 |
|
310 |
|
311 | var i;
|
312 | var annotations = {};
|
313 | for (i = 0; i < this.annotations.length; i++) {
|
314 | var a = this.annotations[i];
|
315 | annotations[a.xval + "," + a.series] = a;
|
316 | }
|
317 |
|
318 | this.annotated_points = [];
|
319 |
|
320 |
|
321 | if (!this.annotations || !this.annotations.length) {
|
322 | return;
|
323 | }
|
324 |
|
325 |
|
326 | for (var setIdx = 0; setIdx < this.points.length; setIdx++) {
|
327 | var points = this.points[setIdx];
|
328 | for (i = 0; i < points.length; i++) {
|
329 | var p = points[i];
|
330 | var k = p.xval + "," + p.name;
|
331 | if (k in annotations) {
|
332 | p.annotation = annotations[k];
|
333 | this.annotated_points.push(p);
|
334 |
|
335 |
|
336 | delete annotations[k];
|
337 | }
|
338 | }
|
339 | }
|
340 | };
|
341 |
|
342 |
|
343 |
|
344 |
|
345 | DygraphLayout.prototype.removeAllDatasets = function() {
|
346 | delete this.points;
|
347 | delete this.setNames;
|
348 | delete this.setPointsLengths;
|
349 | delete this.setPointsOffsets;
|
350 | this.points = [];
|
351 | this.setNames = [];
|
352 | this.setPointsLengths = [];
|
353 | this.setPointsOffsets = [];
|
354 | };
|
355 |
|
356 | export default DygraphLayout;
|