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