3 * Copyright 2012 Dan Vanderkam (danvdk@gmail.com)
4 * MIT-licensed (http://opensource.org/licenses/MIT)
6 Dygraph
.Plugins
.ChartLabels
= (function() {
8 // TODO(danvk): move chart label options out of dygraphs and into the plugin.
10 var chart_labels
= function() {
11 this.title_div_
= null;
12 this.xlabel_div_
= null;
13 this.ylabel_div_
= null;
14 this.y2label_div_
= null;
17 chart_labels
.prototype.toString
= function() {
18 return "ChartLabels Plugin";
21 chart_labels
.prototype.activate
= function(g
) {
24 // clearChart: this.clearChart,
25 drawChart
: this.drawChart
29 // QUESTION: should there be a plugin-utils.js?
30 var createDivInRect
= function(r
) {
31 var div
= document
.createElement('div');
32 div
.style
.position
= 'absolute';
33 div
.style
.left
= r
.x
+ 'px';
34 div
.style
.top
= r
.y
+ 'px';
35 div
.style
.width
= r
.w
+ 'px';
36 div
.style
.height
= r
.h
+ 'px';
40 // Detach and null out any existing nodes.
41 chart_labels
.prototype.detachLabels_
= function() {
42 var els
= [ this.title_div_
,
46 for (var i
= 0; i
< els
.length
; i
++) {
49 if (el
.parentNode
) el
.parentNode
.removeChild(el
);
52 this.title_div_
= null;
53 this.xlabel_div_
= null;
54 this.ylabel_div_
= null;
55 this.y2label_div_
= null;
58 var createRotatedDiv
= function(g
, box
, axis
, classes
, html
) {
59 // TODO(danvk): is this outer div actually necessary?
60 div
= document
.createElement("div");
61 div
.style
.position
= 'absolute';
63 // NOTE: this is cheating. Should be positioned relative to the box.
64 div
.style
.left
= '0px';
66 div
.style
.left
= box
.x
+ 'px';
68 div
.style
.top
= box
.y
+ 'px';
69 div
.style
.width
= box
.w
+ 'px';
70 div
.style
.height
= box
.h
+ 'px';
71 div
.style
.fontSize
= (g
.getOption('yLabelWidth') - 2) + 'px';
73 var inner_div
= document
.createElement("div");
74 inner_div
.style
.position
= 'absolute';
75 inner_div
.style
.width
= box
.h
+ 'px';
76 inner_div
.style
.height
= box
.w
+ 'px';
77 inner_div
.style
.top
= (box
.h
/ 2 - box.w / 2) + 'px';
78 inner_div
.style
.left
= (box
.w
/ 2 - box.h / 2) + 'px';
79 inner_div
.style
.textAlign
= 'center';
81 // CSS rotation is an HTML5 feature which is not standardized. Hence every
82 // browser has its own name for the CSS style.
83 var val
= 'rotate(' + (axis
== 1 ? '-' : '') + '90deg)';
84 inner_div
.style
.transform
= val
; // HTML5
85 inner_div
.style
.WebkitTransform
= val
; // Safari/Chrome
86 inner_div
.style
.MozTransform
= val
; // Firefox
87 inner_div
.style
.OTransform
= val
; // Opera
88 inner_div
.style
.msTransform
= val
; // IE9
90 if (typeof(document
.documentMode
) !== 'undefined' &&
91 document
.documentMode
< 9) {
92 // We're dealing w/ an old version of IE
, so we have to rotate the text
93 // using a BasicImage transform. This uses a different origin of rotation
94 // than HTML5 rotation (top left of div vs. its center).
95 inner_div
.style
.filter
=
96 'progid:DXImageTransform.Microsoft.BasicImage(rotation=' +
97 (axis
== 1 ? '3' : '1') + ')';
98 inner_div
.style
.left
= '0px';
99 inner_div
.style
.top
= '0px';
102 class_div
= document
.createElement("div");
103 class_div
.className
= classes
;
104 class_div
.innerHTML
= html
;
106 inner_div
.appendChild(class_div
);
107 div
.appendChild(inner_div
);
111 chart_labels
.prototype.layout
= function(e
) {
112 this.detachLabels_();
115 var div
= e
.chart_div
;
116 if (g
.getOption('title')) {
117 // QUESTION: should this return an absolutely-positioned div instead?
118 var title_rect
= e
.reserveSpaceTop(g
.getOption('titleHeight'));
119 this.title_div_
= createDivInRect(title_rect
);
120 this.title_div_
.style
.textAlign
= 'center';
121 this.title_div_
.style
.fontSize
= (g
.getOption('titleHeight') - 8) + 'px';
122 this.title_div_
.style
.fontWeight
= 'bold';
124 var class_div
= document
.createElement("div");
125 class_div
.className
= 'dygraph-label dygraph-title';
126 class_div
.innerHTML
= g
.getOption('title');
127 this.title_div_
.appendChild(class_div
);
128 div
.appendChild(this.title_div_
);
131 if (g
.getOption('xlabel')) {
132 var x_rect
= e
.reserveSpaceBottom(g
.getOption('xLabelHeight'));
133 this.xlabel_div_
= createDivInRect(x_rect
);
134 this.xlabel_div_
.style
.textAlign
= 'center';
135 this.xlabel_div_
.style
.fontSize
= (g
.getOption('xLabelHeight') - 2) + 'px';
137 var class_div
= document
.createElement("div");
138 class_div
.className
= 'dygraph-label dygraph-xlabel';
139 class_div
.innerHTML
= g
.getOption('xlabel');
140 this.xlabel_div_
.appendChild(class_div
);
141 div
.appendChild(this.xlabel_div_
);
144 if (g
.getOption('ylabel')) {
145 // It would make sense to shift the chart here to make room for the y-axis
146 // label, but the default yAxisLabelWidth is large enough that this results
147 // in overly-padded charts. The y-axis label should fit fine. If it
148 // doesn't, the yAxisLabelWidth option can be increased.
149 var y_rect
= e
.reserveSpaceLeft(0);
151 this.ylabel_div_
= createRotatedDiv(
153 1, // primary (left) y-axis
154 'dygraph-label dygraph-ylabel',
155 g
.getOption('ylabel'));
156 div
.appendChild(this.ylabel_div_
);
159 if (g
.getOption('y2label') && g
.numAxes() == 2) {
160 // same logic applies here as for ylabel.
161 var y2_rect
= e
.reserveSpaceRight(0);
162 this.y2label_div_
= createRotatedDiv(
164 2, // secondary (right) y-axis
165 'dygraph-label dygraph-y2label',
166 g
.getOption('y2label'));
167 div
.appendChild(this.y2label_div_
);
171 chart_labels
.prototype.drawChart
= function(e
) {
173 if (this.title_div_
) {
174 this.title_div_
.children
[0].innerHTML
= g
.getOption('title');
176 if (this.xlabel_div_
) {
177 this.xlabel_div_
.children
[0].innerHTML
= g
.getOption('xlabel');
179 if (this.ylabel_div_
) {
180 this.ylabel_div_
.children
[0].children
[0].innerHTML
= g
.getOption('ylabel');
182 if (this.y2label_div_
) {
183 this.y2label_div_
.children
[0].children
[0].innerHTML
= g
.getOption('y2label');
187 chart_labels
.prototype.clearChart
= function() {
190 chart_labels
.prototype.destroy
= function() {