|
1 /* |
|
2 Axis label plugin for flot |
|
3 |
|
4 Derived from: |
|
5 Axis Labels Plugin for flot. |
|
6 http://github.com/markrcote/flot-axislabels |
|
7 |
|
8 Original code is Copyright (c) 2010 Xuan Luo. |
|
9 Original code was released under the GPLv3 license by Xuan Luo, September 2010. |
|
10 Original code was rereleased under the MIT license by Xuan Luo, April 2012. |
|
11 |
|
12 Permission is hereby granted, free of charge, to any person obtaining |
|
13 a copy of this software and associated documentation files (the |
|
14 "Software"), to deal in the Software without restriction, including |
|
15 without limitation the rights to use, copy, modify, merge, publish, |
|
16 distribute, sublicense, and/or sell copies of the Software, and to |
|
17 permit persons to whom the Software is furnished to do so, subject to |
|
18 the following conditions: |
|
19 |
|
20 The above copyright notice and this permission notice shall be |
|
21 included in all copies or substantial portions of the Software. |
|
22 |
|
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
|
24 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
|
25 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
|
26 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
|
27 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
|
28 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
|
29 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
30 */ |
|
31 |
|
32 (function($) { |
|
33 "use strict"; |
|
34 |
|
35 var options = { |
|
36 axisLabels: { |
|
37 show: true |
|
38 } |
|
39 }; |
|
40 |
|
41 function AxisLabel(axisName, position, padding, placeholder, axisLabel, surface) { |
|
42 this.axisName = axisName; |
|
43 this.position = position; |
|
44 this.padding = padding; |
|
45 this.placeholder = placeholder; |
|
46 this.axisLabel = axisLabel; |
|
47 this.surface = surface; |
|
48 this.width = 0; |
|
49 this.height = 0; |
|
50 this.elem = null; |
|
51 } |
|
52 |
|
53 AxisLabel.prototype.calculateSize = function() { |
|
54 var axisId = this.axisName + 'Label', |
|
55 layerId = axisId + 'Layer', |
|
56 className = axisId + ' axisLabels'; |
|
57 |
|
58 var info = this.surface.getTextInfo(layerId, this.axisLabel, className); |
|
59 this.labelWidth = info.width; |
|
60 this.labelHeight = info.height; |
|
61 |
|
62 if (this.position === 'left' || this.position === 'right') { |
|
63 this.width = this.labelHeight + this.padding; |
|
64 this.height = 0; |
|
65 } else { |
|
66 this.width = 0; |
|
67 this.height = this.labelHeight + this.padding; |
|
68 } |
|
69 }; |
|
70 |
|
71 AxisLabel.prototype.transforms = function(degrees, x, y, svgLayer) { |
|
72 var transforms = [], translate, rotate; |
|
73 if (x !== 0 || y !== 0) { |
|
74 translate = svgLayer.createSVGTransform(); |
|
75 translate.setTranslate(x, y); |
|
76 transforms.push(translate); |
|
77 } |
|
78 if (degrees !== 0) { |
|
79 rotate = svgLayer.createSVGTransform(); |
|
80 var centerX = Math.round(this.labelWidth / 2), |
|
81 centerY = 0; |
|
82 rotate.setRotate(degrees, centerX, centerY); |
|
83 transforms.push(rotate); |
|
84 } |
|
85 |
|
86 return transforms; |
|
87 }; |
|
88 |
|
89 AxisLabel.prototype.calculateOffsets = function(box) { |
|
90 var offsets = { |
|
91 x: 0, |
|
92 y: 0, |
|
93 degrees: 0 |
|
94 }; |
|
95 if (this.position === 'bottom') { |
|
96 offsets.x = box.left + box.width / 2 - this.labelWidth / 2; |
|
97 offsets.y = box.top + box.height - this.labelHeight; |
|
98 } else if (this.position === 'top') { |
|
99 offsets.x = box.left + box.width / 2 - this.labelWidth / 2; |
|
100 offsets.y = box.top; |
|
101 } else if (this.position === 'left') { |
|
102 offsets.degrees = -90; |
|
103 offsets.x = box.left - this.labelWidth / 2; |
|
104 offsets.y = box.height / 2 + box.top; |
|
105 } else if (this.position === 'right') { |
|
106 offsets.degrees = 90; |
|
107 offsets.x = box.left + box.width - this.labelWidth / 2; |
|
108 offsets.y = box.height / 2 + box.top; |
|
109 } |
|
110 offsets.x = Math.round(offsets.x); |
|
111 offsets.y = Math.round(offsets.y); |
|
112 |
|
113 return offsets; |
|
114 }; |
|
115 |
|
116 AxisLabel.prototype.cleanup = function() { |
|
117 var axisId = this.axisName + 'Label', |
|
118 layerId = axisId + 'Layer', |
|
119 className = axisId + ' axisLabels'; |
|
120 this.surface.removeText(layerId, 0, 0, this.axisLabel, className); |
|
121 }; |
|
122 |
|
123 AxisLabel.prototype.draw = function(box) { |
|
124 var axisId = this.axisName + 'Label', |
|
125 layerId = axisId + 'Layer', |
|
126 className = axisId + ' axisLabels', |
|
127 offsets = this.calculateOffsets(box), |
|
128 style = { |
|
129 position: 'absolute', |
|
130 bottom: '', |
|
131 right: '', |
|
132 display: 'inline-block', |
|
133 'white-space': 'nowrap' |
|
134 }; |
|
135 |
|
136 var layer = this.surface.getSVGLayer(layerId); |
|
137 var transforms = this.transforms(offsets.degrees, offsets.x, offsets.y, layer.parentNode); |
|
138 |
|
139 this.surface.addText(layerId, 0, 0, this.axisLabel, className, undefined, undefined, undefined, undefined, transforms); |
|
140 this.surface.render(); |
|
141 Object.keys(style).forEach(function(key) { |
|
142 layer.style[key] = style[key]; |
|
143 }); |
|
144 }; |
|
145 |
|
146 function init(plot) { |
|
147 plot.hooks.processOptions.push(function(plot, options) { |
|
148 if (!options.axisLabels.show) { |
|
149 return; |
|
150 } |
|
151 |
|
152 var axisLabels = {}; |
|
153 var defaultPadding = 2; // padding between axis and tick labels |
|
154 |
|
155 plot.hooks.axisReserveSpace.push(function(plot, axis) { |
|
156 var opts = axis.options; |
|
157 var axisName = axis.direction + axis.n; |
|
158 |
|
159 axis.labelHeight += axis.boxPosition.centerY; |
|
160 axis.labelWidth += axis.boxPosition.centerX; |
|
161 |
|
162 if (!opts || !opts.axisLabel || !axis.show) { |
|
163 return; |
|
164 } |
|
165 |
|
166 var padding = opts.axisLabelPadding === undefined |
|
167 ? defaultPadding |
|
168 : opts.axisLabelPadding; |
|
169 |
|
170 var axisLabel = axisLabels[axisName]; |
|
171 if (!axisLabel) { |
|
172 axisLabel = new AxisLabel(axisName, |
|
173 opts.position, padding, |
|
174 plot.getPlaceholder()[0], opts.axisLabel, plot.getSurface()); |
|
175 axisLabels[axisName] = axisLabel; |
|
176 } |
|
177 |
|
178 axisLabel.calculateSize(); |
|
179 |
|
180 // Incrementing the sizes of the tick labels. |
|
181 axis.labelHeight += axisLabel.height; |
|
182 axis.labelWidth += axisLabel.width; |
|
183 }); |
|
184 |
|
185 // TODO - use the drawAxis hook |
|
186 plot.hooks.draw.push(function(plot, ctx) { |
|
187 $.each(plot.getAxes(), function(flotAxisName, axis) { |
|
188 var opts = axis.options; |
|
189 if (!opts || !opts.axisLabel || !axis.show) { |
|
190 return; |
|
191 } |
|
192 |
|
193 var axisName = axis.direction + axis.n; |
|
194 axisLabels[axisName].draw(axis.box); |
|
195 }); |
|
196 }); |
|
197 |
|
198 plot.hooks.shutdown.push(function(plot, eventHolder) { |
|
199 for (var axisName in axisLabels) { |
|
200 axisLabels[axisName].cleanup(); |
|
201 } |
|
202 }); |
|
203 }); |
|
204 }; |
|
205 |
|
206 $.plot.plugins.push({ |
|
207 init: init, |
|
208 options: options, |
|
209 name: 'axisLabels', |
|
210 version: '3.0' |
|
211 }); |
|
212 })(jQuery); |