Merge pull request #673 from danvk/track-code-size
[dygraphs.git] / auto_tests / tests / range_selector.js
1 // Copyright 2011 Google Inc. All Rights Reserved.
2
3 /**
4 * @fileoverview Regression tests for range selector.
5 * @author paul.eric.felix@gmail.com (Paul Felix)
6 */
7 describe("range-selector", function() {
8
9 var restoreConsole;
10 var logs = {};
11 beforeEach(function() {
12 document.body.innerHTML = "<div id='graph'></div>";
13 restoreConsole = Util.captureConsole(logs);
14 });
15
16 afterEach(function() {
17 restoreConsole();
18 });
19
20 it('testRangeSelector', function() {
21 var opts = {
22 width: 480,
23 height: 320,
24 showRangeSelector: true,
25 labels: ['X', 'Y']
26 };
27 var data = [
28 [1, 10],
29 [2, 15],
30 [3, 10],
31 [4, 15],
32 [5, 10],
33 [6, 15],
34 [7, 10],
35 [8, 15],
36 [9, 10]
37 ];
38 var graph = document.getElementById("graph");
39 var g = new Dygraph(graph, data, opts);
40 assertGraphExistence(g, graph);
41 });
42
43 it('testRangeSelectorWithErrorBars', function() {
44 var opts = {
45 width: 480,
46 height: 320,
47 errorBars: true,
48 showRangeSelector: true,
49 labels: ['X', 'Y']
50 };
51 var data = [
52 [1, [10, 10]],
53 [2, [15, 10]],
54 [3, [10, 10]],
55 [4, [15, 10]],
56 [5, [10, 10]],
57 [6, [15, 20]],
58 [7, [10, 20]],
59 [8, [15, 20]],
60 [9, [10, 20]]
61 ];
62 var graph = document.getElementById("graph");
63 var g = new Dygraph(graph, data, opts);
64 assertGraphExistence(g, graph);
65 });
66
67 it('testRangeSelectorWithCustomBars', function() {
68 var opts = {
69 width: 480,
70 height: 320,
71 customBars: true,
72 showRangeSelector: true,
73 labels: ['X', 'Y']
74 };
75 var data = [
76 [1, [10, 10, 100]],
77 [2, [15, 20, 110]],
78 [3, [10, 30, 100]],
79 [4, [15, 40, 110]],
80 [5, [10, 120, 100]],
81 [6, [15, 50, 110]],
82 [7, [10, 70, 100]],
83 [8, [15, 90, 110]],
84 [9, [10, 50, 100]]
85 ];
86 var graph = document.getElementById("graph");
87 var g = new Dygraph(graph, data, opts);
88 assertGraphExistence(g, graph);
89 });
90
91 it('testRangeSelectorWithLogScale', function() {
92 var opts = {
93 width: 480,
94 height: 320,
95 logscale: true,
96 showRangeSelector: true,
97 labels: ['X', 'Y']
98 };
99 var data = [
100 [1, 10],
101 [2, 15],
102 [3, 10],
103 [4, 15],
104 [5, 10],
105 [6, 15],
106 [7, 10],
107 [8, 15],
108 [9, 10]
109 ];
110 var graph = document.getElementById("graph");
111 var g = new Dygraph(graph, data, opts);
112 assertGraphExistence(g, graph);
113 });
114
115 it('testRangeSelectorOptions', function() {
116 var opts = {
117 width: 480,
118 height: 320,
119 showRangeSelector: true,
120 rangeSelectorHeight: 30,
121 rangeSelectorPlotFillColor: 'lightyellow',
122 rangeSelectorPlotFillGradientColor: 'rgba(200, 200, 42, 10)',
123 labels: ['X', 'Y']
124 };
125 var data = [
126 [1, 10],
127 [2, 15],
128 [3, 10],
129 [4, 15],
130 [5, 10],
131 [6, 15],
132 [7, 10],
133 [8, 15],
134 [9, 10]
135 ];
136 var graph = document.getElementById("graph");
137 var g = new Dygraph(graph, data, opts);
138 assertGraphExistence(g, graph);
139 });
140
141 it('testAdditionalRangeSelectorOptions', function() {
142 var opts = {
143 width: 480,
144 height: 320,
145 showRangeSelector: true,
146 rangeSelectorHeight: 30,
147 rangeSelectorBackgroundStrokeColor: 'blue',
148 rangeSelectorBackgroundLineWidth: 3,
149 rangeSelectorPlotLineWidth: 0.5,
150 rangeSelectorForegroundStrokeColor: 'red',
151 rangeSelectorForegroundLineWidth: 2,
152 rangeSelectorAlpha: 0.8,
153 labels: ['X', 'Y']
154 };
155 var data = [
156 [1, 10],
157 [2, 15],
158 [3, 10],
159 [4, 15],
160 [5, 10],
161 [6, 15],
162 [7, 10],
163 [8, 15],
164 [9, 10]
165 ];
166 var graph = document.getElementById("graph");
167 var g = new Dygraph(graph, data, opts);
168 assertGraphExistence(g, graph);
169 });
170
171 it('testRangeSelectorEnablingAfterCreation', function() {
172 var opts = {
173 width: 480,
174 height: 320,
175 labels: ['X', 'Y']
176 };
177 var data = [
178 [1, 10],
179 [2, 15],
180 [3, 10],
181 [4, 15],
182 [5, 10],
183 [6, 15],
184 [7, 10],
185 [8, 15],
186 [9, 10]
187 ];
188 var graph = document.getElementById("graph");
189 var g = new Dygraph(graph, data, opts);
190 var initialChartHeight = g.getArea().h;
191 g.updateOptions({showRangeSelector: true});
192 assertGraphExistence(g, graph);
193 assert(g.getArea().h < initialChartHeight); // range selector shown
194
195 g.updateOptions({showRangeSelector: false});
196 assert.equal(g.getArea().h, initialChartHeight); // range selector hidden
197 });
198
199 // The animatedZooms option does not work with the range selector. Make sure it gets turned off.
200 it('testRangeSelectorWithAnimatedZoomsOption', function() {
201 var opts = {
202 width: 480,
203 height: 320,
204 showRangeSelector: true,
205 animatedZooms: true,
206 labels: ['X', 'Y']
207 };
208 var data = [
209 [1, 10],
210 [2, 15],
211 [3, 10],
212 [4, 15],
213 [5, 10],
214 [6, 15],
215 [7, 10],
216 [8, 15],
217 [9, 10]
218 ];
219 var graph = document.getElementById("graph");
220 var g = new Dygraph(graph, data, opts);
221 assertGraphExistence(g, graph);
222 assert.isFalse(g.getOption('animatedZooms'));
223 assert.deepEqual(logs, {
224 log: [], error: [],
225 warn: ["Animated zooms and range selector are not compatible; disabling animatedZooms."]
226 });
227 });
228
229 it('testRangeSelectorWithAnimatedZoomsOption2', function() {
230 var opts = {
231 width: 480,
232 height: 320,
233 animatedZooms: true,
234 labels: ['X', 'Y']
235 };
236 var data = [
237 [1, 10],
238 [2, 15],
239 [3, 10],
240 [4, 15],
241 [5, 10],
242 [6, 15],
243 [7, 10],
244 [8, 15],
245 [9, 10]
246 ];
247 var graph = document.getElementById("graph");
248 var g = new Dygraph(graph, data, opts);
249 g.updateOptions({showRangeSelector: true});
250 assertGraphExistence(g, graph);
251 assert.isFalse(g.getOption('animatedZooms'));
252 assert.deepEqual(logs, {
253 log: [], error: [],
254 warn: ["Animated zooms and range selector are not compatible; disabling animatedZooms."]
255 });
256 });
257
258 it('testRangeSelectorInteraction', function() {
259 var opts = {
260 width: 480,
261 height: 320,
262 showRangeSelector: true,
263 labels: ['X', 'Y']
264 };
265 var data = [
266 [1, 10],
267 [2, 15],
268 [3, 10],
269 [4, 15],
270 [5, 10],
271 [6, 15],
272 [7, 10],
273 [8, 15],
274 [9, 10]
275 ];
276 var graph = document.getElementById("graph");
277 var g = new Dygraph(graph, data, opts);
278 assertGraphExistence(g, graph);
279 var zoomhandles = graph.getElementsByClassName('dygraph-rangesel-zoomhandle');
280
281 // Move left zoomhandle in
282 var xRange = g.xAxisRange().slice();
283
284 var mouseDownEvent = DygraphOps.createEvent({
285 type : 'dragstart',
286 detail: 1,
287 clientX : 0,
288 clientY : 0
289 });
290 zoomhandles[0].dispatchEvent(mouseDownEvent);
291
292 var mouseMoveEvent = DygraphOps.createEvent({
293 type : 'mousemove',
294 clientX : 20,
295 clientY : 20
296 });
297 zoomhandles[0].dispatchEvent(mouseMoveEvent);
298
299 var mouseUpEvent = DygraphOps.createEvent({
300 type : 'mouseup',
301 detail: 1,
302 clientX : 20,
303 clientY : 20
304 });
305 zoomhandles[0].dispatchEvent(mouseUpEvent);
306
307 var newXRange = g.xAxisRange().slice();
308 assert(newXRange[0] > xRange[0], 'left zoomhandle should have moved: '+newXRange[0]+'>'+xRange[0]);
309 assert.equal(xRange[1], newXRange[1], 'right zoomhandle should not have moved');
310
311 // Move right zoomhandle in
312 xRange = newXRange;
313
314 mouseDownEvent = DygraphOps.createEvent({
315 type : 'dragstart',
316 detail: 1,
317 clientX : 100,
318 clientY : 100
319 });
320 zoomhandles[1].dispatchEvent(mouseDownEvent);
321
322 mouseMoveEvent = DygraphOps.createEvent({
323 type : 'mousemove',
324 clientX : 80,
325 clientY : 80
326 });
327 zoomhandles[1].dispatchEvent(mouseMoveEvent);
328
329 mouseUpEvent = DygraphOps.createEvent({
330 type : 'mouseup',
331 detail: 1,
332 clientX : 80,
333 clientY : 80
334 });
335 zoomhandles[1].dispatchEvent(mouseUpEvent);
336
337 var newXRange = g.xAxisRange().slice();
338 assert(newXRange[1] < xRange[1], 'right zoomhandle should have moved: '+newXRange[1]+'<'+xRange[1]);
339 assert.equal(xRange[0], newXRange[0], 'left zoomhandle should not have moved');
340
341 // Pan left
342 xRange = newXRange;
343 var fgcanvas = graph.getElementsByClassName('dygraph-rangesel-fgcanvas')[0];
344 var x = parseInt(zoomhandles[0].style.left) + 20;
345 var y = parseInt(zoomhandles[0].style.top);
346
347 mouseDownEvent = DygraphOps.createEvent({
348 type : 'mousedown',
349 detail: 1,
350 clientX : x,
351 clientY : y
352 });
353 fgcanvas.dispatchEvent(mouseDownEvent);
354
355 x -= 10;
356
357 mouseMoveEvent = DygraphOps.createEvent({
358 type : 'mousemove',
359 clientX : x,
360 clientY : y
361 });
362 fgcanvas.dispatchEvent(mouseMoveEvent);
363
364 mouseUpEvent = DygraphOps.createEvent({
365 type : 'mouseup',
366 detail: 1,
367 clientX : x,
368 clientY : y
369 });
370 fgcanvas.dispatchEvent(mouseUpEvent);
371
372 var newXRange = g.xAxisRange().slice();
373 assert(newXRange[0] < xRange[0], newXRange[0]+'<'+xRange[0]);
374 assert(newXRange[1] < xRange[1], newXRange[1]+'<'+xRange[1]);
375 });
376
377
378 it('testRangeSelectorPositionIfXAxisNotDrawn', function() {
379 var opts = {
380 width: 480,
381 height: 100,
382 xAxisHeight: 30,
383 axes : { x : { drawAxis: false }},
384 showRangeSelector: true,
385 rangeSelectorHeight: 30,
386 labels: ['X', 'Y']
387 };
388 var data = [
389 [0, 1],
390 [10, 1]
391 ];
392 var graph = document.getElementById("graph");
393 var g = new Dygraph(graph, data, opts);
394
395 //assert, that the range selector is at top position 70 since the 30px of the
396 // xAxis shouldn't be reserved since it isn't drawn.
397 assertGraphExistence(g, graph);
398 var bgcanvas = graph.getElementsByClassName('dygraph-rangesel-bgcanvas')[0];
399 assert.equal("70px", bgcanvas.style.top, "Range selector is not at the expected position.");
400 var fgcanvas = graph.getElementsByClassName('dygraph-rangesel-fgcanvas')[0];
401 assert.equal("70px", fgcanvas.style.top, "Range selector is not at the expected position.");
402 });
403
404 it('testMiniPlotDrawn', function() {
405 // Install Proxy to track canvas calls.
406 var origFunc = Dygraph.getContext;
407 var miniHtx;
408 Dygraph.getContext = function(canvas) {
409 if (canvas.className != 'dygraph-rangesel-bgcanvas') {
410 return origFunc(canvas);
411 }
412 miniHtx = new Proxy(origFunc(canvas));
413 return miniHtx;
414 };
415
416 var opts = {
417 width: 480,
418 height: 100,
419 xAxisHeight: 30,
420 axes : { x : { drawAxis: false }},
421 showRangeSelector: true,
422 rangeSelectorHeight: 30,
423 rangeSelectorPlotStrokeColor: '#ff0000',
424 labels: ['X', 'Y']
425 };
426 var data = [
427 [0, 1],
428 [5, 4],
429 [10, 8]
430 ];
431 var graph = document.getElementById("graph");
432 var g = new Dygraph(graph, data, opts);
433
434 // TODO(danvk): more precise tests.
435 assert.isNotNull(miniHtx);
436 assert.isTrue(0 < CanvasAssertions.numLinesDrawn(miniHtx, '#ff0000'));
437
438 Dygraph.getContext = origFunc;
439 });
440
441 // Tests data computation for the mini plot with a single series.
442 it('testSingleCombinedSeries', function() {
443 var opts = {
444 showRangeSelector: true,
445 labels: ['X', 'Y1']
446 };
447 var data = [
448 [0, 1],
449 [5, 4],
450 [10, 8]
451 ];
452 var graph = document.getElementById("graph");
453 var g = new Dygraph(graph, data, opts);
454
455 var rangeSelector = g.getPluginInstance_(Dygraph.Plugins.RangeSelector);
456 assert.isNotNull(rangeSelector);
457
458 var combinedSeries = rangeSelector.computeCombinedSeriesAndLimits_();
459 assert.deepEqual({
460 yMin: 1 - 7 * 0.25, // 25% padding
461 yMax: 8 + 7 * 0.25,
462 data: [
463 [0, 1],
464 [5, 4],
465 [10, 8]
466 ]
467 }, combinedSeries);
468 });
469
470
471 // Tests that multiple series are averaged for the miniplot.
472 it('testCombinedSeries', function() {
473 var opts = {
474 showRangeSelector: true,
475 labels: ['X', 'Y1', 'Y2']
476 };
477 var data = [
478 [0, 1, 3], // average = 2
479 [5, 4, 6], // average = 5
480 [10, 7, 9] // average = 8
481 ];
482 var graph = document.getElementById("graph");
483 var g = new Dygraph(graph, data, opts);
484
485 var rangeSelector = g.getPluginInstance_(Dygraph.Plugins.RangeSelector);
486 assert.isNotNull(rangeSelector);
487
488 var combinedSeries = rangeSelector.computeCombinedSeriesAndLimits_();
489 assert.deepEqual({
490 yMin: 2 - 6 * 0.25, // 25% padding on combined series range.
491 yMax: 8 + 6 * 0.25,
492 data: [
493 [0, 2],
494 [5, 5],
495 [10, 8]
496 ]
497 }, combinedSeries);
498 });
499
500 // Tests selection of a specific series to average for the mini plot.
501 it('testSelectedCombinedSeries', function() {
502 var opts = {
503 showRangeSelector: true,
504 labels: ['X', 'Y1', 'Y2', 'Y3', 'Y4'],
505 series: {
506 'Y1': { showInRangeSelector: true },
507 'Y3': { showInRangeSelector: true }
508 }
509 };
510 var data = [
511 [0, 5, 8, 13, 21], // average (first and third) = 9
512 [5, 1, 3, 7, 14], // average (first and third) = 4
513 [10, 0, 19, 10, 6] // average (first and third) = 5
514 ];
515 var graph = document.getElementById("graph");
516 var g = new Dygraph(graph, data, opts);
517
518 var rangeSelector = g.getPluginInstance_(Dygraph.Plugins.RangeSelector);
519 assert.isNotNull(rangeSelector);
520
521 var combinedSeries = rangeSelector.computeCombinedSeriesAndLimits_();
522 assert.deepEqual({
523 yMin: 4 - 5 * 0.25, // 25% padding on combined series range.
524 yMax: 9 + 5 * 0.25,
525 data: [
526 [0, 9],
527 [5, 4],
528 [10, 5]
529 ]
530 }, combinedSeries);
531 });
532
533 // Tests data computation for the mini plot with a single error bar series.
534 it('testSingleCombinedSeriesCustomBars', function() {
535 var opts = {
536 customBars: true,
537 showRangeSelector: true,
538 labels: ['X', 'Y1']
539 };
540 var data = [
541 [0, [0, 1, 2]], // [low, value, high]
542 [5, [1, 4, 5]],
543 [10, [7, 8, 9]]
544 ];
545 var graph = document.getElementById("graph");
546 var g = new Dygraph(graph, data, opts);
547
548 var rangeSelector = g.getPluginInstance_(Dygraph.Plugins.RangeSelector);
549 assert.isNotNull(rangeSelector);
550
551 var combinedSeries = rangeSelector.computeCombinedSeriesAndLimits_();
552 assert.deepEqual({
553 yMin: 1 - 7 * 0.25, // 25% padding
554 yMax: 8 + 7 * 0.25,
555 data: [
556 [0, 1],
557 [5, 4],
558 [10, 8]
559 ]
560 }, combinedSeries);
561 });
562
563 it('testSingleCombinedSeriesErrorBars', function() {
564 var opts = {
565 errorBars: true,
566 showRangeSelector: true,
567 labels: ['X', 'Y1']
568 };
569 var data = [
570 [0, [1, 1]], // [value, standard deviation]
571 [5, [4, 2]],
572 [10, [8, 1]]
573 ];
574 var graph = document.getElementById("graph");
575 var g = new Dygraph(graph, data, opts);
576
577 var rangeSelector = g.getPluginInstance_(Dygraph.Plugins.RangeSelector);
578 assert.isNotNull(rangeSelector);
579
580 var combinedSeries = rangeSelector.computeCombinedSeriesAndLimits_();
581 assert.deepEqual({
582 yMin: 1 - 7 * 0.25, // 25% padding
583 yMax: 8 + 7 * 0.25,
584 data: [
585 [0, 1],
586 [5, 4],
587 [10, 8]
588 ]
589 }, combinedSeries);
590 });
591
592 // Tests data computation for the mini plot with two custom bar series.
593 it('testTwoCombinedSeriesCustomBars', function() {
594 var opts = {
595 customBars: true,
596 showRangeSelector: true,
597 labels: ['X', 'Y1', 'Y2']
598 };
599 var data = [
600 [0, [0, 1, 2], [4, 5, 6]], // [low, value, high], avg_val = 3
601 [5, [1, 4, 5], [5, 8, 9]], // avg_val = 6
602 [10, [7, 8, 9], [11, 12, 13]] // avg_val = 10
603 ];
604 var graph = document.getElementById("graph");
605 var g = new Dygraph(graph, data, opts);
606
607 var rangeSelector = g.getPluginInstance_(Dygraph.Plugins.RangeSelector);
608 assert.isNotNull(rangeSelector);
609
610 var combinedSeries = rangeSelector.computeCombinedSeriesAndLimits_();
611 assert.deepEqual({
612 yMin: 3 - 7 * 0.25, // 25% padding
613 yMax: 10 + 7 * 0.25,
614 data: [
615 [0, 3],
616 [5, 6],
617 [10, 10]
618 ]
619 }, combinedSeries);
620 });
621
622
623 var assertGraphExistence = function(g, graph) {
624 assert.isNotNull(g);
625 var zoomhandles = graph.getElementsByClassName('dygraph-rangesel-zoomhandle');
626 assert.equal(2, zoomhandles.length);
627 var bgcanvas = graph.getElementsByClassName('dygraph-rangesel-bgcanvas');
628 assert.equal(1, bgcanvas.length);
629 var fgcanvas = graph.getElementsByClassName('dygraph-rangesel-fgcanvas');
630 assert.equal(1, fgcanvas.length);
631 };
632
633 });