[483] | 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 | }); |
---|