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