Merge pull request #674 from danvk/module
[dygraphs.git] / auto_tests / tests / interaction_model.js
CommitLineData
9c831431
RK
1/**
2 * @fileoverview Test cases for the interaction model.
3 *
4 * @author konigsberg@google.com (Robert Konigsbrg)
5 */
9c831431 6
e8c70e4e
DV
7import Dygraph from '../../src/dygraph';
8import DygraphInteraction from '../../src/dygraph-interaction-model';
9import DygraphOps from './DygraphOps';
9c831431 10
e8c70e4e
DV
11describe("interaction-model", function() {
12
13cleanupAfterEach();
9c831431 14
af3a17a8
RK
15var data1 = "X,Y\n" +
16 "20,-1\n" +
17 "21,0\n" +
18 "22,1\n" +
19 "23,0\n";
20
21var data2 =
65129ba8
DV
22 "X,Y\n" +
23 "1,10\n" +
24 "2,20\n" +
25 "3,30\n" +
26 "4,40\n" +
27 "5,120\n" +
28 "6,50\n" +
29 "7,70\n" +
30 "8,90\n" +
31 "9,50\n";
af3a17a8 32
9c831431
RK
33function getXLabels() {
34 var x_labels = document.getElementsByClassName("dygraph-axis-label-x");
35 var ary = [];
36 for (var i = 0; i < x_labels.length; i++) {
37 ary.push(x_labels[i].innerHTML);
38 }
39 return ary;
40}
41
89fdcedb
DV
42/*
43it('testPan', function() {
9c831431
RK
44 var originalXRange = g.xAxisRange();
45 var originalYRange = g.yAxisRange(0);
46
47 DygraphOps.dispatchMouseDown(g, xRange[0], yRange[0]);
48 DygraphOps.dispatchMouseMove(g, xRange[1], yRange[0]); // this is really necessary.
49 DygraphOps.dispatchMouseUp(g, xRange[1], yRange[0]);
50
dc910fce
DV
51 assert.closeTo(xRange, g.xAxisRange(), 0.2);
52 // assert.closeTo(originalYRange, g.yAxisRange(0), 0.2); // Not true, it's something in the middle.
9c831431
RK
53
54 var midX = (xRange[1] - xRange[0]) / 2;
55 DygraphOps.dispatchMouseDown(g, midX, yRange[0]);
56 DygraphOps.dispatchMouseMove(g, midX, yRange[1]); // this is really necessary.
57 DygraphOps.dispatchMouseUp(g, midX, yRange[1]);
58
dc910fce
DV
59 assert.closeTo(xRange, g.xAxisRange(), 0.2);
60 assert.closeTo(yRange, g.yAxisRange(0), 0.2);
89fdcedb
DV
61});
62*/
9c831431
RK
63
64/**
65 * This tests that when changing the interaction model so pan is used instead
66 * of zoom as the default behavior, a standard click method is still called.
67 */
89fdcedb 68it('testClickCallbackIsCalled', function() {
9c831431
RK
69 var clicked;
70
71 var clickCallback = function(event, x) {
72 clicked = x;
73 };
74
9c831431 75 var graph = document.getElementById("graph");
af3a17a8 76 var g = new Dygraph(graph, data1,
9c831431
RK
77 {
78 width: 100,
79 height : 100,
80 clickCallback : clickCallback
81 });
82
83 DygraphOps.dispatchMouseDown_Point(g, 10, 10);
84 DygraphOps.dispatchMouseMove_Point(g, 10, 10);
85 DygraphOps.dispatchMouseUp_Point(g, 10, 10);
86
89fdcedb
DV
87 assert.equal(20, clicked);
88});
9c831431
RK
89
90/**
91 * This tests that when changing the interaction model so pan is used instead
92 * of zoom as the default behavior, a standard click method is still called.
93 */
89fdcedb 94it('testClickCallbackIsCalledOnCustomPan', function() {
9c831431
RK
95 var clicked;
96
97 var clickCallback = function(event, x) {
98 clicked = x;
99 };
100
9c831431
RK
101 function customDown(event, g, context) {
102 context.initializeMouseDown(event, g, context);
e8c70e4e 103 DygraphInteraction.startPan(event, g, context);
9c831431
RK
104 }
105
106 function customMove(event, g, context) {
e8c70e4e 107 DygraphInteraction.movePan(event, g, context);
9c831431
RK
108 }
109
110 function customUp(event, g, context) {
e8c70e4e 111 DygraphInteraction.endPan(event, g, context);
9c831431
RK
112 }
113
114 var opts = {
115 width: 100,
116 height : 100,
117 clickCallback : clickCallback,
118 interactionModel : {
119 'mousedown' : customDown,
120 'mousemove' : customMove,
121 'mouseup' : customUp,
122 }
123 };
124
125 var graph = document.getElementById("graph");
af3a17a8 126 var g = new Dygraph(graph, data1, opts);
9c831431
RK
127
128 DygraphOps.dispatchMouseDown_Point(g, 10, 10);
129 DygraphOps.dispatchMouseMove_Point(g, 10, 10);
130 DygraphOps.dispatchMouseUp_Point(g, 10, 10);
131
89fdcedb
DV
132 assert.equal(20, clicked);
133});
9c831431 134
319d0361 135var clickAt = function(g, x, y) {
af3a17a8
RK
136 DygraphOps.dispatchMouseDown(g, x, y);
137 DygraphOps.dispatchMouseMove(g, x, y);
138 DygraphOps.dispatchMouseUp(g, x, y);
319d0361 139};
af3a17a8
RK
140
141/**
027e9e9b
DV
142 * This tests that clickCallback is still called with the nonInteractiveModel.
143 */
89fdcedb 144it('testClickCallbackIsCalledWithNonInteractiveModel', function() {
027e9e9b
DV
145 var clicked;
146
147 // TODO(danvk): also test pointClickCallback here.
148 var clickCallback = function(event, x) {
149 clicked = x;
150 };
151
152 var opts = {
153 width: 100,
154 height : 100,
155 clickCallback : clickCallback,
e8c70e4e 156 interactionModel : DygraphInteraction.nonInteractiveModel_
027e9e9b
DV
157 };
158
159 var graph = document.getElementById("graph");
160 var g = new Dygraph(graph, data1, opts);
161
162 DygraphOps.dispatchMouseDown_Point(g, 10, 10);
163 DygraphOps.dispatchMouseMove_Point(g, 10, 10);
164 DygraphOps.dispatchMouseUp_Point(g, 10, 10);
165
89fdcedb
DV
166 assert.equal(20, clicked);
167});
027e9e9b
DV
168
169/**
af3a17a8
RK
170 * A sanity test to ensure pointClickCallback is called.
171 */
89fdcedb 172it('testPointClickCallback', function() {
65129ba8
DV
173 var clicked = null;
174 var g = new Dygraph('graph', data2, {
175 pointClickCallback: function(event, point) {
af3a17a8
RK
176 clicked = point;
177 }
178 });
179
319d0361 180 clickAt(g, 4, 40);
af3a17a8 181
65129ba8 182 assert.isNotNull(clicked);
89fdcedb
DV
183 assert.equal(4, clicked.xval);
184 assert.equal(40, clicked.yval);
185});
af3a17a8
RK
186
187/**
188 * A sanity test to ensure pointClickCallback is not called when out of range.
189 */
89fdcedb 190it('testNoPointClickCallbackWhenOffPoint', function() {
af3a17a8
RK
191 var clicked;
192 var g = new Dygraph(document.getElementById("graph"), data2, {
193 pointClickCallback : function(event, point) {
194 clicked = point;
195 }
196 });
197
319d0361 198 clickAt(g, 5, 40);
af3a17a8 199
89fdcedb
DV
200 assert.isUndefined(clicked);
201});
af3a17a8
RK
202
203/**
204 * Ensures pointClickCallback circle size is taken into account.
205 */
89fdcedb 206it('testPointClickCallback_circleSize', function() {
af3a17a8 207 // TODO(konigsberg): Implement.
89fdcedb 208});
af3a17a8
RK
209
210/**
211 * Ensures that pointClickCallback is called prior to clickCallback
212 */
89fdcedb 213it('testPointClickCallbackCalledPriorToClickCallback', function() {
af3a17a8
RK
214 var counter = 0;
215 var pointClicked;
216 var clicked;
217 var g = new Dygraph(document.getElementById("graph"), data2, {
218 pointClickCallback : function(event, point) {
219 counter++;
220 pointClicked = counter;
221 },
222 clickCallback : function(event, point) {
223 counter++;
224 clicked = counter;
225 }
226 });
227
319d0361 228 clickAt(g, 4, 40);
89fdcedb
DV
229 assert.equal(1, pointClicked);
230 assert.equal(2, clicked);
231});
af3a17a8
RK
232
233/**
234 * Ensures that when there's no pointClickCallback, clicking on a point still calls
235 * clickCallback
236 */
89fdcedb 237it('testClickCallback_clickOnPoint', function() {
af3a17a8
RK
238 var clicked;
239 var g = new Dygraph(document.getElementById("graph"), data2, {
240 clickCallback : function(event, point) {
241 clicked = 1;
242 }
243 });
244
319d0361 245 clickAt(g, 4, 40);
89fdcedb
DV
246 assert.equal(1, clicked);
247});
af3a17a8 248
89fdcedb 249it('testIsZoomed_none', function() {
32566cec
RK
250 var g = new Dygraph(document.getElementById("graph"), data2, {});
251
89fdcedb
DV
252 assert.isFalse(g.isZoomed());
253 assert.isFalse(g.isZoomed("x"));
254 assert.isFalse(g.isZoomed("y"));
255});
357f7a8a 256
89fdcedb 257it('testIsZoomed_x', function() {
32566cec
RK
258 var g = new Dygraph(document.getElementById("graph"), data2, {});
259
5ee26cc1
DV
260 DygraphOps.dispatchMouseDown_Point(g, 100, 100);
261 DygraphOps.dispatchMouseMove_Point(g, 130, 100);
262 DygraphOps.dispatchMouseUp_Point(g, 130, 100);
32566cec 263
89fdcedb
DV
264 assert.isTrue(g.isZoomed());
265 assert.isTrue(g.isZoomed("x"));
266 assert.isFalse(g.isZoomed("y"));
267});
32566cec 268
89fdcedb 269it('testIsZoomed_y', function() {
32566cec
RK
270 var g = new Dygraph(document.getElementById("graph"), data2, {});
271
272 DygraphOps.dispatchMouseDown_Point(g, 10, 10);
273 DygraphOps.dispatchMouseMove_Point(g, 10, 30);
274 DygraphOps.dispatchMouseUp_Point(g, 10, 30);
275
89fdcedb
DV
276 assert.isTrue(g.isZoomed());
277 assert.isFalse(g.isZoomed("x"));
278 assert.isTrue(g.isZoomed("y"));
279});
32566cec 280
89fdcedb 281it('testIsZoomed_both', function() {
32566cec
RK
282 var g = new Dygraph(document.getElementById("graph"), data2, {});
283
284 // Zoom x axis
5ee26cc1
DV
285 DygraphOps.dispatchMouseDown_Point(g, 100, 100);
286 DygraphOps.dispatchMouseMove_Point(g, 130, 100);
287 DygraphOps.dispatchMouseUp_Point(g, 130, 100);
32566cec
RK
288
289 // Now zoom y axis
5ee26cc1
DV
290 DygraphOps.dispatchMouseDown_Point(g, 100, 100);
291 DygraphOps.dispatchMouseMove_Point(g, 100, 130);
292 DygraphOps.dispatchMouseUp_Point(g, 100, 130);
32566cec
RK
293
294
89fdcedb
DV
295 assert.isTrue(g.isZoomed());
296 assert.isTrue(g.isZoomed("x"));
297 assert.isTrue(g.isZoomed("y"));
298});
32566cec 299
89fdcedb 300it('testIsZoomed_updateOptions_none', function() {
32566cec
RK
301 var g = new Dygraph(document.getElementById("graph"), data2, {});
302
303 g.updateOptions({});
304
89fdcedb
DV
305 assert.isFalse(g.isZoomed());
306 assert.isFalse(g.isZoomed("x"));
307 assert.isFalse(g.isZoomed("y"));
308});
32566cec 309
89fdcedb 310it('testIsZoomed_updateOptions_x', function() {
32566cec
RK
311 var g = new Dygraph(document.getElementById("graph"), data2, {});
312
313 g.updateOptions({dateWindow: [-.5, .3]});
89fdcedb
DV
314 assert.isTrue(g.isZoomed());
315 assert.isTrue(g.isZoomed("x"));
316 assert.isFalse(g.isZoomed("y"));
317});
32566cec 318
89fdcedb 319it('testIsZoomed_updateOptions_y', function() {
32566cec
RK
320 var g = new Dygraph(document.getElementById("graph"), data2, {});
321
322 g.updateOptions({valueRange: [1, 10]});
323
89fdcedb
DV
324 assert.isTrue(g.isZoomed());
325 assert.isFalse(g.isZoomed("x"));
326 assert.isTrue(g.isZoomed("y"));
327});
32566cec 328
89fdcedb 329it('testIsZoomed_updateOptions_both', function() {
32566cec
RK
330 var g = new Dygraph(document.getElementById("graph"), data2, {});
331
332 g.updateOptions({dateWindow: [-1, 1], valueRange: [1, 10]});
333
89fdcedb
DV
334 assert.isTrue(g.isZoomed());
335 assert.isTrue(g.isZoomed("x"));
336 assert.isTrue(g.isZoomed("y"));
337});
1357d81e
US
338
339
89fdcedb 340it('testCorrectAxisValueRangeAfterUnzoom', function() {
5ee26cc1
DV
341 var g = new Dygraph(document.getElementById("graph"),
342 data2, {
343 valueRange: [1, 50],
344 dateWindow: [1, 9],
345 animatedZooms:false
346 });
1357d81e 347
9aedaae3 348 // Zoom x axis
5ee26cc1
DV
349 DygraphOps.dispatchMouseDown_Point(g, 100, 100);
350 DygraphOps.dispatchMouseMove_Point(g, 130, 100);
351 DygraphOps.dispatchMouseUp_Point(g, 130, 100);
1357d81e 352
9aedaae3 353 // Zoom y axis
5ee26cc1
DV
354 DygraphOps.dispatchMouseDown_Point(g, 100, 100);
355 DygraphOps.dispatchMouseMove_Point(g, 100, 130);
356 DygraphOps.dispatchMouseUp_Point(g, 100, 130);
89fdcedb
DV
357 var currentYAxisRange = g.yAxisRange();
358 var currentXAxisRange = g.xAxisRange();
9aedaae3
US
359
360 //check that the range for the axis has changed
89fdcedb
DV
361 assert.notEqual(1, currentXAxisRange[0]);
362 assert.notEqual(10, currentXAxisRange[1]);
363 assert.notEqual(1, currentYAxisRange[0]);
364 assert.notEqual(50, currentYAxisRange[1]);
9aedaae3 365
f3cd243e
DV
366 // unzoom by doubleclick. This is really the order in which a browser
367 // generates events, and we depend on it.
368 DygraphOps.dispatchMouseDown_Point(g, 10, 10);
369 DygraphOps.dispatchMouseUp_Point(g, 10, 10);
370 DygraphOps.dispatchMouseDown_Point(g, 10, 10);
371 DygraphOps.dispatchMouseUp_Point(g, 10, 10);
1357d81e
US
372 DygraphOps.dispatchDoubleClick(g, null);
373
9aedaae3
US
374 // check if range for y-axis was reset to original value
375 // TODO check if range for x-axis is correct.
376 // Currently not possible because dateRange is set to null and extremes are returned
89fdcedb
DV
377 var newYAxisRange = g.yAxisRange();
378 assert.equal(1, newYAxisRange[0]);
379 assert.equal(50, newYAxisRange[1]);
380});
dbcf3e6d
DV
381
382/**
383 * Ensures pointClickCallback is called when some points along the y-axis don't
384 * exist.
385 */
89fdcedb 386it('testPointClickCallback_missingData', function() {
dbcf3e6d
DV
387
388 // There's a B-value at 2, but no A-value.
389 var data =
390 "X,A,B\n" +
391 "1,,100\n"+
392 "2,,110\n"+
393 "3,140,120\n"+
394 "4,130,110\n"+
395 "";
396
397 var clicked;
398 var g = new Dygraph(document.getElementById("graph"), data, {
399 pointClickCallback : function(event, point) {
400 clicked = point;
401 }
402 });
403
319d0361 404 clickAt(g, 2, 110);
dbcf3e6d 405
89fdcedb
DV
406 assert.equal(2, clicked.xval);
407 assert.equal(110, clicked.yval);
408});
409
bf7d192b
DV
410describe('animated zooms', function() {
411 var oldDuration;
412
413 before(function() {
414 oldDuration = Dygraph.ANIMATION_DURATION;
415 Dygraph.ANIMATION_DURATION = 100; // speed up the animation for testing
416 });
417 after(function() {
418 Dygraph.ANIMATION_DURATION = oldDuration;
419 });
420
421 it('should support animated zooms', function(done) {
422 var data =
423 "X,A,B\n" +
424 "1,120,100\n"+
425 "2,110,110\n"+
426 "3,140,120\n"+
427 "4,130,110\n";
428
429 var ranges = [];
430
431 var g = new Dygraph('graph', data, {
432 animatedZooms: true,
433 });
434
435 // updating the dateWindow does not result in an animation.
436 assert.deepEqual([1, 4], g.xAxisRange());
437 g.updateOptions({dateWindow: [2, 4]});
438 assert.deepEqual([2, 4], g.xAxisRange());
439
440 g.updateOptions({
441 // zoomCallback is called once when the animation is complete.
442 zoomCallback: function(xMin, xMax) {
443 assert.equal(1, xMin);
444 assert.equal(4, xMax);
445 assert.deepEqual([1, 4], g.xAxisRange());
446 done();
447 }
448 }, false);
449
450 // Zoom out -- resetZoom() _does_ produce an animation.
451 g.resetZoom();
452 assert.notDeepEqual([2, 4], g.xAxisRange()); // first frame is synchronous
453 assert.notDeepEqual([1, 4], g.xAxisRange());
454
455 // at this point control flow goes up to zoomCallback
456 });
457
458});
459
b56f033a
KB
460//bulk copied from "testCorrectAxisValueRangeAfterUnzoom"
461//tests if the xRangePad is taken into account after unzoom.
1d2021b5
K
462it('testCorrectAxisPaddingAfterUnzoom', function() {
463 var g = new Dygraph(document.getElementById("graph"),
464 data2, {
465 valueRange: [1, 50],
466 dateWindow: [1, 9],
467 xRangePad: 10,
468 animatedZooms:false
469 });
470
471 var extremes = g.xAxisExtremes();
472
473 // Zoom x axis
474 DygraphOps.dispatchMouseDown_Point(g, 100, 100);
475 DygraphOps.dispatchMouseMove_Point(g, 130, 100);
476 DygraphOps.dispatchMouseUp_Point(g, 130, 100);
477
478 // Zoom y axis
479 DygraphOps.dispatchMouseDown_Point(g, 100, 100);
480 DygraphOps.dispatchMouseMove_Point(g, 100, 130);
481 DygraphOps.dispatchMouseUp_Point(g, 100, 130);
482 var currentYAxisRange = g.yAxisRange();
483 var currentXAxisRange = g.xAxisRange();
484
485 //check that the range for the axis has changed
486 assert.notEqual(1, currentXAxisRange[0]);
487 assert.notEqual(10, currentXAxisRange[1]);
488 assert.notEqual(1, currentYAxisRange[0]);
489 assert.notEqual(50, currentYAxisRange[1]);
490
491 // unzoom by doubleclick. This is really the order in which a browser
492 // generates events, and we depend on it.
493 DygraphOps.dispatchMouseDown_Point(g, 10, 10);
494 DygraphOps.dispatchMouseUp_Point(g, 10, 10);
495 DygraphOps.dispatchMouseDown_Point(g, 10, 10);
496 DygraphOps.dispatchMouseUp_Point(g, 10, 10);
497 DygraphOps.dispatchDoubleClick(g, null);
498
b56f033a 499 // check if range for x-axis was reset to original value
1d2021b5
K
500 var newXAxisRange = g.xAxisRange();
501 assert.equal(extremes[0], newXAxisRange[0]);
502 assert.equal(extremes[1], newXAxisRange[1]);
503});
504
89fdcedb 505});