1 | define(["dojo/_base/lang", "dojo/_base/array", "dojo/sniff", "dojo/_base/declare", |
---|
2 | "dojo/_base/connect", "dojo/dom-geometry", "./Invisible", |
---|
3 | "../scaler/linear", "./common", "dojox/gfx", "dojox/lang/utils", "dojox/lang/functional", |
---|
4 | "dojo/has!dojo-bidi?../bidi/axis2d/Default"], |
---|
5 | function(lang, arr, has, declare, connect, domGeom, Invisible, |
---|
6 | lin, acommon, g, du, df, BidiDefault){ |
---|
7 | |
---|
8 | /*===== |
---|
9 | var __AxisCtorArgs = { |
---|
10 | // summary: |
---|
11 | // Optional arguments used in the definition of an axis. |
---|
12 | // vertical: Boolean? |
---|
13 | // A flag that says whether an axis is vertical (i.e. y axis) or horizontal. Default is false (horizontal). |
---|
14 | // fixUpper: String? |
---|
15 | // Align the greatest value on the axis with the specified tick level. Options are "major", "minor", "micro", or "none". Defaults to "none". |
---|
16 | // fixLower: String? |
---|
17 | // Align the smallest value on the axis with the specified tick level. Options are "major", "minor", "micro", or "none". Defaults to "none". |
---|
18 | // natural: Boolean? |
---|
19 | // Ensure tick marks are made on "natural" numbers. Defaults to false. |
---|
20 | // leftBottom: Boolean? |
---|
21 | // The position of a vertical axis; if true, will be placed against the left-bottom corner of the chart. Defaults to true. |
---|
22 | // includeZero: Boolean? |
---|
23 | // Include 0 on the axis rendering. Default is false. |
---|
24 | // fixed: Boolean? |
---|
25 | // Force all axis labels to be fixed numbers. Default is true. |
---|
26 | // majorLabels: Boolean? |
---|
27 | // Flag to draw labels at major ticks. Default is true. |
---|
28 | // minorTicks: Boolean? |
---|
29 | // Flag to draw minor ticks on an axis. Default is true. |
---|
30 | // minorLabels: Boolean? |
---|
31 | // Flag to labels on minor ticks when there is enough space. Default is true. |
---|
32 | // microTicks: Boolean? |
---|
33 | // Flag to draw micro ticks on an axis. Default is false. |
---|
34 | // htmlLabels: Boolean? |
---|
35 | // Flag to use HTML (as opposed to the native vector graphics engine) to draw labels. Default is true. |
---|
36 | // min: Number? |
---|
37 | // The smallest value on an axis. Default is 0. |
---|
38 | // max: Number? |
---|
39 | // The largest value on an axis. Default is 1. |
---|
40 | // from: Number? |
---|
41 | // Force the chart to render data visible from this value. Default is 0. |
---|
42 | // to: Number? |
---|
43 | // Force the chart to render data visible to this value. Default is 1. |
---|
44 | // majorTickStep: Number? |
---|
45 | // The amount to skip before a major tick is drawn. When not set the major ticks step is computed from |
---|
46 | // the data range. |
---|
47 | // minorTickStep: Number? |
---|
48 | // The amount to skip before a minor tick is drawn. When not set the minor ticks step is computed from |
---|
49 | // the data range. |
---|
50 | // microTickStep: Number? |
---|
51 | // The amount to skip before a micro tick is drawn. When not set the micro ticks step is computed from |
---|
52 | // labels: Object[]? |
---|
53 | // An array of labels for major ticks, with corresponding numeric values, ordered by value. |
---|
54 | // labelFunc: Function? |
---|
55 | // An optional function to use to compute label text. It takes precedence over |
---|
56 | // the default text when available. The function must be of the following form: |
---|
57 | // | function labelFunc(text, value, precision) {} |
---|
58 | // `text` is the already pre-formatted text. Pre-formatting is done using `dojo/number` is available, `Date.toFixed` otherwise. |
---|
59 | // `value` is the raw axis value. |
---|
60 | // `precision` is the requested precision to be applied. |
---|
61 | // maxLabelSize: Number? |
---|
62 | // The maximum size, in pixels, for a label. To be used with the optional label function. |
---|
63 | // stroke: dojox.gfx.Stroke? |
---|
64 | // An optional stroke to be used for drawing an axis. |
---|
65 | // majorTick: Object? |
---|
66 | // An object containing a dojox.gfx.Stroke, and a length (number) for a major tick. |
---|
67 | // minorTick: Object? |
---|
68 | // An object containing a dojox.gfx.Stroke, and a length (number) for a minor tick. |
---|
69 | // microTick: Object? |
---|
70 | // An object containing a dojox.gfx.Stroke, and a length (number) for a micro tick. |
---|
71 | // tick: Object? |
---|
72 | // An object containing a dojox.gfx.Stroke, and a length (number) for a tick. |
---|
73 | // font: String? |
---|
74 | // An optional font definition (as used in the CSS font property) for labels. |
---|
75 | // fontColor: String|dojo.Color? |
---|
76 | // An optional color to be used in drawing labels. |
---|
77 | // titleGap: Number? |
---|
78 | // An optional grap between axis title and axis label |
---|
79 | // titleFont: String? |
---|
80 | // An optional font definition for axis title |
---|
81 | // titleFontColor: String? |
---|
82 | // An optional axis title color |
---|
83 | // titleOrientation: String? |
---|
84 | // An optional orientation for axis title. "axis" means the title facing the axis, "away" means facing away. |
---|
85 | // If no value is set "axis" is used. |
---|
86 | // enableCache: Boolean? |
---|
87 | // Whether the ticks and labels are cached from one rendering to another. This improves the rendering performance of |
---|
88 | // successive rendering but penalize the first rendering. For labels it is only working with gfx labels |
---|
89 | // not html ones. Default false. |
---|
90 | // dropLabels: Boolean? |
---|
91 | // Whether the axis automatically drops labels at regular interval or not to avoid labels overlapping. |
---|
92 | // This gives better results but require more computations. You can disable it to save computation |
---|
93 | // time when you know your labels won't overlap. Default is true. |
---|
94 | // labelSizeChange: Boolean? |
---|
95 | // Indicates to the axis whether the axis labels are changing their size on zoom. If false this allows to |
---|
96 | // optimize the axis by avoiding recomputing labels maximum size on zoom actions. Default is false. |
---|
97 | }; |
---|
98 | =====*/ |
---|
99 | |
---|
100 | var centerAnchorLimit = 45; // in degrees |
---|
101 | |
---|
102 | var Default = declare(has("dojo-bidi")? "dojox.charting.axis2d.NonBidiDefault" : "dojox.charting.axis2d.Default", Invisible, { |
---|
103 | // summary: |
---|
104 | // The default axis object used in dojox.charting. See dojox.charting.Chart.addAxis for details. |
---|
105 | |
---|
106 | // defaultParams: Object |
---|
107 | // The default parameters used to define any axis. |
---|
108 | // optionalParams: Object |
---|
109 | // Any optional parameters needed to define an axis. |
---|
110 | |
---|
111 | /*===== |
---|
112 | // TODO: the documentation tools need these to be pre-defined in order to pick them up |
---|
113 | // correctly, but the code here is partially predicated on whether or not the properties |
---|
114 | // actually exist. For now, we will leave these undocumented but in the code for later. -- TRT |
---|
115 | |
---|
116 | // opt: Object |
---|
117 | // The actual options used to define this axis, created at initialization. |
---|
118 | // scaler: Object |
---|
119 | // The calculated helper object to tell charts how to draw an axis and any data. |
---|
120 | // ticks: Object |
---|
121 | // The calculated tick object that helps a chart draw the scaling on an axis. |
---|
122 | // dirty: Boolean |
---|
123 | // The state of the axis (whether it needs to be redrawn or not) |
---|
124 | // scale: Number |
---|
125 | // The current scale of the axis. |
---|
126 | // offset: Number |
---|
127 | // The current offset of the axis. |
---|
128 | |
---|
129 | opt: null, |
---|
130 | scaler: null, |
---|
131 | ticks: null, |
---|
132 | dirty: true, |
---|
133 | scale: 1, |
---|
134 | offset: 0, |
---|
135 | =====*/ |
---|
136 | defaultParams: { |
---|
137 | vertical: false, // true for vertical axis |
---|
138 | fixUpper: "none", // align the upper on ticks: "major", "minor", "micro", "none" |
---|
139 | fixLower: "none", // align the lower on ticks: "major", "minor", "micro", "none" |
---|
140 | natural: false, // all tick marks should be made on natural numbers |
---|
141 | leftBottom: true, // position of the axis, used with "vertical" |
---|
142 | includeZero: false, // 0 should be included |
---|
143 | fixed: true, // all labels are fixed numbers |
---|
144 | majorLabels: true, // draw major labels |
---|
145 | minorTicks: true, // draw minor ticks |
---|
146 | minorLabels: true, // draw minor labels |
---|
147 | microTicks: false, // draw micro ticks |
---|
148 | rotation: 0, // label rotation angle in degrees |
---|
149 | htmlLabels: true, // use HTML to draw labels |
---|
150 | enableCache: false, // whether we cache or not |
---|
151 | dropLabels: true, // whether we automatically drop overlapping labels or not |
---|
152 | labelSizeChange: false // whether the labels size change on zoom |
---|
153 | }, |
---|
154 | optionalParams: { |
---|
155 | min: 0, // minimal value on this axis |
---|
156 | max: 1, // maximal value on this axis |
---|
157 | from: 0, // visible from this value |
---|
158 | to: 1, // visible to this value |
---|
159 | majorTickStep: 4, // major tick step |
---|
160 | minorTickStep: 2, // minor tick step |
---|
161 | microTickStep: 1, // micro tick step |
---|
162 | labels: [], // array of labels for major ticks |
---|
163 | // with corresponding numeric values |
---|
164 | // ordered by values |
---|
165 | labelFunc: null, // function to compute label values |
---|
166 | maxLabelSize: 0, // size in px. For use with labelFunc |
---|
167 | maxLabelCharCount: 0, // size in word count. |
---|
168 | trailingSymbol: null, |
---|
169 | |
---|
170 | // TODO: add support for minRange! |
---|
171 | // minRange: 1, // smallest distance from min allowed on the axis |
---|
172 | |
---|
173 | // theme components |
---|
174 | stroke: {}, // stroke for an axis |
---|
175 | majorTick: {}, // stroke + length for a tick |
---|
176 | minorTick: {}, // stroke + length for a tick |
---|
177 | microTick: {}, // stroke + length for a tick |
---|
178 | tick: {}, // stroke + length for a tick |
---|
179 | font: "", // font for labels |
---|
180 | fontColor: "", // color for labels as a string |
---|
181 | title: "", // axis title |
---|
182 | titleGap: 0, // gap between axis title and axis label |
---|
183 | titleFont: "", // axis title font |
---|
184 | titleFontColor: "", // axis title font color |
---|
185 | titleOrientation: "" // "axis" means the title facing the axis, "away" means facing away |
---|
186 | }, |
---|
187 | |
---|
188 | constructor: function(chart, kwArgs){ |
---|
189 | // summary: |
---|
190 | // The constructor for an axis. |
---|
191 | // chart: dojox/charting/Chart |
---|
192 | // The chart the axis belongs to. |
---|
193 | // kwArgs: __AxisCtorArgs? |
---|
194 | // Any optional keyword arguments to be used to define this axis. |
---|
195 | this.opt = lang.clone(this.defaultParams); |
---|
196 | du.updateWithObject(this.opt, kwArgs); |
---|
197 | du.updateWithPattern(this.opt, kwArgs, this.optionalParams); |
---|
198 | if(this.opt.enableCache){ |
---|
199 | this._textFreePool = []; |
---|
200 | this._lineFreePool = []; |
---|
201 | this._textUsePool = []; |
---|
202 | this._lineUsePool = []; |
---|
203 | } |
---|
204 | this._invalidMaxLabelSize = true; |
---|
205 | }, |
---|
206 | setWindow: function(scale, offset){ |
---|
207 | // summary: |
---|
208 | // Set the drawing "window" for the axis. |
---|
209 | // scale: Number |
---|
210 | // The new scale for the axis. |
---|
211 | // offset: Number |
---|
212 | // The new offset for the axis. |
---|
213 | // returns: dojox/charting/axis2d/Default |
---|
214 | // The reference to the axis for functional chaining. |
---|
215 | if(scale != this.scale){ |
---|
216 | // if scale changed we need to recompute new max label size |
---|
217 | this._invalidMaxLabelSize = true; |
---|
218 | } |
---|
219 | return this.inherited(arguments); |
---|
220 | }, |
---|
221 | |
---|
222 | _groupLabelWidth: function(labels, font, wcLimit){ |
---|
223 | if(!labels.length){ |
---|
224 | return 0; |
---|
225 | } |
---|
226 | if(labels.length > 50){ |
---|
227 | // let's avoid degenerated cases |
---|
228 | labels.length = 50; |
---|
229 | } |
---|
230 | if(lang.isObject(labels[0])){ |
---|
231 | labels = df.map(labels, function(label){ return label.text; }); |
---|
232 | } |
---|
233 | if(wcLimit){ |
---|
234 | labels = df.map(labels, function(label){ |
---|
235 | return lang.trim(label).length == 0 ? "" : label.substring(0, wcLimit) + this.trailingSymbol; |
---|
236 | }, this); |
---|
237 | } |
---|
238 | var s = labels.join("<br>"); |
---|
239 | return g._base._getTextBox(s, {font: font}).w || 0; |
---|
240 | }, |
---|
241 | |
---|
242 | _getMaxLabelSize: function(min, max, span, rotation, font, size){ |
---|
243 | if(this._maxLabelSize == null && arguments.length == 6){ |
---|
244 | var o = this.opt; |
---|
245 | // everything might have changed, reset the minMinorStep value |
---|
246 | this.scaler.minMinorStep = this._prevMinMinorStep = 0; |
---|
247 | var ob = lang.clone(o); |
---|
248 | delete ob.to; |
---|
249 | delete ob.from; |
---|
250 | // build all the ticks from min, to max not from to to _but_ using the step |
---|
251 | // that would be used if we where just displaying from to to from. |
---|
252 | var sb = lin.buildScaler(min, max, span, ob, o.to - o.from); |
---|
253 | sb.minMinorStep = 0; |
---|
254 | this._majorStart = sb.major.start; |
---|
255 | // we build all the ticks not only the ones we need to draw in order to get |
---|
256 | // a correct drop rate computation that works for any offset of this scale |
---|
257 | var tb = lin.buildTicks(sb, o); |
---|
258 | // if there is not tick at all tb is null |
---|
259 | if(size && tb){ |
---|
260 | var majLabelW = 0, minLabelW = 0; // non rotated versions |
---|
261 | // we first collect all labels when needed |
---|
262 | var tickLabelFunc = function(tick){ |
---|
263 | if(tick.label){ |
---|
264 | this.push(tick.label); |
---|
265 | } |
---|
266 | }; |
---|
267 | var labels = []; |
---|
268 | if(this.opt.majorLabels){ |
---|
269 | arr.forEach(tb.major, tickLabelFunc, labels); |
---|
270 | majLabelW = this._groupLabelWidth(labels, font, ob.maxLabelCharCount); |
---|
271 | if(ob.maxLabelSize){ |
---|
272 | majLabelW = Math.min(ob.maxLabelSize, majLabelW); |
---|
273 | } |
---|
274 | } |
---|
275 | // do the minor labels computation only if dropLabels is set |
---|
276 | labels = []; |
---|
277 | if(this.opt.dropLabels && this.opt.minorLabels){ |
---|
278 | arr.forEach(tb.minor, tickLabelFunc, labels); |
---|
279 | minLabelW = this._groupLabelWidth(labels, font, ob.maxLabelCharCount); |
---|
280 | if(ob.maxLabelSize){ |
---|
281 | minLabelW = Math.min(ob.maxLabelSize, minLabelW); |
---|
282 | } |
---|
283 | } |
---|
284 | this._maxLabelSize = { |
---|
285 | majLabelW: majLabelW, minLabelW: minLabelW, |
---|
286 | majLabelH: size, minLabelH: size |
---|
287 | }; |
---|
288 | }else{ |
---|
289 | this._maxLabelSize = null; |
---|
290 | } |
---|
291 | } |
---|
292 | return this._maxLabelSize; |
---|
293 | }, |
---|
294 | |
---|
295 | calculate: function(min, max, span){ |
---|
296 | this.inherited(arguments); |
---|
297 | // when the scale has not changed there is no reason for minMinorStep to change |
---|
298 | this.scaler.minMinorStep = this._prevMinMinorStep; |
---|
299 | // we want to recompute the dropping mechanism only when the scale or the size of the axis is changing |
---|
300 | // not when for example when we scroll (otherwise effect would be weird) |
---|
301 | if((this._invalidMaxLabelSize || span != this._oldSpan) && (min != Infinity && max != -Infinity)){ |
---|
302 | this._invalidMaxLabelSize = false; |
---|
303 | if(this.opt.labelSizeChange){ |
---|
304 | this._maxLabelSize = null; |
---|
305 | } |
---|
306 | this._oldSpan = span; |
---|
307 | var o = this.opt; |
---|
308 | var ta = this.chart.theme.axis, rotation = o.rotation % 360, |
---|
309 | labelGap = this.chart.theme.axis.tick.labelGap, |
---|
310 | // TODO: we use one font --- of major tick, we need to use major and minor fonts |
---|
311 | font = o.font || (ta.majorTick && ta.majorTick.font) || (ta.tick && ta.tick.font), |
---|
312 | size = font ? g.normalizedLength(g.splitFontString(font).size) : 0, |
---|
313 | // even if we don't drop label we need to compute max size for offsets |
---|
314 | labelW = this._getMaxLabelSize(min, max, span, rotation, font, size); |
---|
315 | if(typeof labelGap != "number"){ |
---|
316 | labelGap = 4; // in pixels |
---|
317 | } |
---|
318 | if(labelW && o.dropLabels){ |
---|
319 | var cosr = Math.abs(Math.cos(rotation * Math.PI / 180)), |
---|
320 | sinr = Math.abs(Math.sin(rotation * Math.PI / 180)); |
---|
321 | var majLabelW, minLabelW; |
---|
322 | if(rotation < 0){ |
---|
323 | rotation += 360; |
---|
324 | } |
---|
325 | switch(rotation){ |
---|
326 | case 0: |
---|
327 | case 180: |
---|
328 | // trivial cases: horizontal labels |
---|
329 | if(this.vertical){ |
---|
330 | majLabelW = minLabelW = size; |
---|
331 | }else{ |
---|
332 | majLabelW = labelW.majLabelW; |
---|
333 | minLabelW = labelW.minLabelW; |
---|
334 | } |
---|
335 | break; |
---|
336 | case 90: |
---|
337 | case 270: |
---|
338 | // trivial cases: vertical |
---|
339 | if(this.vertical){ |
---|
340 | majLabelW = labelW.majLabelW; |
---|
341 | minLabelW = labelW.minLabelW; |
---|
342 | }else{ |
---|
343 | majLabelW = minLabelW = size; |
---|
344 | } |
---|
345 | break; |
---|
346 | default: |
---|
347 | // all major labels are parallel they can't collapse except if the two ticks are |
---|
348 | // closer than the height of the text * cos(90-rotation) |
---|
349 | majLabelW = this.vertical ? Math.min(labelW.majLabelW, size / cosr) : Math.min(labelW.majLabelW, size / sinr); |
---|
350 | // for minor labels we need to rotated them |
---|
351 | var gap1 = Math.sqrt(labelW.minLabelW * labelW.minLabelW + size * size), |
---|
352 | gap2 = this.vertical ? size * cosr + labelW.minLabelW * sinr : labelW.minLabelW * cosr + size * sinr; |
---|
353 | minLabelW = Math.min(gap1, gap2); |
---|
354 | break; |
---|
355 | } |
---|
356 | // we need to check both minor and major labels fit a minor step |
---|
357 | this.scaler.minMinorStep = this._prevMinMinorStep = Math.max(majLabelW, minLabelW) + labelGap; |
---|
358 | var canMinorLabel = this.scaler.minMinorStep <= this.scaler.minor.tick * this.scaler.bounds.scale; |
---|
359 | if(!canMinorLabel){ |
---|
360 | // we can't place minor labels, let's see if we can place major ones |
---|
361 | // in a major step and if not which skip interval we must follow |
---|
362 | this._skipInterval = Math.floor((majLabelW + labelGap) / (this.scaler.major.tick * this.scaler.bounds.scale)); |
---|
363 | }else{ |
---|
364 | // everything fit well |
---|
365 | this._skipInterval = 0; |
---|
366 | } |
---|
367 | }else{ |
---|
368 | // drop label disabled |
---|
369 | this._skipInterval = 0; |
---|
370 | } |
---|
371 | } |
---|
372 | // computes the tick subset we need for that scale/offset |
---|
373 | this.ticks = lin.buildTicks(this.scaler, this.opt); |
---|
374 | return this; |
---|
375 | }, |
---|
376 | |
---|
377 | getOffsets: function(){ |
---|
378 | // summary: |
---|
379 | // Get the physical offset values for this axis (used in drawing data series). This method is not |
---|
380 | // supposed to be called by the users but internally. |
---|
381 | // returns: Object |
---|
382 | // The calculated offsets in the form of { l, r, t, b } (left, right, top, bottom). |
---|
383 | var s = this.scaler, offsets = { l: 0, r: 0, t: 0, b: 0 }; |
---|
384 | if(!s){ |
---|
385 | return offsets; |
---|
386 | } |
---|
387 | var o = this.opt, |
---|
388 | ta = this.chart.theme.axis, |
---|
389 | labelGap = this.chart.theme.axis.tick.labelGap, |
---|
390 | // TODO: we use one font --- of major tick, we need to use major and minor fonts |
---|
391 | taTitleFont = o.titleFont || (ta.title && ta.title.font), |
---|
392 | taTitleGap = (o.titleGap==0) ? 0 : o.titleGap || (ta.title && ta.title.gap), |
---|
393 | taMajorTick = this.chart.theme.getTick("major", o), |
---|
394 | taMinorTick = this.chart.theme.getTick("minor", o), |
---|
395 | tsize = taTitleFont ? g.normalizedLength(g.splitFontString(taTitleFont).size) : 0, |
---|
396 | rotation = o.rotation % 360, leftBottom = o.leftBottom, |
---|
397 | cosr = Math.abs(Math.cos(rotation * Math.PI / 180)), |
---|
398 | sinr = Math.abs(Math.sin(rotation * Math.PI / 180)); |
---|
399 | this.trailingSymbol = (o.trailingSymbol === undefined || o.trailingSymbol === null) ? |
---|
400 | this.trailingSymbol : o.trailingSymbol; |
---|
401 | if(typeof labelGap != "number"){ |
---|
402 | labelGap = 4; // in pixels |
---|
403 | } |
---|
404 | if(rotation < 0){ |
---|
405 | rotation += 360; |
---|
406 | } |
---|
407 | var maxLabelSize = this._getMaxLabelSize(); // don't need parameters, calculate has been called before => we use cached value |
---|
408 | if(maxLabelSize){ |
---|
409 | var side; |
---|
410 | var labelWidth = Math.ceil(Math.max(maxLabelSize.majLabelW, maxLabelSize.minLabelW)) + 1, |
---|
411 | size = Math.ceil(Math.max(maxLabelSize.majLabelH, maxLabelSize.minLabelH)) + 1; |
---|
412 | if(this.vertical){ |
---|
413 | side = leftBottom ? "l" : "r"; |
---|
414 | switch(rotation){ |
---|
415 | case 0: |
---|
416 | case 180: |
---|
417 | offsets[side] = labelWidth; |
---|
418 | offsets.t = offsets.b = size / 2; |
---|
419 | break; |
---|
420 | case 90: |
---|
421 | case 270: |
---|
422 | offsets[side] = size; |
---|
423 | offsets.t = offsets.b = labelWidth / 2; |
---|
424 | break; |
---|
425 | default: |
---|
426 | if(rotation <= centerAnchorLimit || (180 < rotation && rotation <= (180 + centerAnchorLimit))){ |
---|
427 | offsets[side] = size * sinr / 2 + labelWidth * cosr; |
---|
428 | offsets[leftBottom ? "t" : "b"] = size * cosr / 2 + labelWidth * sinr; |
---|
429 | offsets[leftBottom ? "b" : "t"] = size * cosr / 2; |
---|
430 | }else if(rotation > (360 - centerAnchorLimit) || (180 > rotation && rotation > (180 - centerAnchorLimit))){ |
---|
431 | offsets[side] = size * sinr / 2 + labelWidth * cosr; |
---|
432 | offsets[leftBottom ? "b" : "t"] = size * cosr / 2 + labelWidth * sinr; |
---|
433 | offsets[leftBottom ? "t" : "b"] = size * cosr / 2; |
---|
434 | }else if(rotation < 90 || (180 < rotation && rotation < 270)){ |
---|
435 | offsets[side] = size * sinr + labelWidth * cosr; |
---|
436 | offsets[leftBottom ? "t" : "b"] = size * cosr + labelWidth * sinr; |
---|
437 | }else{ |
---|
438 | offsets[side] = size * sinr + labelWidth * cosr; |
---|
439 | offsets[leftBottom ? "b" : "t"] = size * cosr + labelWidth * sinr; |
---|
440 | } |
---|
441 | break; |
---|
442 | } |
---|
443 | offsets[side] += labelGap + Math.max(taMajorTick.length > 0?taMajorTick.length:0, |
---|
444 | taMinorTick.length > 0?taMinorTick.length:0) + (o.title ? (tsize + taTitleGap) : 0); |
---|
445 | }else{ |
---|
446 | side = leftBottom ? "b" : "t"; |
---|
447 | switch(rotation){ |
---|
448 | case 0: |
---|
449 | case 180: |
---|
450 | offsets[side] = size; |
---|
451 | offsets.l = offsets.r = labelWidth / 2; |
---|
452 | break; |
---|
453 | case 90: |
---|
454 | case 270: |
---|
455 | offsets[side] = labelWidth; |
---|
456 | offsets.l = offsets.r = size / 2; |
---|
457 | break; |
---|
458 | default: |
---|
459 | if((90 - centerAnchorLimit) <= rotation && rotation <= 90 || (270 - centerAnchorLimit) <= rotation && rotation <= 270){ |
---|
460 | offsets[side] = size * cosr / 2 + labelWidth * sinr; |
---|
461 | offsets[leftBottom ? "r" : "l"] = size * sinr / 2 + labelWidth * cosr; |
---|
462 | offsets[leftBottom ? "l" : "r"] = size * sinr / 2; |
---|
463 | }else if(90 <= rotation && rotation <= (90 + centerAnchorLimit) || 270 <= rotation && rotation <= (270 + centerAnchorLimit)){ |
---|
464 | offsets[side] = size * cosr / 2 + labelWidth * sinr; |
---|
465 | offsets[leftBottom ? "l" : "r"] = size * sinr / 2 + labelWidth * cosr; |
---|
466 | offsets[leftBottom ? "r" : "l"] = size * sinr / 2; |
---|
467 | }else if(rotation < centerAnchorLimit || (180 < rotation && rotation < (180 + centerAnchorLimit))){ |
---|
468 | offsets[side] = size * cosr + labelWidth * sinr; |
---|
469 | offsets[leftBottom ? "r" : "l"] = size * sinr + labelWidth * cosr; |
---|
470 | }else{ |
---|
471 | offsets[side] = size * cosr + labelWidth * sinr; |
---|
472 | offsets[leftBottom ? "l" : "r"] = size * sinr + labelWidth * cosr; |
---|
473 | } |
---|
474 | break; |
---|
475 | } |
---|
476 | offsets[side] += labelGap + Math.max(taMajorTick.length > 0?taMajorTick.length:0, |
---|
477 | taMinorTick.length > 0?taMinorTick.length:0) + (o.title ? (tsize + taTitleGap) : 0); |
---|
478 | } |
---|
479 | } |
---|
480 | return offsets; // Object |
---|
481 | }, |
---|
482 | cleanGroup: function(creator){ |
---|
483 | if(this.opt.enableCache && this.group){ |
---|
484 | this._lineFreePool = this._lineFreePool.concat(this._lineUsePool); |
---|
485 | this._lineUsePool = []; |
---|
486 | this._textFreePool = this._textFreePool.concat(this._textUsePool); |
---|
487 | this._textUsePool = []; |
---|
488 | } |
---|
489 | this.inherited(arguments); |
---|
490 | }, |
---|
491 | createText: function(labelType, creator, x, y, align, textContent, font, fontColor, labelWidth){ |
---|
492 | if(!this.opt.enableCache || labelType=="html"){ |
---|
493 | return acommon.createText[labelType]( |
---|
494 | this.chart, |
---|
495 | creator, |
---|
496 | x, |
---|
497 | y, |
---|
498 | align, |
---|
499 | textContent, |
---|
500 | font, |
---|
501 | fontColor, |
---|
502 | labelWidth |
---|
503 | ); |
---|
504 | } |
---|
505 | var text; |
---|
506 | if(this._textFreePool.length > 0){ |
---|
507 | text = this._textFreePool.pop(); |
---|
508 | text.setShape({x: x, y: y, text: textContent, align: align}); |
---|
509 | // For now all items share the same font, no need to re-set it |
---|
510 | //.setFont(font).setFill(fontColor); |
---|
511 | // was cleared, add it back |
---|
512 | creator.add(text); |
---|
513 | }else{ |
---|
514 | text = acommon.createText[labelType]( |
---|
515 | this.chart, |
---|
516 | creator, |
---|
517 | x, |
---|
518 | y, |
---|
519 | align, |
---|
520 | textContent, |
---|
521 | font, |
---|
522 | fontColor |
---|
523 | ); |
---|
524 | } |
---|
525 | this._textUsePool.push(text); |
---|
526 | return text; |
---|
527 | }, |
---|
528 | createLine: function(creator, params){ |
---|
529 | var line; |
---|
530 | if(this.opt.enableCache && this._lineFreePool.length > 0){ |
---|
531 | line = this._lineFreePool.pop(); |
---|
532 | line.setShape(params); |
---|
533 | // was cleared, add it back |
---|
534 | creator.add(line); |
---|
535 | }else{ |
---|
536 | line = creator.createLine(params); |
---|
537 | } |
---|
538 | if(this.opt.enableCache){ |
---|
539 | this._lineUsePool.push(line); |
---|
540 | } |
---|
541 | return line; |
---|
542 | }, |
---|
543 | render: function(dim, offsets){ |
---|
544 | // summary: |
---|
545 | // Render/draw the axis. |
---|
546 | // dim: Object |
---|
547 | // An object of the form { width, height}. |
---|
548 | // offsets: Object |
---|
549 | // An object of the form { l, r, t, b }. |
---|
550 | // returns: dojox/charting/axis2d/Default |
---|
551 | // The reference to the axis for functional chaining. |
---|
552 | |
---|
553 | var isRtl = this._isRtl(); // chart mirroring |
---|
554 | if(!this.dirty || !this.scaler){ |
---|
555 | return this; // dojox/charting/axis2d/Default |
---|
556 | } |
---|
557 | // prepare variable |
---|
558 | var o = this.opt, ta = this.chart.theme.axis, leftBottom = o.leftBottom, rotation = o.rotation % 360, |
---|
559 | start, stop, titlePos, titleRotation=0, titleOffset, axisVector, tickVector, anchorOffset, labelOffset, labelAlign, |
---|
560 | labelGap = this.chart.theme.axis.tick.labelGap, |
---|
561 | // TODO: we use one font --- of major tick, we need to use major and minor fonts |
---|
562 | taFont = o.font || (ta.majorTick && ta.majorTick.font) || (ta.tick && ta.tick.font), |
---|
563 | taTitleFont = o.titleFont || (ta.title && ta.title.font), |
---|
564 | // TODO: we use one font color --- we need to use different colors |
---|
565 | taFontColor = o.fontColor || (ta.majorTick && ta.majorTick.fontColor) || (ta.tick && ta.tick.fontColor) || "black", |
---|
566 | taTitleFontColor = o.titleFontColor || (ta.title && ta.title.fontColor) || "black", |
---|
567 | taTitleGap = (o.titleGap==0) ? 0 : o.titleGap || (ta.title && ta.title.gap) || 15, |
---|
568 | taTitleOrientation = o.titleOrientation || (ta.title && ta.title.orientation) || "axis", |
---|
569 | taMajorTick = this.chart.theme.getTick("major", o), |
---|
570 | taMinorTick = this.chart.theme.getTick("minor", o), |
---|
571 | taMicroTick = this.chart.theme.getTick("micro", o), |
---|
572 | |
---|
573 | taStroke = "stroke" in o ? o.stroke : ta.stroke, |
---|
574 | size = taFont ? g.normalizedLength(g.splitFontString(taFont).size) : 0, |
---|
575 | cosr = Math.abs(Math.cos(rotation * Math.PI / 180)), |
---|
576 | sinr = Math.abs(Math.sin(rotation * Math.PI / 180)), |
---|
577 | tsize = taTitleFont ? g.normalizedLength(g.splitFontString(taTitleFont).size) : 0; |
---|
578 | if(typeof labelGap != "number"){ |
---|
579 | labelGap = 4; // in pixels |
---|
580 | } |
---|
581 | if(rotation < 0){ |
---|
582 | rotation += 360; |
---|
583 | } |
---|
584 | var cachedLabelW = this._getMaxLabelSize(); |
---|
585 | cachedLabelW = cachedLabelW && cachedLabelW.majLabelW; |
---|
586 | if(this.vertical){ |
---|
587 | start = {y: dim.height - offsets.b}; |
---|
588 | stop = {y: offsets.t}; |
---|
589 | titlePos = {y: (dim.height - offsets.b + offsets.t)/2}; |
---|
590 | titleOffset = size * sinr + (cachedLabelW || 0) * cosr + labelGap + Math.max(taMajorTick.length > 0?taMajorTick.length:0, |
---|
591 | taMinorTick.length > 0?taMinorTick.length:0) + |
---|
592 | tsize + taTitleGap; |
---|
593 | axisVector = {x: 0, y: -1}; |
---|
594 | labelOffset = {x: 0, y: 0}; |
---|
595 | tickVector = {x: 1, y: 0}; |
---|
596 | anchorOffset = {x: labelGap, y: 0}; |
---|
597 | switch(rotation){ |
---|
598 | case 0: |
---|
599 | labelAlign = "end"; |
---|
600 | labelOffset.y = size * 0.4; |
---|
601 | break; |
---|
602 | case 90: |
---|
603 | labelAlign = "middle"; |
---|
604 | labelOffset.x = -size; |
---|
605 | break; |
---|
606 | case 180: |
---|
607 | labelAlign = "start"; |
---|
608 | labelOffset.y = -size * 0.4; |
---|
609 | break; |
---|
610 | case 270: |
---|
611 | labelAlign = "middle"; |
---|
612 | break; |
---|
613 | default: |
---|
614 | if(rotation < centerAnchorLimit){ |
---|
615 | labelAlign = "end"; |
---|
616 | labelOffset.y = size * 0.4; |
---|
617 | }else if(rotation < 90){ |
---|
618 | labelAlign = "end"; |
---|
619 | labelOffset.y = size * 0.4; |
---|
620 | }else if(rotation < (180 - centerAnchorLimit)){ |
---|
621 | labelAlign = "start"; |
---|
622 | }else if(rotation < (180 + centerAnchorLimit)){ |
---|
623 | labelAlign = "start"; |
---|
624 | labelOffset.y = -size * 0.4; |
---|
625 | }else if(rotation < 270){ |
---|
626 | labelAlign = "start"; |
---|
627 | labelOffset.x = leftBottom ? 0 : size * 0.4; |
---|
628 | }else if(rotation < (360 - centerAnchorLimit)){ |
---|
629 | labelAlign = "end"; |
---|
630 | labelOffset.x = leftBottom ? 0 : size * 0.4; |
---|
631 | }else{ |
---|
632 | labelAlign = "end"; |
---|
633 | labelOffset.y = size * 0.4; |
---|
634 | } |
---|
635 | } |
---|
636 | if(leftBottom){ |
---|
637 | start.x = stop.x = offsets.l; |
---|
638 | titleRotation = (taTitleOrientation && taTitleOrientation == "away") ? 90 : 270; |
---|
639 | titlePos.x = offsets.l - titleOffset + (titleRotation == 270 ? tsize : 0); |
---|
640 | tickVector.x = -1; |
---|
641 | anchorOffset.x = -anchorOffset.x; |
---|
642 | }else{ |
---|
643 | start.x = stop.x = dim.width - offsets.r; |
---|
644 | titleRotation = (taTitleOrientation && taTitleOrientation == "axis") ? 90 : 270; |
---|
645 | titlePos.x = dim.width - offsets.r + titleOffset - (titleRotation == 270 ? 0 : tsize); |
---|
646 | switch(labelAlign){ |
---|
647 | case "start": |
---|
648 | labelAlign = "end"; |
---|
649 | break; |
---|
650 | case "end": |
---|
651 | labelAlign = "start"; |
---|
652 | break; |
---|
653 | case "middle": |
---|
654 | labelOffset.x += size; |
---|
655 | break; |
---|
656 | } |
---|
657 | } |
---|
658 | }else{ |
---|
659 | start = {x: offsets.l}; |
---|
660 | stop = {x: dim.width - offsets.r}; |
---|
661 | titlePos = {x: (dim.width - offsets.r + offsets.l)/2}; |
---|
662 | titleOffset = size * cosr + (cachedLabelW || 0) * sinr + labelGap + Math.max(taMajorTick.length > 0?taMajorTick.length:0, |
---|
663 | taMinorTick.length > 0?taMinorTick.length:0) + |
---|
664 | tsize + taTitleGap; |
---|
665 | axisVector = {x: isRtl ? -1 : 1, y: 0}; // chart mirroring |
---|
666 | labelOffset = {x: 0, y: 0}; |
---|
667 | tickVector = {x: 0, y: 1}; |
---|
668 | anchorOffset = {x: 0, y: labelGap}; |
---|
669 | switch(rotation){ |
---|
670 | case 0: |
---|
671 | labelAlign = "middle"; |
---|
672 | labelOffset.y = size; |
---|
673 | break; |
---|
674 | case 90: |
---|
675 | labelAlign = "start"; |
---|
676 | labelOffset.x = -size * 0.4; |
---|
677 | break; |
---|
678 | case 180: |
---|
679 | labelAlign = "middle"; |
---|
680 | break; |
---|
681 | case 270: |
---|
682 | labelAlign = "end"; |
---|
683 | labelOffset.x = size * 0.4; |
---|
684 | break; |
---|
685 | default: |
---|
686 | if(rotation < (90 - centerAnchorLimit)){ |
---|
687 | labelAlign = "start"; |
---|
688 | labelOffset.y = leftBottom ? size : 0; |
---|
689 | }else if(rotation < (90 + centerAnchorLimit)){ |
---|
690 | labelAlign = "start"; |
---|
691 | labelOffset.x = -size * 0.4; |
---|
692 | }else if(rotation < 180){ |
---|
693 | labelAlign = "start"; |
---|
694 | labelOffset.y = leftBottom ? 0 : -size; |
---|
695 | }else if(rotation < (270 - centerAnchorLimit)){ |
---|
696 | labelAlign = "end"; |
---|
697 | labelOffset.y = leftBottom ? 0 : -size; |
---|
698 | }else if(rotation < (270 + centerAnchorLimit)){ |
---|
699 | labelAlign = "end"; |
---|
700 | labelOffset.y = leftBottom ? size * 0.4 : 0; |
---|
701 | }else{ |
---|
702 | labelAlign = "end"; |
---|
703 | labelOffset.y = leftBottom ? size : 0; |
---|
704 | } |
---|
705 | } |
---|
706 | if(leftBottom){ |
---|
707 | start.y = stop.y = dim.height - offsets.b; |
---|
708 | titleRotation = (taTitleOrientation && taTitleOrientation == "axis") ? 180 : 0; |
---|
709 | titlePos.y = dim.height - offsets.b + titleOffset - (titleRotation ? tsize : 0); |
---|
710 | }else{ |
---|
711 | start.y = stop.y = offsets.t; |
---|
712 | titleRotation = (taTitleOrientation && taTitleOrientation == "away") ? 180 : 0; |
---|
713 | titlePos.y = offsets.t - titleOffset + (titleRotation ? 0 : tsize); |
---|
714 | tickVector.y = -1; |
---|
715 | anchorOffset.y = -anchorOffset.y; |
---|
716 | switch(labelAlign){ |
---|
717 | case "start": |
---|
718 | labelAlign = "end"; |
---|
719 | break; |
---|
720 | case "end": |
---|
721 | labelAlign = "start"; |
---|
722 | break; |
---|
723 | case "middle": |
---|
724 | labelOffset.y -= size; |
---|
725 | break; |
---|
726 | } |
---|
727 | } |
---|
728 | } |
---|
729 | |
---|
730 | // render shapes |
---|
731 | |
---|
732 | this.cleanGroup(); |
---|
733 | |
---|
734 | var s = this.group, |
---|
735 | c = this.scaler, |
---|
736 | t = this.ticks, |
---|
737 | f = lin.getTransformerFromModel(this.scaler), |
---|
738 | // GFX Canvas now supports labels, so let's _not_ fallback to HTML anymore on canvas, just use |
---|
739 | // HTML labels if explicitly asked + no rotation + no IE + no Opera |
---|
740 | labelType = (!o.title || !titleRotation) && !rotation && this.opt.htmlLabels && !has("ie") && !has("opera") ? "html" : "gfx", |
---|
741 | dx = tickVector.x * taMajorTick.length, |
---|
742 | dy = tickVector.y * taMajorTick.length, |
---|
743 | skip = this._skipInterval; |
---|
744 | |
---|
745 | s.createLine({ |
---|
746 | x1: start.x, |
---|
747 | y1: start.y, |
---|
748 | x2: stop.x, |
---|
749 | y2: stop.y |
---|
750 | }).setStroke(taStroke); |
---|
751 | |
---|
752 | //create axis title |
---|
753 | if(o.title){ |
---|
754 | var axisTitle = acommon.createText[labelType]( |
---|
755 | this.chart, |
---|
756 | s, |
---|
757 | titlePos.x, |
---|
758 | titlePos.y, |
---|
759 | "middle", |
---|
760 | o.title, |
---|
761 | taTitleFont, |
---|
762 | taTitleFontColor |
---|
763 | ); |
---|
764 | if(labelType == "html"){ |
---|
765 | this.htmlElements.push(axisTitle); |
---|
766 | }else{ |
---|
767 | //as soon as rotation is provided, labelType won't be "html" |
---|
768 | //rotate gfx labels |
---|
769 | axisTitle.setTransform(g.matrix.rotategAt(titleRotation, titlePos.x, titlePos.y)); |
---|
770 | } |
---|
771 | } |
---|
772 | |
---|
773 | // go out nicely instead of try/catch |
---|
774 | if(t == null){ |
---|
775 | this.dirty = false; |
---|
776 | return this; |
---|
777 | } |
---|
778 | |
---|
779 | var rel = (t.major.length > 0)?(t.major[0].value - this._majorStart) / c.major.tick:0; |
---|
780 | var canLabel = this.opt.majorLabels; |
---|
781 | arr.forEach(t.major, function(tick, i){ |
---|
782 | var offset = f(tick.value), elem, |
---|
783 | x = (isRtl ? stop.x : start.x) + axisVector.x * offset, // chart mirroring |
---|
784 | y = start.y + axisVector.y * offset; |
---|
785 | i += rel; |
---|
786 | this.createLine(s, { |
---|
787 | x1: x, y1: y, |
---|
788 | x2: x + dx, |
---|
789 | y2: y + dy |
---|
790 | }).setStroke(taMajorTick); |
---|
791 | if(tick.label && (!skip || (i - (1 + skip)) % (1 + skip) == 0)){ |
---|
792 | var label = o.maxLabelCharCount ? this.getTextWithLimitCharCount(tick.label, taFont, o.maxLabelCharCount) : { |
---|
793 | text: tick.label, |
---|
794 | truncated: false |
---|
795 | }; |
---|
796 | label = o.maxLabelSize ? this.getTextWithLimitLength(label.text, taFont, o.maxLabelSize, label.truncated) : label; |
---|
797 | elem = this.createText(labelType, |
---|
798 | s, |
---|
799 | x + (taMajorTick.length > 0 ? dx : 0) + anchorOffset.x + (rotation ? 0 : labelOffset.x), |
---|
800 | y + (taMajorTick.length > 0 ? dy : 0) + anchorOffset.y + (rotation ? 0 : labelOffset.y), |
---|
801 | labelAlign, |
---|
802 | label.text, |
---|
803 | taFont, |
---|
804 | taFontColor |
---|
805 | //cachedLabelW |
---|
806 | ); |
---|
807 | // if bidi support was required, the textDir is "auto" and truncation |
---|
808 | // took place, we need to update the dir of the element for cases as: |
---|
809 | // Fool label: 111111W (W for bidi character) |
---|
810 | // truncated label: 11... |
---|
811 | // in this case for auto textDir the dir will be "ltr" which is wrong. |
---|
812 | if(label.truncated){ |
---|
813 | this.chart.formatTruncatedLabel(elem, tick.label, labelType); |
---|
814 | } |
---|
815 | label.truncated && this.labelTooltip(elem, this.chart, tick.label, label.text, taFont, labelType); |
---|
816 | if(labelType == "html"){ |
---|
817 | this.htmlElements.push(elem); |
---|
818 | }else if(rotation){ |
---|
819 | elem.setTransform([ |
---|
820 | {dx: labelOffset.x, dy: labelOffset.y}, |
---|
821 | g.matrix.rotategAt( |
---|
822 | rotation, |
---|
823 | x + (taMajorTick.length > 0 ? dx : 0) + anchorOffset.x, |
---|
824 | y + (taMajorTick.length > 0 ? dy : 0) + anchorOffset.y |
---|
825 | ) |
---|
826 | ]); |
---|
827 | } |
---|
828 | } |
---|
829 | }, this); |
---|
830 | |
---|
831 | dx = tickVector.x * taMinorTick.length; |
---|
832 | dy = tickVector.y * taMinorTick.length; |
---|
833 | canLabel = this.opt.minorLabels && c.minMinorStep <= c.minor.tick * c.bounds.scale; |
---|
834 | arr.forEach(t.minor, function(tick){ |
---|
835 | var offset = f(tick.value), elem, |
---|
836 | x = (isRtl ? stop.x : start.x) + axisVector.x * offset, |
---|
837 | y = start.y + axisVector.y * offset; // chart mirroring |
---|
838 | this.createLine(s, { |
---|
839 | x1: x, y1: y, |
---|
840 | x2: x + dx, |
---|
841 | y2: y + dy |
---|
842 | }).setStroke(taMinorTick); |
---|
843 | if(canLabel && tick.label){ |
---|
844 | var label = o.maxLabelCharCount ? this.getTextWithLimitCharCount(tick.label, taFont, o.maxLabelCharCount) : { |
---|
845 | text: tick.label, |
---|
846 | truncated: false |
---|
847 | }; |
---|
848 | label = o.maxLabelSize ? this.getTextWithLimitLength(label.text, taFont, o.maxLabelSize, label.truncated) : label; |
---|
849 | elem = this.createText(labelType, |
---|
850 | s, |
---|
851 | x + (taMinorTick.length > 0 ? dx : 0) + anchorOffset.x + (rotation ? 0 : labelOffset.x), |
---|
852 | y + (taMinorTick.length > 0 ? dy : 0) + anchorOffset.y + (rotation ? 0 : labelOffset.y), |
---|
853 | labelAlign, |
---|
854 | label.text, |
---|
855 | taFont, |
---|
856 | taFontColor |
---|
857 | //cachedLabelW |
---|
858 | ); |
---|
859 | // if bidi support was required, the textDir is "auto" and truncation |
---|
860 | // took place, we need to update the dir of the element for cases as: |
---|
861 | // Fool label: 111111W (W for bidi character) |
---|
862 | // truncated label: 11... |
---|
863 | // in this case for auto textDir the dir will be "ltr" which is wrong. |
---|
864 | if(label.truncated){ |
---|
865 | this.chart.formatTruncatedLabel(elem, tick.label, labelType); |
---|
866 | } |
---|
867 | label.truncated && this.labelTooltip(elem, this.chart, tick.label, label.text, taFont, labelType); |
---|
868 | if(labelType == "html"){ |
---|
869 | this.htmlElements.push(elem); |
---|
870 | }else if(rotation){ |
---|
871 | elem.setTransform([ |
---|
872 | {dx: labelOffset.x, dy: labelOffset.y}, |
---|
873 | g.matrix.rotategAt( |
---|
874 | rotation, |
---|
875 | x + (taMinorTick.length > 0 ? dx : 0) + anchorOffset.x, |
---|
876 | y + (taMinorTick.length > 0 ? dy : 0) + anchorOffset.y |
---|
877 | ) |
---|
878 | ]); |
---|
879 | } |
---|
880 | } |
---|
881 | }, this); |
---|
882 | |
---|
883 | dx = tickVector.x * taMicroTick.length; |
---|
884 | dy = tickVector.y * taMicroTick.length; |
---|
885 | arr.forEach(t.micro, function(tick){ |
---|
886 | var offset = f(tick.value), |
---|
887 | x = start.x + axisVector.x * offset, |
---|
888 | y = start.y + axisVector.y * offset; |
---|
889 | this.createLine(s, { |
---|
890 | x1: x, y1: y, |
---|
891 | x2: x + dx, |
---|
892 | y2: y + dy |
---|
893 | }).setStroke(taMicroTick); |
---|
894 | }, this); |
---|
895 | |
---|
896 | this.dirty = false; |
---|
897 | return this; // dojox/charting/axis2d/Default |
---|
898 | }, |
---|
899 | labelTooltip: function(elem, chart, label, truncatedLabel, font, elemType){ |
---|
900 | var modules = ["dijit/Tooltip"]; |
---|
901 | var aroundRect = {type: "rect"}, position = ["above", "below"], |
---|
902 | fontWidth = g._base._getTextBox(truncatedLabel, {font: font}).w || 0, |
---|
903 | fontHeight = font ? g.normalizedLength(g.splitFontString(font).size) : 0; |
---|
904 | if(elemType == "html"){ |
---|
905 | lang.mixin(aroundRect, domGeom.position(elem.firstChild, true)); |
---|
906 | aroundRect.width = Math.ceil(fontWidth); |
---|
907 | aroundRect.height = Math.ceil(fontHeight); |
---|
908 | this._events.push({ |
---|
909 | shape: dojo, |
---|
910 | handle: connect.connect(elem.firstChild, "onmouseover", this, function(e){ |
---|
911 | require(modules, function(Tooltip){ |
---|
912 | Tooltip.show(label, aroundRect, position); |
---|
913 | }); |
---|
914 | }) |
---|
915 | }); |
---|
916 | this._events.push({ |
---|
917 | shape: dojo, |
---|
918 | handle: connect.connect(elem.firstChild, "onmouseout", this, function(e){ |
---|
919 | require(modules, function(Tooltip){ |
---|
920 | Tooltip.hide(aroundRect); |
---|
921 | }); |
---|
922 | }) |
---|
923 | }); |
---|
924 | }else{ |
---|
925 | var shp = elem.getShape(), |
---|
926 | lt = chart.getCoords(); |
---|
927 | aroundRect = lang.mixin(aroundRect, { |
---|
928 | x: shp.x - fontWidth / 2, |
---|
929 | y: shp.y |
---|
930 | }); |
---|
931 | aroundRect.x += lt.x; |
---|
932 | aroundRect.y += lt.y; |
---|
933 | aroundRect.x = Math.round(aroundRect.x); |
---|
934 | aroundRect.y = Math.round(aroundRect.y); |
---|
935 | aroundRect.width = Math.ceil(fontWidth); |
---|
936 | aroundRect.height = Math.ceil(fontHeight); |
---|
937 | this._events.push({ |
---|
938 | shape: elem, |
---|
939 | handle: elem.connect("onmouseenter", this, function(e){ |
---|
940 | require(modules, function(Tooltip){ |
---|
941 | Tooltip.show(label, aroundRect, position); |
---|
942 | }); |
---|
943 | }) |
---|
944 | }); |
---|
945 | this._events.push({ |
---|
946 | shape: elem, |
---|
947 | handle: elem.connect("onmouseleave", this, function(e){ |
---|
948 | require(modules, function(Tooltip){ |
---|
949 | Tooltip.hide(aroundRect); |
---|
950 | }); |
---|
951 | }) |
---|
952 | }); |
---|
953 | } |
---|
954 | }, |
---|
955 | _isRtl: function(){ |
---|
956 | return false; |
---|
957 | } |
---|
958 | }); |
---|
959 | return has("dojo-bidi")? declare("dojox.charting.axis2d.Default", [Default, BidiDefault]) : Default; |
---|
960 | }); |
---|