Commit | Line | Data |
---|---|---|
6d6c60b6 RK |
1 | /** |
2 | * @fileoverview Test cases for how axis labels are chosen and formatted. | |
3 | * | |
4 | * @author dan@dygraphs.com (Dan Vanderkam) | |
5 | */ | |
6 | var AxisLabelsTestCase = TestCase("axis-labels"); | |
7 | ||
8 | AxisLabelsTestCase.prototype.setUp = function() { | |
9 | document.body.innerHTML = "<div id='graph'></div>"; | |
10 | }; | |
11 | ||
12 | AxisLabelsTestCase.prototype.tearDown = function() { | |
13 | }; | |
14 | ||
15 | function getYLabels() { | |
16 | var y_labels = document.getElementsByClassName("dygraph-axis-label-y"); | |
17 | var ary = []; | |
18 | for (var i = 0; i < y_labels.length; i++) { | |
19 | ary.push(y_labels[i].innerHTML); | |
20 | } | |
21 | return ary; | |
22 | } | |
23 | ||
24 | function getXLabels() { | |
25 | var x_labels = document.getElementsByClassName("dygraph-axis-label-x"); | |
26 | var ary = []; | |
27 | for (var i = 0; i < x_labels.length; i++) { | |
28 | ary.push(x_labels[i].innerHTML); | |
29 | } | |
30 | return ary; | |
31 | } | |
32 | ||
33 | function makeNumbers(ary) { | |
34 | var ret = []; | |
35 | for (var i = 0; i < ary.length; i++) { | |
36 | ret.push(parseFloat(ary[i])); | |
37 | } | |
38 | return ret; | |
39 | } | |
40 | ||
41 | function getLegend() { | |
42 | var legend = document.getElementsByClassName("dygraph-legend")[0]; | |
43 | return legend.textContent; | |
44 | } | |
45 | ||
46 | AxisLabelsTestCase.prototype.kCloseFloat = 1.0e-10; | |
47 | ||
48 | AxisLabelsTestCase.prototype.testMinusOneToOne = function() { | |
49 | var opts = { | |
50 | width: 480, | |
51 | height: 320 | |
52 | }; | |
53 | var data = "X,Y\n" + | |
54 | "0,-1\n" + | |
55 | "1,0\n" + | |
56 | "2,1\n" + | |
57 | "3,0\n" | |
58 | ; | |
59 | ||
60 | var graph = document.getElementById("graph"); | |
61 | var g = new Dygraph(graph, data, opts); | |
62 | ||
63 | // TODO(danvk): would ['-1.0','-0.5','0.0','0.5','1.0'] be better? | |
64 | assertEquals(['-1','-0.5','0','0.5','1'], getYLabels()); | |
65 | ||
66 | // Go up to 2 | |
67 | data += "4,2\n"; | |
68 | g.updateOptions({file: data}); | |
69 | assertEquals(['-1','-0.5','0','0.5','1','1.5','2'], getYLabels()); | |
70 | ||
71 | // Now 10 | |
72 | data += "5,10\n"; | |
73 | g.updateOptions({file: data}); | |
74 | assertEquals(['-2','0','2','4','6','8','10'], getYLabels()); | |
75 | ||
76 | // Now 100 | |
77 | data += "6,100\n"; | |
78 | g.updateOptions({file: data}); | |
79 | assertEquals(['0','20','40','60','80','100'], getYLabels()); | |
80 | ||
81 | g.setSelection(0); | |
82 | assertEquals('0: Y:-1', getLegend()); | |
83 | }; | |
84 | ||
85 | AxisLabelsTestCase.prototype.testSmallRangeNearZero = function() { | |
86 | var opts = { | |
87 | drawAxesAtZero: true, | |
88 | width: 480, | |
89 | height: 320 | |
90 | }; | |
91 | var data = "X,Y\n" + | |
92 | "0,-1\n" + | |
93 | "1,0\n" + | |
94 | "2,1\n" + | |
95 | "3,0\n" | |
96 | ; | |
97 | opts.valueRange = [-0.1, 0.1]; | |
98 | ||
99 | var graph = document.getElementById("graph"); | |
100 | var g = new Dygraph(graph, data, opts); | |
101 | assertEqualsDelta(makeNumbers(["-0.1","-0.08","-0.06","-0.04","-0.02","0","0.02","0.04","0.06","0.08"]), | |
102 | makeNumbers(getYLabels()), this.kCloseFloat); | |
103 | ||
104 | opts.valueRange = [-0.05, 0.05]; | |
105 | g.updateOptions(opts); | |
106 | // TODO(danvk): why '1.00e-2' and not '0.01'? | |
107 | assertEquals(makeNumbers(["-0.05","-0.04","-0.03","-0.02","-0.01","0","1.00e-2","0.02","0.03","0.04"]), | |
108 | makeNumbers(getYLabels())); | |
109 | ||
110 | opts.valueRange = [-0.01, 0.01]; | |
111 | g.updateOptions(opts); | |
112 | assertEquals(makeNumbers(["-0.01","-8.00e-3","-6.00e-3","-4.00e-3","-2.00e-3","0","2.00e-3","4.00e-3","6.00e-3","8.00e-3"]), makeNumbers(getYLabels())); | |
113 | ||
114 | g.setSelection(1); | |
115 | assertEquals('1: Y:0', getLegend()); | |
116 | }; | |
117 | ||
118 | AxisLabelsTestCase.prototype.testSmallRangeAwayFromZero = function() { | |
119 | var opts = { | |
120 | width: 480, | |
121 | height: 320 | |
122 | }; | |
123 | var data = "X,Y\n" + | |
124 | "0,-1\n" + | |
125 | "1,0\n" + | |
126 | "2,1\n" + | |
127 | "3,0\n" | |
128 | ; | |
129 | var graph = document.getElementById("graph"); | |
130 | ||
131 | opts.valueRange = [9.9, 10.1]; | |
132 | var g = new Dygraph(graph, data, opts); | |
133 | assertEquals(["9.9","9.92","9.94","9.96","9.98","10","10.02","10.04","10.06","10.08"], getYLabels()); | |
134 | ||
135 | opts.valueRange = [9.99, 10.01]; | |
136 | g.updateOptions(opts); | |
137 | // TODO(danvk): this is bad | |
138 | assertEquals(["9.99","9.99","9.99","10","10","10","10","10","10.01","10.01"], getYLabels()); | |
139 | ||
140 | opts.valueRange = [9.999, 10.001]; | |
141 | g.updateOptions(opts); | |
142 | // TODO(danvk): this is even worse! | |
143 | assertEquals(["10","10","10","10","10","10","10","10","10","10"], getYLabels()); | |
144 | ||
145 | g.setSelection(1); | |
146 | assertEquals('1: Y:0', getLegend()); | |
147 | }; | |
148 | ||
149 | AxisLabelsTestCase.prototype.testXAxisTimeLabelFormatter = function() { | |
150 | var opts = { | |
151 | width: 480, | |
152 | height: 320 | |
153 | }; | |
154 | var data = [[5.0,0],[5.1,1],[5.2,2],[5.3,3],[5.4,4],[5.5,5],[5.6,6],[5.7,7],[5.8,8],[5.9,9]]; | |
155 | var graph = document.getElementById("graph"); | |
156 | var g = new Dygraph(graph, data, opts); | |
157 | g.updateOptions({ | |
158 | axes : { | |
159 | x : { | |
160 | axisLabelFormatter : function (totalMinutes) { | |
161 | var hours = Math.floor( totalMinutes / 60); | |
162 | var minutes = Math.floor((totalMinutes - (hours * 60))); | |
163 | var seconds = Math.round((totalMinutes * 60) - (hours * 3600) - (minutes * 60)); | |
164 | ||
165 | if (hours < 10) hours = "0" + hours; | |
166 | if (minutes < 10) minutes = "0" + minutes; | |
167 | if (seconds < 10) seconds = "0" + seconds; | |
168 | ||
169 | return hours + ':' + minutes + ':' + seconds; | |
170 | } | |
171 | } | |
172 | } | |
173 | }); | |
174 | ||
175 | assertEquals(["00:05:00","00:05:12","00:05:24","00:05:36","00:05:48"], getXLabels()); | |
176 | ||
177 | // The legend does not use the axisLabelFormatter: | |
178 | g.setSelection(1); | |
179 | assertEquals('5.1: Y1:1', getLegend()); | |
180 | }; | |
181 | ||
182 | AxisLabelsTestCase.prototype.testAxisLabelFormatter = function () { | |
183 | var opts = { | |
184 | width: 480, | |
185 | height: 320, | |
186 | axes : { | |
187 | x : { | |
188 | axisLabelFormatter : function(x, granularity, opts, dg) { | |
189 | assertEquals('number', typeof(x)); | |
190 | assertEquals('number', typeof(granularity)); | |
191 | assertEquals('function', typeof(opts)); | |
192 | assertEquals('[Dygraph graph]', dg.toString()); | |
193 | return 'x' + x; | |
194 | } | |
195 | }, | |
196 | y : { | |
197 | axisLabelFormatter : function(y, granularity, opts, dg) { | |
198 | assertEquals('number', typeof(y)); | |
199 | assertEquals('number', typeof(granularity)); | |
200 | assertEquals('function', typeof(opts)); | |
201 | assertEquals('[Dygraph graph]', dg.toString()); | |
202 | return 'y' + y; | |
203 | } | |
204 | } | |
205 | }, | |
206 | labels: ['x', 'y'] | |
207 | }; | |
208 | var data = []; | |
209 | for (var i = 0; i < 10; i++) { | |
210 | data.push([i, 2 * i]); | |
211 | } | |
212 | var graph = document.getElementById("graph"); | |
213 | var g = new Dygraph(graph, data, opts); | |
214 | ||
215 | assertEquals(['x0','x2','x4','x6','x8'], getXLabels()); | |
216 | assertEquals(['y0','y2','y4','y6','y8','y10','y12','y14','y16','y18'], getYLabels()); | |
217 | ||
218 | g.setSelection(2); | |
219 | assertEquals("2: y:4", getLegend()); | |
220 | }; | |
221 | ||
222 | AxisLabelsTestCase.prototype.testDateAxisLabelFormatter = function () { | |
223 | var opts = { | |
224 | width: 480, | |
225 | height: 320, | |
226 | axes : { | |
227 | x : { | |
228 | axisLabelFormatter : function(x, granularity, opts, dg) { | |
229 | assertTrue(Dygraph.isDateLike(x)); | |
230 | assertEquals('number', typeof(granularity)); | |
231 | assertEquals('function', typeof(opts)); | |
232 | assertEquals('[Dygraph graph]', dg.toString()); | |
233 | return 'x' + x.strftime('%Y/%m/%d'); | |
234 | } | |
235 | }, | |
236 | y : { | |
237 | axisLabelFormatter : function(y, granularity, opts, dg) { | |
238 | assertEquals('number', typeof(y)); | |
239 | assertEquals('number', typeof(granularity)); | |
240 | assertEquals('function', typeof(opts)); | |
241 | assertEquals('[Dygraph graph]', dg.toString()); | |
242 | return 'y' + y; | |
243 | } | |
244 | } | |
245 | }, | |
246 | labels: ['x', 'y'] | |
247 | }; | |
248 | var data = []; | |
249 | for (var i = 1; i < 10; i++) { | |
250 | data.push([new Date("2011/01/0" + i), 2 * i]); | |
251 | } | |
252 | var graph = document.getElementById("graph"); | |
253 | var g = new Dygraph(graph, data, opts); | |
254 | ||
255 | assertEquals(["x2011/01/01", "x2011/01/02", "x2011/01/03", "x2011/01/04", "x2011/01/05", "x2011/01/06", "x2011/01/07", "x2011/01/08", "x2011/01/09"], getXLabels()); | |
256 | assertEquals(['y2','y4','y6','y8','y10','y12','y14','y16','y18'], getYLabels()); | |
257 | ||
258 | g.setSelection(0); | |
259 | assertEquals("2011/01/01: y:2", getLegend()); | |
260 | }; | |
261 | ||
262 | // This test verifies that when a valueFormatter is set (but not an | |
263 | // axisLabelFormatter), then the valueFormatter is used to format the axis | |
264 | // labels. | |
265 | AxisLabelsTestCase.prototype.testValueFormatter = function () { | |
266 | var opts = { | |
267 | width: 480, | |
268 | height: 320, | |
269 | axes : { | |
270 | x : { | |
271 | valueFormatter: function(x, opts, series_name, dg) { | |
272 | assertEquals('number', typeof(x)); | |
273 | assertEquals('function', typeof(opts)); | |
274 | assertEquals('string', typeof(series_name)); | |
275 | assertEquals('[Dygraph graph]', dg.toString()); | |
276 | return 'x' + x; | |
277 | } | |
278 | }, | |
279 | y : { | |
280 | valueFormatter: function(y, opts, series_name, dg) { | |
281 | assertEquals('number', typeof(y)); | |
282 | assertEquals('function', typeof(opts)); | |
283 | assertEquals('string', typeof(series_name)); | |
284 | assertEquals('[Dygraph graph]', dg.toString()); | |
285 | return 'y' + y; | |
286 | } | |
287 | } | |
288 | }, | |
289 | labels: ['x', 'y'] | |
290 | }; | |
291 | var data = []; | |
292 | for (var i = 0; i < 10; i++) { | |
293 | data.push([i, 2 * i]); | |
294 | } | |
295 | var graph = document.getElementById("graph"); | |
296 | var g = new Dygraph(graph, data, opts); | |
297 | ||
298 | // the valueFormatter options do not affect the ticks. | |
299 | assertEquals(['0','2','4','6','8'], getXLabels()); | |
300 | assertEquals(['0','2','4','6','8','10','12','14','16','18'], | |
301 | getYLabels()); | |
302 | ||
303 | // they do affect the legend, however. | |
304 | g.setSelection(2); | |
305 | assertEquals("x2: y:y4", getLegend()); | |
306 | }; | |
307 | ||
308 | AxisLabelsTestCase.prototype.testDateValueFormatter = function () { | |
309 | var opts = { | |
310 | width: 480, | |
311 | height: 320, | |
312 | axes : { | |
313 | x : { | |
314 | valueFormatter: function(x, opts, series_name, dg) { | |
315 | assertEquals('number', typeof(x)); | |
316 | assertEquals('function', typeof(opts)); | |
317 | assertEquals('string', typeof(series_name)); | |
318 | assertEquals('[Dygraph graph]', dg.toString()); | |
319 | return 'x' + new Date(x).strftime('%Y/%m/%d'); | |
320 | } | |
321 | }, | |
322 | y : { | |
323 | valueFormatter: function(y, opts, series_name, dg) { | |
324 | assertEquals('number', typeof(y)); | |
325 | assertEquals('function', typeof(opts)); | |
326 | assertEquals('string', typeof(series_name)); | |
327 | assertEquals('[Dygraph graph]', dg.toString()); | |
328 | return 'y' + y; | |
329 | } | |
330 | } | |
331 | }, | |
332 | labels: ['x', 'y'] | |
333 | }; | |
334 | ||
335 | var data = []; | |
336 | for (var i = 1; i < 10; i++) { | |
337 | data.push([new Date("2011/01/0" + i), 2 * i]); | |
338 | } | |
339 | var graph = document.getElementById("graph"); | |
340 | var g = new Dygraph(graph, data, opts); | |
341 | ||
342 | // valueFormatters do not affect ticks. | |
343 | assertEquals(['01Jan','02Jan','03Jan','04Jan','05Jan','06Jan','07Jan','08Jan','09Jan'], getXLabels()); | |
344 | assertEquals(['2','4','6','8','10','12','14','16','18'], getYLabels()); | |
345 | ||
346 | // the valueFormatter options also affect the legend. | |
347 | g.setSelection(2); | |
348 | assertEquals('x2011/01/03: y:y6', getLegend()); | |
349 | }; | |
350 | ||
351 | // This test verifies that when both a valueFormatter and an axisLabelFormatter | |
352 | // are specified, the axisLabelFormatter takes precedence. | |
353 | AxisLabelsTestCase.prototype.testAxisLabelFormatterPrecedence = function () { | |
354 | var opts = { | |
355 | width: 480, | |
356 | height: 320, | |
357 | axes : { | |
358 | x : { | |
359 | valueFormatter: function(x) { | |
360 | return 'xvf' + x; | |
361 | }, | |
362 | axisLabelFormatter: function(x, granularity) { | |
363 | return 'x' + x; | |
364 | } | |
365 | }, | |
366 | y : { | |
367 | valueFormatter: function(y) { | |
368 | return 'yvf' + y; | |
369 | }, | |
370 | axisLabelFormatter: function(y) { | |
371 | return 'y' + y; | |
372 | } | |
373 | } | |
374 | }, | |
375 | labels: ['x', 'y'] | |
376 | }; | |
377 | var data = []; | |
378 | for (var i = 0; i < 10; i++) { | |
379 | data.push([i, 2 * i]); | |
380 | } | |
381 | var graph = document.getElementById("graph"); | |
382 | var g = new Dygraph(graph, data, opts); | |
383 | ||
384 | assertEquals(['x0','x2','x4','x6','x8'], getXLabels()); | |
385 | assertEquals(['y0','y2','y4','y6','y8','y10','y12','y14','y16','y18'], getYLabels()); | |
386 | ||
387 | g.setSelection(9); | |
388 | assertEquals("xvf9: y:yvf18", getLegend()); | |
389 | }; | |
390 | ||
391 | // This is the same as the previous test, except that options are added | |
392 | // one-by-one. | |
393 | AxisLabelsTestCase.prototype.testAxisLabelFormatterIncremental = function () { | |
394 | var opts = { | |
395 | width: 480, | |
396 | height: 320, | |
397 | labels: ['x', 'y'] | |
398 | }; | |
399 | var data = []; | |
400 | for (var i = 0; i < 10; i++) { | |
401 | data.push([i, 2 * i]); | |
402 | } | |
403 | var graph = document.getElementById("graph"); | |
404 | var g = new Dygraph(graph, data, opts); | |
405 | g.updateOptions({ | |
406 | axes : { | |
407 | x : { | |
408 | valueFormatter: function(x) { | |
409 | return 'xvf' + x; | |
410 | } | |
411 | } | |
412 | } | |
413 | }); | |
414 | g.updateOptions({ | |
415 | axes : { | |
416 | y : { | |
417 | valueFormatter: function(y) { | |
418 | return 'yvf' + y; | |
419 | } | |
420 | } | |
421 | } | |
422 | }); | |
423 | g.updateOptions({ | |
424 | axes : { | |
425 | x : { | |
426 | axisLabelFormatter: function(x, granularity) { | |
427 | return 'x' + x; | |
428 | } | |
429 | } | |
430 | } | |
431 | }); | |
432 | g.updateOptions({ | |
433 | axes : { | |
434 | y : { | |
435 | axisLabelFormatter: function(y) { | |
436 | return 'y' + y; | |
437 | } | |
438 | } | |
439 | } | |
440 | }); | |
441 | ||
442 | assertEquals(["x0","x2","x4","x6","x8"], getXLabels()); | |
443 | assertEquals(['y0','y2','y4','y6','y8','y10','y12','y14','y16','y18'], getYLabels()); | |
444 | ||
445 | g.setSelection(9); | |
446 | assertEquals("xvf9: y:yvf18", getLegend()); | |
447 | }; | |
448 | ||
449 | AxisLabelsTestCase.prototype.testGlobalFormatters = function() { | |
450 | var opts = { | |
451 | width: 480, | |
452 | height: 320, | |
453 | labels: ['x', 'y'], | |
454 | valueFormatter: function(x) { | |
455 | return 'vf' + x; | |
456 | }, | |
457 | axisLabelFormatter: function(x) { | |
458 | return 'alf' + x; | |
459 | } | |
460 | }; | |
461 | var data = []; | |
462 | for (var i = 0; i < 10; i++) { | |
463 | data.push([i, 2 * i]); | |
464 | } | |
465 | var graph = document.getElementById("graph"); | |
466 | var g = new Dygraph(graph, data, opts); | |
467 | ||
468 | assertEquals(['alf0','alf2','alf4','alf6','alf8'], getXLabels()); | |
469 | assertEquals(['alf0','alf2','alf4','alf6','alf8','alf10','alf12','alf14','alf16','alf18'], getYLabels()); | |
470 | ||
471 | g.setSelection(9); | |
472 | assertEquals("vf9: y:vf18", getLegend()); | |
473 | }; | |
474 | ||
475 | AxisLabelsTestCase.prototype.testSeriesOrder = function() { | |
476 | var opts = { | |
477 | width: 480, | |
478 | height: 320 | |
479 | }; | |
480 | var data = "x,00,01,10,11\n" + | |
481 | "0,101,201,301,401\n" + | |
482 | "1,102,202,302,402\n" + | |
483 | "2,103,203,303,403\n" + | |
484 | "3,104,204,304,404\n" | |
485 | ; | |
486 | ||
487 | var graph = document.getElementById("graph"); | |
488 | var g = new Dygraph(graph, data, opts); | |
489 | ||
490 | g.setSelection(2); | |
491 | assertEquals('2: 00:103 01:203 10:303 11:403', getLegend()); | |
492 | ||
493 | // Sanity checks for indexFromSetName | |
494 | assertEquals(0, g.indexFromSetName("x")); | |
495 | assertEquals(1, g.indexFromSetName("00")); | |
496 | assertEquals(null, g.indexFromSetName("abcde")); | |
497 | ||
498 | // Verify that we get the label list back in the right order | |
499 | assertEquals(["x", "00", "01", "10", "11"], g.getLabels()); | |
500 | }; |