axisLabelFontSize can now be configured per-axis.
[dygraphs.git] / auto_tests / tests / axis_labels.js
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 AxisLabelsTestCase.simpleData =
16 "X,Y,Y2\n" +
17 "0,-1,0.25\n" +
18 "1,0,0.5\n" +
19 "2,1,0.9\n" +
20 "3,0,0.7\n";
21
22 /**
23 * Takes in an array of strings and returns an array of floats.
24 */
25 function makeNumbers(ary) {
26 var ret = [];
27 for (var i = 0; i < ary.length; i++) {
28 ret.push(parseFloat(ary[i]));
29 }
30 return ret;
31 }
32
33 AxisLabelsTestCase.prototype.kCloseFloat = 1.0e-10;
34
35 AxisLabelsTestCase.prototype.testMinusOneToOne = function() {
36 var opts = {
37 width: 480,
38 height: 320
39 };
40 var data = "X,Y\n" +
41 "0,-1\n" +
42 "1,0\n" +
43 "2,1\n" +
44 "3,0\n"
45 ;
46
47 var graph = document.getElementById("graph");
48 var g = new Dygraph(graph, data, opts);
49
50 // TODO(danvk): would ['-1.0','-0.5','0.0','0.5','1.0'] be better?
51 assertEquals(['-1','-0.5','0','0.5','1'], Util.getYLabels());
52
53 // Go up to 2
54 data += "4,2\n";
55 g.updateOptions({file: data});
56 assertEquals(['-1','-0.5','0','0.5','1','1.5','2'], Util.getYLabels());
57
58 // Now 10
59 data += "5,10\n";
60 g.updateOptions({file: data});
61 assertEquals(['-2','0','2','4','6','8','10'], Util.getYLabels());
62
63 // Now 100
64 data += "6,100\n";
65 g.updateOptions({file: data});
66 assertEquals(['0','20','40','60','80','100'], Util.getYLabels());
67
68 g.setSelection(0);
69 assertEquals('0: Y:-1', Util.getLegend());
70 };
71
72 AxisLabelsTestCase.prototype.testSmallRangeNearZero = function() {
73 var opts = {
74 drawAxesAtZero: true,
75 width: 480,
76 height: 320
77 };
78 var data = "X,Y\n" +
79 "0,-1\n" +
80 "1,0\n" +
81 "2,1\n" +
82 "3,0\n"
83 ;
84 opts.valueRange = [-0.1, 0.1];
85
86 var graph = document.getElementById("graph");
87 var g = new Dygraph(graph, data, opts);
88 assertEqualsDelta(makeNumbers(["-0.1","-0.08","-0.06","-0.04","-0.02","0","0.02","0.04","0.06","0.08"]),
89 makeNumbers(Util.getYLabels()), this.kCloseFloat);
90
91 opts.valueRange = [-0.05, 0.05];
92 g.updateOptions(opts);
93 // TODO(danvk): why '1.00e-2' and not '0.01'?
94 assertEquals(makeNumbers(["-0.05","-0.04","-0.03","-0.02","-0.01","0","1.00e-2","0.02","0.03","0.04"]),
95 makeNumbers(Util.getYLabels()));
96
97 opts.valueRange = [-0.01, 0.01];
98 g.updateOptions(opts);
99 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(Util.getYLabels()));
100
101 g.setSelection(1);
102 assertEquals('1: Y:0', Util.getLegend());
103 };
104
105 AxisLabelsTestCase.prototype.testSmallRangeAwayFromZero = function() {
106 var opts = {
107 width: 480,
108 height: 320
109 };
110 var data = "X,Y\n" +
111 "0,-1\n" +
112 "1,0\n" +
113 "2,1\n" +
114 "3,0\n"
115 ;
116 var graph = document.getElementById("graph");
117
118 opts.valueRange = [9.9, 10.1];
119 var g = new Dygraph(graph, data, opts);
120 assertEquals(["9.9","9.92","9.94","9.96","9.98","10","10.02","10.04","10.06","10.08"], Util.getYLabels());
121
122 opts.valueRange = [9.99, 10.01];
123 g.updateOptions(opts);
124 // TODO(danvk): this is bad
125 assertEquals(["9.99","9.99","9.99","10","10","10","10","10","10.01","10.01"], Util.getYLabels());
126
127 opts.valueRange = [9.999, 10.001];
128 g.updateOptions(opts);
129 // TODO(danvk): this is even worse!
130 assertEquals(["10","10","10","10","10","10","10","10","10","10"], Util.getYLabels());
131
132 g.setSelection(1);
133 assertEquals('1: Y:0', Util.getLegend());
134 };
135
136 AxisLabelsTestCase.prototype.testXAxisTimeLabelFormatter = function() {
137 var opts = {
138 width: 480,
139 height: 320
140 };
141 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]];
142 var graph = document.getElementById("graph");
143 var g = new Dygraph(graph, data, opts);
144 g.updateOptions({
145 axes : {
146 x : {
147 axisLabelFormatter : function (totalMinutes) {
148 var hours = Math.floor( totalMinutes / 60);
149 var minutes = Math.floor((totalMinutes - (hours * 60)));
150 var seconds = Math.round((totalMinutes * 60) - (hours * 3600) - (minutes * 60));
151
152 if (hours < 10) hours = "0" + hours;
153 if (minutes < 10) minutes = "0" + minutes;
154 if (seconds < 10) seconds = "0" + seconds;
155
156 return hours + ':' + minutes + ':' + seconds;
157 }
158 }
159 }
160 });
161
162 assertEquals(["00:05:00","00:05:12","00:05:24","00:05:36","00:05:48"], Util.getXLabels());
163
164 // The legend does not use the axisLabelFormatter:
165 g.setSelection(1);
166 assertEquals('5.1: Y1:1', Util.getLegend());
167 };
168
169 AxisLabelsTestCase.prototype.testAxisLabelFormatter = function () {
170 var opts = {
171 width: 480,
172 height: 320,
173 axes : {
174 x : {
175 axisLabelFormatter : function(x, granularity, opts, dg) {
176 assertEquals('number', typeof(x));
177 assertEquals('number', typeof(granularity));
178 assertEquals('function', typeof(opts));
179 assertEquals('[Dygraph graph]', dg.toString());
180 return 'x' + x;
181 }
182 },
183 y : {
184 axisLabelFormatter : function(y, granularity, opts, dg) {
185 assertEquals('number', typeof(y));
186 assertEquals('number', typeof(granularity));
187 assertEquals('function', typeof(opts));
188 assertEquals('[Dygraph graph]', dg.toString());
189 return 'y' + y;
190 }
191 }
192 },
193 labels: ['x', 'y']
194 };
195 var data = [];
196 for (var i = 0; i < 10; i++) {
197 data.push([i, 2 * i]);
198 }
199 var graph = document.getElementById("graph");
200 var g = new Dygraph(graph, data, opts);
201
202 assertEquals(['x0','x2','x4','x6','x8'], Util.getXLabels());
203 assertEquals(['y0','y2','y4','y6','y8','y10','y12','y14','y16','y18'], Util.getYLabels());
204
205 g.setSelection(2);
206 assertEquals("2: y:4", Util.getLegend());
207 };
208
209 AxisLabelsTestCase.prototype.testDateAxisLabelFormatter = function () {
210 var opts = {
211 width: 480,
212 height: 320,
213 axes : {
214 x : {
215 axisLabelFormatter : function(x, granularity, opts, dg) {
216 assertTrue(Dygraph.isDateLike(x));
217 assertEquals('number', typeof(granularity));
218 assertEquals('function', typeof(opts));
219 assertEquals('[Dygraph graph]', dg.toString());
220 return 'x' + x.strftime('%Y/%m/%d');
221 }
222 },
223 y : {
224 axisLabelFormatter : function(y, granularity, opts, dg) {
225 assertEquals('number', typeof(y));
226 assertEquals('number', typeof(granularity));
227 assertEquals('function', typeof(opts));
228 assertEquals('[Dygraph graph]', dg.toString());
229 return 'y' + y;
230 }
231 }
232 },
233 labels: ['x', 'y']
234 };
235 var data = [];
236 for (var i = 1; i < 10; i++) {
237 data.push([new Date("2011/01/0" + i), 2 * i]);
238 }
239 var graph = document.getElementById("graph");
240 var g = new Dygraph(graph, data, opts);
241
242 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"], Util.getXLabels());
243 assertEquals(['y2','y4','y6','y8','y10','y12','y14','y16','y18'], Util.getYLabels());
244
245 g.setSelection(0);
246 assertEquals("2011/01/01: y:2", Util.getLegend());
247 };
248
249 // This test verifies that when a valueFormatter is set (but not an
250 // axisLabelFormatter), then the valueFormatter is used to format the axis
251 // labels.
252 AxisLabelsTestCase.prototype.testValueFormatter = function () {
253 var opts = {
254 width: 480,
255 height: 320,
256 axes : {
257 x : {
258 valueFormatter: function(x, opts, series_name, dg) {
259 assertEquals('number', typeof(x));
260 assertEquals('function', typeof(opts));
261 assertEquals('string', typeof(series_name));
262 assertEquals('[Dygraph graph]', dg.toString());
263 return 'x' + x;
264 }
265 },
266 y : {
267 valueFormatter: function(y, opts, series_name, dg) {
268 assertEquals('number', typeof(y));
269 assertEquals('function', typeof(opts));
270 assertEquals('string', typeof(series_name));
271 assertEquals('[Dygraph graph]', dg.toString());
272 return 'y' + y;
273 }
274 }
275 },
276 labels: ['x', 'y']
277 };
278 var data = [];
279 for (var i = 0; i < 10; i++) {
280 data.push([i, 2 * i]);
281 }
282 var graph = document.getElementById("graph");
283 var g = new Dygraph(graph, data, opts);
284
285 // the valueFormatter options do not affect the ticks.
286 assertEquals(['0','2','4','6','8'], Util.getXLabels());
287 assertEquals(['0','2','4','6','8','10','12','14','16','18'],
288 Util.getYLabels());
289
290 // they do affect the legend, however.
291 g.setSelection(2);
292 assertEquals("x2: y:y4", Util.getLegend());
293 };
294
295 AxisLabelsTestCase.prototype.testDateValueFormatter = function () {
296 var opts = {
297 width: 480,
298 height: 320,
299 axes : {
300 x : {
301 valueFormatter: function(x, opts, series_name, dg) {
302 assertEquals('number', typeof(x));
303 assertEquals('function', typeof(opts));
304 assertEquals('string', typeof(series_name));
305 assertEquals('[Dygraph graph]', dg.toString());
306 return 'x' + new Date(x).strftime('%Y/%m/%d');
307 }
308 },
309 y : {
310 valueFormatter: function(y, opts, series_name, dg) {
311 assertEquals('number', typeof(y));
312 assertEquals('function', typeof(opts));
313 assertEquals('string', typeof(series_name));
314 assertEquals('[Dygraph graph]', dg.toString());
315 return 'y' + y;
316 }
317 }
318 },
319 labels: ['x', 'y']
320 };
321
322 var data = [];
323 for (var i = 1; i < 10; i++) {
324 data.push([new Date("2011/01/0" + i), 2 * i]);
325 }
326 var graph = document.getElementById("graph");
327 var g = new Dygraph(graph, data, opts);
328
329 // valueFormatters do not affect ticks.
330 assertEquals(['01Jan','02Jan','03Jan','04Jan','05Jan','06Jan','07Jan','08Jan','09Jan'], Util.getXLabels());
331 assertEquals(['2','4','6','8','10','12','14','16','18'], Util.getYLabels());
332
333 // the valueFormatter options also affect the legend.
334 g.setSelection(2);
335 assertEquals('x2011/01/03: y:y6', Util.getLegend());
336 };
337
338 // This test verifies that when both a valueFormatter and an axisLabelFormatter
339 // are specified, the axisLabelFormatter takes precedence.
340 AxisLabelsTestCase.prototype.testAxisLabelFormatterPrecedence = function () {
341 var opts = {
342 width: 480,
343 height: 320,
344 axes : {
345 x : {
346 valueFormatter: function(x) {
347 return 'xvf' + x;
348 },
349 axisLabelFormatter: function(x, granularity) {
350 return 'x' + x;
351 }
352 },
353 y : {
354 valueFormatter: function(y) {
355 return 'yvf' + y;
356 },
357 axisLabelFormatter: function(y) {
358 return 'y' + y;
359 }
360 }
361 },
362 labels: ['x', 'y']
363 };
364 var data = [];
365 for (var i = 0; i < 10; i++) {
366 data.push([i, 2 * i]);
367 }
368 var graph = document.getElementById("graph");
369 var g = new Dygraph(graph, data, opts);
370
371 assertEquals(['x0','x2','x4','x6','x8'], Util.getXLabels());
372 assertEquals(['y0','y2','y4','y6','y8','y10','y12','y14','y16','y18'], Util.getYLabels());
373
374 g.setSelection(9);
375 assertEquals("xvf9: y:yvf18", Util.getLegend());
376 };
377
378 // This is the same as the previous test, except that options are added
379 // one-by-one.
380 AxisLabelsTestCase.prototype.testAxisLabelFormatterIncremental = function () {
381 var opts = {
382 width: 480,
383 height: 320,
384 labels: ['x', 'y']
385 };
386 var data = [];
387 for (var i = 0; i < 10; i++) {
388 data.push([i, 2 * i]);
389 }
390 var graph = document.getElementById("graph");
391 var g = new Dygraph(graph, data, opts);
392 g.updateOptions({
393 axes : {
394 x : {
395 valueFormatter: function(x) {
396 return 'xvf' + x;
397 }
398 }
399 }
400 });
401 g.updateOptions({
402 axes : {
403 y : {
404 valueFormatter: function(y) {
405 return 'yvf' + y;
406 }
407 }
408 }
409 });
410 g.updateOptions({
411 axes : {
412 x : {
413 axisLabelFormatter: function(x, granularity) {
414 return 'x' + x;
415 }
416 }
417 }
418 });
419 g.updateOptions({
420 axes : {
421 y : {
422 axisLabelFormatter: function(y) {
423 return 'y' + y;
424 }
425 }
426 }
427 });
428
429 assertEquals(["x0","x2","x4","x6","x8"], Util.getXLabels());
430 assertEquals(['y0','y2','y4','y6','y8','y10','y12','y14','y16','y18'], Util.getYLabels());
431
432 g.setSelection(9);
433 assertEquals("xvf9: y:yvf18", Util.getLegend());
434 };
435
436 AxisLabelsTestCase.prototype.testGlobalFormatters = function() {
437 var opts = {
438 width: 480,
439 height: 320,
440 labels: ['x', 'y'],
441 valueFormatter: function(x) {
442 return 'vf' + x;
443 },
444 axisLabelFormatter: function(x) {
445 return 'alf' + x;
446 }
447 };
448 var data = [];
449 for (var i = 0; i < 10; i++) {
450 data.push([i, 2 * i]);
451 }
452 var graph = document.getElementById("graph");
453 var g = new Dygraph(graph, data, opts);
454
455 assertEquals(['alf0','alf2','alf4','alf6','alf8'], Util.getXLabels());
456 assertEquals(['alf0','alf2','alf4','alf6','alf8','alf10','alf12','alf14','alf16','alf18'], Util.getYLabels());
457
458 g.setSelection(9);
459 assertEquals("vf9: y:vf18", Util.getLegend());
460 };
461
462 AxisLabelsTestCase.prototype.testSeriesOrder = function() {
463 var opts = {
464 width: 480,
465 height: 320
466 };
467 var data = "x,00,01,10,11\n" +
468 "0,101,201,301,401\n" +
469 "1,102,202,302,402\n" +
470 "2,103,203,303,403\n" +
471 "3,104,204,304,404\n"
472 ;
473
474 var graph = document.getElementById("graph");
475 var g = new Dygraph(graph, data, opts);
476
477 g.setSelection(2);
478 assertEquals('2: 00:103 01:203 10:303 11:403', Util.getLegend());
479
480 // Sanity checks for indexFromSetName
481 assertEquals(0, g.indexFromSetName("x"));
482 assertEquals(1, g.indexFromSetName("00"));
483 assertEquals(null, g.indexFromSetName("abcde"));
484
485 // Verify that we get the label list back in the right order
486 assertEquals(["x", "00", "01", "10", "11"], g.getLabels());
487 };
488
489 AxisLabelsTestCase.prototype.testLabelKMB = function() {
490 var data = [];
491 data.push([0,0]);
492 data.push([1,2000]);
493 data.push([2,1000]);
494
495 var g = new Dygraph(
496 document.getElementById("graph"),
497 data,
498 {
499 labels: [ 'X', 'bar' ],
500 axes : {
501 y: {
502 labelsKMB: true
503 }
504 }
505 }
506 );
507
508 assertEquals(["0", "500", "1K", "1.5K", "2K"], Util.getYLabels());
509 };
510
511 AxisLabelsTestCase.prototype.testLabelKMG2 = function() {
512 var data = [];
513 data.push([0,0]);
514 data.push([1,2000]);
515 data.push([2,1000]);
516
517 var g = new Dygraph(
518 document.getElementById("graph"),
519 data,
520 {
521 labels: [ 'X', 'bar' ],
522 axes : {
523 y: {
524 labelsKMG2: true
525 }
526 }
527 }
528 );
529
530 assertEquals(
531 ["0","256","512","768","1k","1.25k","1.5k","1.75k","2k"],
532 Util.getYLabels());
533 };
534
535 // Same sa testLabelKMG2 but specifies the option at the
536 // top of the option dictionary.
537 AxisLabelsTestCase.prototype.testLabelKMG2_top = function() {
538 var data = [];
539 data.push([0,0]);
540 data.push([1,2000]);
541 data.push([2,1000]);
542
543 var g = new Dygraph(
544 document.getElementById("graph"),
545 data,
546 {
547 labels: [ 'X', 'bar' ],
548 labelsKMG2: true
549 }
550 );
551
552 assertEquals(
553 ["0","256","512","768","1k","1.25k","1.5k","1.75k","2k"],
554 Util.getYLabels());
555 };
556
557 /**
558 * Verify that log scale axis range is properly specified.
559 */
560 AxisLabelsTestCase.prototype.testLogScale = function() {
561 var g = new Dygraph("graph", [[0, 5], [1, 1000]], { logscale : true });
562 var nonEmptyLabels = Util.getYLabels().filter(function(x) { return x.length > 0; });
563 assertEquals(["6","10","30","60","100","300","600","1000"], nonEmptyLabels);
564
565 g.updateOptions({ logscale : false });
566 assertEquals(['0','200','400','600','800','1000'], Util.getYLabels());
567 }
568
569 /**
570 * Verify that include zero range is properly specified.
571 */
572 AxisLabelsTestCase.prototype.testIncludeZero = function() {
573 var g = new Dygraph("graph", [[0, 500], [1, 1000]], { includeZero : true });
574 assertEquals(['0','200','400','600','800','1000'], Util.getYLabels());
575
576 g.updateOptions({ includeZero : false });
577 assertEquals(['500','600','700','800','900','1000'], Util.getYLabels());
578 }
579
580 AxisLabelsTestCase.prototype.testAxisLabelFontSize = function() {
581 var graph = document.getElementById("graph");
582 var g = new Dygraph(graph, AxisLabelsTestCase.simpleData, {});
583
584 // Be sure we're dealing with a 14-point default.
585 assertEquals(14, Dygraph.DEFAULT_ATTRS.axisLabelFontSize);
586
587 Util.assertFontSizes(graph, "dygraph-axis-label-x", 14);
588 Util.assertFontSizes(graph, "dygraph-axis-label-y", 14);
589
590 g.updateOptions({ axisLabelFontSize : 8});
591 Util.assertFontSizes(graph, "dygraph-axis-label-x", 8);
592 Util.assertFontSizes(graph, "dygraph-axis-label-y", 8);
593
594 g.updateOptions({
595 axisLabelFontSize : null,
596 axes : {
597 x : { axisLabelFontSize : 5 },
598 }
599 });
600
601 Util.assertFontSizes(graph, "dygraph-axis-label-x", 5);
602 Util.assertFontSizes(graph, "dygraph-axis-label-y", 14);
603
604 g.updateOptions({
605 axes : {
606 y : { axisLabelFontSize : 20 },
607 }
608 });
609
610 Util.assertFontSizes(graph, "dygraph-axis-label-x", 5);
611 Util.assertFontSizes(graph, "dygraph-axis-label-y", 20);
612
613 g.updateOptions({
614 series : {
615 Y2 : { axis : "y2" } // copy y2 series to y2 axis.
616 },
617 axes : {
618 y2 : { axisLabelFontSize : 12 },
619 }
620 });
621
622 Util.assertFontSizes(graph, "dygraph-axis-label-x", 5);
623 Util.assertFontSizes(graph, "dygraph-axis-label-y1", 20);
624 Util.assertFontSizes(graph, "dygraph-axis-label-y2", 12);
625 }
626
627 AxisLabelsTestCase.prototype.testAxisLabelFontSizeNull = function() {
628 var graph = document.getElementById("graph");
629 var g = new Dygraph(graph, AxisLabelsTestCase.simpleData,
630 {
631 axisLabelFontSize: null
632 });
633
634 // Be sure we're dealing with a 14-point default.
635 assertEquals(14, Dygraph.DEFAULT_ATTRS.axisLabelFontSize);
636
637 Util.assertFontSizes(graph, "dygraph-axis-label-x", 14);
638 Util.assertFontSizes(graph, "dygraph-axis-label-y", 14);
639 }