Default.js 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722
  1. /*
  2. Copyright (c) 2004-2012, The Dojo Foundation All Rights Reserved.
  3. Available via Academic Free License >= 2.1 OR the modified BSD license.
  4. see: http://dojotoolkit.org/license for details
  5. */
  6. if(!dojo._hasResource["dojox.charting.axis2d.Default"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  7. dojo._hasResource["dojox.charting.axis2d.Default"] = true;
  8. dojo.provide("dojox.charting.axis2d.Default");
  9. dojo.require("dojox.charting.axis2d.Invisible");
  10. dojo.require("dojox.charting.scaler.linear");
  11. dojo.require("dojox.charting.axis2d.common");
  12. dojo.require("dojo.colors");
  13. dojo.require("dojo.string");
  14. dojo.require("dojox.gfx");
  15. dojo.require("dojox.lang.functional");
  16. dojo.require("dojox.lang.utils");
  17. /*=====
  18. dojox.charting.axis2d.__AxisCtorArgs = function(
  19. vertical, fixUpper, fixLower, natural, leftBottom,
  20. includeZero, fixed, majorLabels, minorTicks, minorLabels, microTicks, htmlLabels,
  21. min, max, from, to, majorTickStep, minorTickStep, microTickStep,
  22. labels, labelFunc, maxLabelSize,
  23. stroke, majorTick, minorTick, microTick, tick,
  24. font, fontColor
  25. ){
  26. // summary:
  27. // Optional arguments used in the definition of an axis.
  28. //
  29. // vertical: Boolean?
  30. // A flag that says whether an axis is vertical (i.e. y axis) or horizontal. Default is false (horizontal).
  31. // fixUpper: String?
  32. // Align the greatest value on the axis with the specified tick level. Options are "major", "minor", "micro", or "none". Defaults to "none".
  33. // fixLower: String?
  34. // Align the smallest value on the axis with the specified tick level. Options are "major", "minor", "micro", or "none". Defaults to "none".
  35. // natural: Boolean?
  36. // Ensure tick marks are made on "natural" numbers. Defaults to false.
  37. // leftBottom: Boolean?
  38. // The position of a vertical axis; if true, will be placed against the left-bottom corner of the chart. Defaults to true.
  39. // includeZero: Boolean?
  40. // Include 0 on the axis rendering. Default is false.
  41. // fixed: Boolean?
  42. // Force all axis labels to be fixed numbers. Default is true.
  43. // majorLabels: Boolean?
  44. // Flag to draw all labels at major ticks. Default is true.
  45. // minorTicks: Boolean?
  46. // Flag to draw minor ticks on an axis. Default is true.
  47. // minorLabels: Boolean?
  48. // Flag to draw labels on minor ticks. Default is true.
  49. // microTicks: Boolean?
  50. // Flag to draw micro ticks on an axis. Default is false.
  51. // htmlLabels: Boolean?
  52. // Flag to use HTML (as opposed to the native vector graphics engine) to draw labels. Default is true.
  53. // min: Number?
  54. // The smallest value on an axis. Default is 0.
  55. // max: Number?
  56. // The largest value on an axis. Default is 1.
  57. // from: Number?
  58. // Force the chart to render data visible from this value. Default is 0.
  59. // to: Number?
  60. // Force the chart to render data visible to this value. Default is 1.
  61. // majorTickStep: Number?
  62. // The amount to skip before a major tick is drawn. Default is 4.
  63. // minorTickStep: Number?
  64. // The amount to skip before a minor tick is drawn. Default is 2.
  65. // microTickStep: Number?
  66. // The amount to skip before a micro tick is drawn. Default is 1.
  67. // labels: Object[]?
  68. // An array of labels for major ticks, with corresponding numeric values, ordered by value.
  69. // labelFunc: Function?
  70. // An optional function used to compute label values.
  71. // maxLabelSize: Number?
  72. // The maximum size, in pixels, for a label. To be used with the optional label function.
  73. // stroke: dojox.gfx.Stroke?
  74. // An optional stroke to be used for drawing an axis.
  75. // majorTick: Object?
  76. // An object containing a dojox.gfx.Stroke, and a length (number) for a major tick.
  77. // minorTick: Object?
  78. // An object containing a dojox.gfx.Stroke, and a length (number) for a minor tick.
  79. // microTick: Object?
  80. // An object containing a dojox.gfx.Stroke, and a length (number) for a micro tick.
  81. // tick: Object?
  82. // An object containing a dojox.gfx.Stroke, and a length (number) for a tick.
  83. // font: String?
  84. // An optional font definition (as used in the CSS font property) for labels.
  85. // fontColor: String|dojo.Color?
  86. // An optional color to be used in drawing labels.
  87. this.vertical = vertical;
  88. this.fixUpper = fixUpper;
  89. this.fixLower = fixLower;
  90. this.natural = natural;
  91. this.leftBottom = leftBottom;
  92. this.includeZero = includeZero;
  93. this.fixed = fixed;
  94. this.majorLabels = majorLabels;
  95. this.minorTicks = minorTicks;
  96. this.minorLabels = minorLabels;
  97. this.microTicks = microTicks;
  98. this.htmlLabels = htmlLabels;
  99. this.min = min;
  100. this.max = max;
  101. this.from = from;
  102. this.to = to;
  103. this.majorTickStep = majorTickStep;
  104. this.minorTickStep = minorTickStep;
  105. this.microTickStep = microTickStep;
  106. this.labels = labels;
  107. this.labelFunc = labelFunc;
  108. this.maxLabelSize = maxLabelSize;
  109. this.stroke = stroke;
  110. this.majorTick = majorTick;
  111. this.minorTick = minorTick;
  112. this.microTick = microTick;
  113. this.tick = tick;
  114. this.font = font;
  115. this.fontColor = fontColor;
  116. }
  117. =====*/
  118. (function(){
  119. var dc = dojox.charting,
  120. du = dojox.lang.utils,
  121. g = dojox.gfx,
  122. lin = dc.scaler.linear,
  123. labelGap = 4, // in pixels
  124. centerAnchorLimit = 45; // in degrees
  125. dojo.declare("dojox.charting.axis2d.Default", dojox.charting.axis2d.Invisible, {
  126. // summary:
  127. // The default axis object used in dojox.charting. See dojox.charting.Chart.addAxis for details.
  128. //
  129. // defaultParams: Object
  130. // The default parameters used to define any axis.
  131. // optionalParams: Object
  132. // Any optional parameters needed to define an axis.
  133. /*
  134. // TODO: the documentation tools need these to be pre-defined in order to pick them up
  135. // correctly, but the code here is partially predicated on whether or not the properties
  136. // actually exist. For now, we will leave these undocumented but in the code for later. -- TRT
  137. // opt: Object
  138. // The actual options used to define this axis, created at initialization.
  139. // scalar: Object
  140. // The calculated helper object to tell charts how to draw an axis and any data.
  141. // ticks: Object
  142. // The calculated tick object that helps a chart draw the scaling on an axis.
  143. // dirty: Boolean
  144. // The state of the axis (whether it needs to be redrawn or not)
  145. // scale: Number
  146. // The current scale of the axis.
  147. // offset: Number
  148. // The current offset of the axis.
  149. opt: null,
  150. scalar: null,
  151. ticks: null,
  152. dirty: true,
  153. scale: 1,
  154. offset: 0,
  155. */
  156. defaultParams: {
  157. vertical: false, // true for vertical axis
  158. fixUpper: "none", // align the upper on ticks: "major", "minor", "micro", "none"
  159. fixLower: "none", // align the lower on ticks: "major", "minor", "micro", "none"
  160. natural: false, // all tick marks should be made on natural numbers
  161. leftBottom: true, // position of the axis, used with "vertical"
  162. includeZero: false, // 0 should be included
  163. fixed: true, // all labels are fixed numbers
  164. majorLabels: true, // draw major labels
  165. minorTicks: true, // draw minor ticks
  166. minorLabels: true, // draw minor labels
  167. microTicks: false, // draw micro ticks
  168. rotation: 0, // label rotation angle in degrees
  169. htmlLabels: true // use HTML to draw labels
  170. },
  171. optionalParams: {
  172. min: 0, // minimal value on this axis
  173. max: 1, // maximal value on this axis
  174. from: 0, // visible from this value
  175. to: 1, // visible to this value
  176. majorTickStep: 4, // major tick step
  177. minorTickStep: 2, // minor tick step
  178. microTickStep: 1, // micro tick step
  179. labels: [], // array of labels for major ticks
  180. // with corresponding numeric values
  181. // ordered by values
  182. labelFunc: null, // function to compute label values
  183. maxLabelSize: 0, // size in px. For use with labelFunc
  184. maxLabelCharCount: 0, // size in word count.
  185. trailingSymbol: null,
  186. // TODO: add support for minRange!
  187. // minRange: 1, // smallest distance from min allowed on the axis
  188. // theme components
  189. stroke: {}, // stroke for an axis
  190. majorTick: {}, // stroke + length for a tick
  191. minorTick: {}, // stroke + length for a tick
  192. microTick: {}, // stroke + length for a tick
  193. tick: {}, // stroke + length for a tick
  194. font: "", // font for labels
  195. fontColor: "", // color for labels as a string
  196. title: "", // axis title
  197. titleGap: 0, // gap between axis title and axis label
  198. titleFont: "", // axis title font
  199. titleFontColor: "", // axis title font color
  200. titleOrientation: "" // "axis" means the title facing the axis, "away" means facing away
  201. },
  202. constructor: function(chart, kwArgs){
  203. // summary:
  204. // The constructor for an axis.
  205. // chart: dojox.charting.Chart2D
  206. // The chart the axis belongs to.
  207. // kwArgs: dojox.charting.axis2d.__AxisCtorArgs?
  208. // Any optional keyword arguments to be used to define this axis.
  209. this.opt = dojo.clone(this.defaultParams);
  210. du.updateWithObject(this.opt, kwArgs);
  211. du.updateWithPattern(this.opt, kwArgs, this.optionalParams);
  212. },
  213. getOffsets: function(){
  214. // summary:
  215. // Get the physical offset values for this axis (used in drawing data series).
  216. // returns: Object
  217. // The calculated offsets in the form of { l, r, t, b } (left, right, top, bottom).
  218. var s = this.scaler, offsets = { l: 0, r: 0, t: 0, b: 0 };
  219. if(!s){
  220. return offsets;
  221. }
  222. var o = this.opt, labelWidth = 0, a, b, c, d,
  223. gl = dc.scaler.common.getNumericLabel,
  224. offset = 0, ma = s.major, mi = s.minor,
  225. ta = this.chart.theme.axis,
  226. // TODO: we use one font --- of major tick, we need to use major and minor fonts
  227. taFont = o.font || (ta.majorTick && ta.majorTick.font) || (ta.tick && ta.tick.font),
  228. taTitleFont = o.titleFont || (ta.tick && ta.tick.titleFont),
  229. taTitleGap = (o.titleGap==0) ? 0 : o.titleGap || (ta.tick && ta.tick.titleGap) || 15,
  230. taMajorTick = this.chart.theme.getTick("major", o),
  231. taMinorTick = this.chart.theme.getTick("minor", o),
  232. size = taFont ? g.normalizedLength(g.splitFontString(taFont).size) : 0,
  233. tsize = taTitleFont ? g.normalizedLength(g.splitFontString(taTitleFont).size) : 0,
  234. rotation = o.rotation % 360, leftBottom = o.leftBottom,
  235. cosr = Math.abs(Math.cos(rotation * Math.PI / 180)),
  236. sinr = Math.abs(Math.sin(rotation * Math.PI / 180));
  237. this.trailingSymbol = (o.trailingSymbol === undefined || o.trailingSymbol === null) ? this.trailingSymbol : o.trailingSymbol;
  238. if(rotation < 0){
  239. rotation += 360;
  240. }
  241. if(size){
  242. // we need width of all labels
  243. if(this.labels){
  244. labelWidth = this._groupLabelWidth(this.labels, taFont, o.maxLabelCharCount);
  245. }else{
  246. labelWidth = this._groupLabelWidth([
  247. gl(ma.start, ma.prec, o),
  248. gl(ma.start + ma.count * ma.tick, ma.prec, o),
  249. gl(mi.start, mi.prec, o),
  250. gl(mi.start + mi.count * mi.tick, mi.prec, o)
  251. ], taFont, o.maxLabelCharCount);
  252. }
  253. labelWidth = o.maxLabelSize ? Math.min(o.maxLabelSize, labelWidth) : labelWidth;
  254. if(this.vertical){
  255. var side = leftBottom ? "l" : "r";
  256. switch(rotation){
  257. case 0:
  258. case 180:
  259. offsets[side] = labelWidth;
  260. offsets.t = offsets.b = size / 2;
  261. break;
  262. case 90:
  263. case 270:
  264. offsets[side] = size;
  265. offsets.t = offsets.b = labelWidth / 2;
  266. break;
  267. default:
  268. if(rotation <= centerAnchorLimit || (180 < rotation && rotation <= (180 + centerAnchorLimit))){
  269. offsets[side] = size * sinr / 2 + labelWidth * cosr;
  270. offsets[leftBottom ? "t" : "b"] = size * cosr / 2 + labelWidth * sinr;
  271. offsets[leftBottom ? "b" : "t"] = size * cosr / 2;
  272. }else if(rotation > (360 - centerAnchorLimit) || (180 > rotation && rotation > (180 - centerAnchorLimit))){
  273. offsets[side] = size * sinr / 2 + labelWidth * cosr;
  274. offsets[leftBottom ? "b" : "t"] = size * cosr / 2 + labelWidth * sinr;
  275. offsets[leftBottom ? "t" : "b"] = size * cosr / 2;
  276. }else if(rotation < 90 || (180 < rotation && rotation < 270)){
  277. offsets[side] = size * sinr + labelWidth * cosr;
  278. offsets[leftBottom ? "t" : "b"] = size * cosr + labelWidth * sinr;
  279. }else{
  280. offsets[side] = size * sinr + labelWidth * cosr;
  281. offsets[leftBottom ? "b" : "t"] = size * cosr + labelWidth * sinr;
  282. }
  283. break;
  284. }
  285. offsets[side] += labelGap + Math.max(taMajorTick.length, taMinorTick.length) + (o.title ? (tsize + taTitleGap) : 0);
  286. }else{
  287. var side = leftBottom ? "b" : "t";
  288. switch(rotation){
  289. case 0:
  290. case 180:
  291. offsets[side] = size;
  292. offsets.l = offsets.r = labelWidth / 2;
  293. break;
  294. case 90:
  295. case 270:
  296. offsets[side] = labelWidth;
  297. offsets.l = offsets.r = size / 2;
  298. break;
  299. default:
  300. if((90 - centerAnchorLimit) <= rotation && rotation <= 90 || (270 - centerAnchorLimit) <= rotation && rotation <= 270){
  301. offsets[side] = size * sinr / 2 + labelWidth * cosr;
  302. offsets[leftBottom ? "r" : "l"] = size * cosr / 2 + labelWidth * sinr;
  303. offsets[leftBottom ? "l" : "r"] = size * cosr / 2;
  304. }else if(90 <= rotation && rotation <= (90 + centerAnchorLimit) || 270 <= rotation && rotation <= (270 + centerAnchorLimit)){
  305. offsets[side] = size * sinr / 2 + labelWidth * cosr;
  306. offsets[leftBottom ? "l" : "r"] = size * cosr / 2 + labelWidth * sinr;
  307. offsets[leftBottom ? "r" : "l"] = size * cosr / 2;
  308. }else if(rotation < centerAnchorLimit || (180 < rotation && rotation < (180 - centerAnchorLimit))){
  309. offsets[side] = size * sinr + labelWidth * cosr;
  310. offsets[leftBottom ? "r" : "l"] = size * cosr + labelWidth * sinr;
  311. }else{
  312. offsets[side] = size * sinr + labelWidth * cosr;
  313. offsets[leftBottom ? "l" : "r"] = size * cosr + labelWidth * sinr;
  314. }
  315. break;
  316. }
  317. offsets[side] += labelGap + Math.max(taMajorTick.length, taMinorTick.length) + (o.title ? (tsize + taTitleGap) : 0);
  318. }
  319. }
  320. if(labelWidth){
  321. this._cachedLabelWidth = labelWidth;
  322. }
  323. return offsets; // Object
  324. },
  325. render: function(dim, offsets){
  326. // summary:
  327. // Render/draw the axis.
  328. // dim: Object
  329. // An object of the form { width, height}.
  330. // offsets: Object
  331. // An object of the form { l, r, t, b }.
  332. // returns: dojox.charting.axis2d.Default
  333. // The reference to the axis for functional chaining.
  334. if(!this.dirty){
  335. return this; // dojox.charting.axis2d.Default
  336. }
  337. // prepare variable
  338. var o = this.opt, ta = this.chart.theme.axis, leftBottom = o.leftBottom, rotation = o.rotation % 360,
  339. start, stop, titlePos, titleRotation=0, titleOffset, axisVector, tickVector, anchorOffset, labelOffset, labelAlign,
  340. // TODO: we use one font --- of major tick, we need to use major and minor fonts
  341. taFont = o.font || (ta.majorTick && ta.majorTick.font) || (ta.tick && ta.tick.font),
  342. taTitleFont = o.titleFont || (ta.tick && ta.tick.titleFont),
  343. // TODO: we use one font color --- we need to use different colors
  344. taFontColor = o.fontColor || (ta.majorTick && ta.majorTick.fontColor) || (ta.tick && ta.tick.fontColor) || "black",
  345. taTitleFontColor = o.titleFontColor || (ta.tick && ta.tick.titleFontColor) || "black",
  346. taTitleGap = (o.titleGap==0) ? 0 : o.titleGap || (ta.tick && ta.tick.titleGap) || 15,
  347. taTitleOrientation = o.titleOrientation || (ta.tick && ta.tick.titleOrientation) || "axis",
  348. taMajorTick = this.chart.theme.getTick("major", o),
  349. taMinorTick = this.chart.theme.getTick("minor", o),
  350. taMicroTick = this.chart.theme.getTick("micro", o),
  351. tickSize = Math.max(taMajorTick.length, taMinorTick.length, taMicroTick.length),
  352. taStroke = "stroke" in o ? o.stroke : ta.stroke,
  353. size = taFont ? g.normalizedLength(g.splitFontString(taFont).size) : 0,
  354. cosr = Math.abs(Math.cos(rotation * Math.PI / 180)),
  355. sinr = Math.abs(Math.sin(rotation * Math.PI / 180)),
  356. tsize = taTitleFont ? g.normalizedLength(g.splitFontString(taTitleFont).size) : 0;
  357. if(rotation < 0){
  358. rotation += 360;
  359. }
  360. if(this.vertical){
  361. start = {y: dim.height - offsets.b};
  362. stop = {y: offsets.t};
  363. titlePos = {y: (dim.height - offsets.b + offsets.t)/2};
  364. titleOffset = size * sinr + (this._cachedLabelWidth || 0) * cosr + labelGap + Math.max(taMajorTick.length, taMinorTick.length) + tsize + taTitleGap;
  365. axisVector = {x: 0, y: -1};
  366. labelOffset = {x: 0, y: 0};
  367. tickVector = {x: 1, y: 0};
  368. anchorOffset = {x: labelGap, y: 0};
  369. switch(rotation){
  370. case 0:
  371. labelAlign = "end";
  372. labelOffset.y = size * 0.4;
  373. break;
  374. case 90:
  375. labelAlign = "middle";
  376. labelOffset.x = -size;
  377. break;
  378. case 180:
  379. labelAlign = "start";
  380. labelOffset.y = -size * 0.4;
  381. break;
  382. case 270:
  383. labelAlign = "middle";
  384. break;
  385. default:
  386. if(rotation < centerAnchorLimit){
  387. labelAlign = "end";
  388. labelOffset.y = size * 0.4;
  389. }else if(rotation < 90){
  390. labelAlign = "end";
  391. labelOffset.y = size * 0.4;
  392. }else if(rotation < (180 - centerAnchorLimit)){
  393. labelAlign = "start";
  394. }else if(rotation < (180 + centerAnchorLimit)){
  395. labelAlign = "start";
  396. labelOffset.y = -size * 0.4;
  397. }else if(rotation < 270){
  398. labelAlign = "start";
  399. labelOffset.x = leftBottom ? 0 : size * 0.4;
  400. }else if(rotation < (360 - centerAnchorLimit)){
  401. labelAlign = "end";
  402. labelOffset.x = leftBottom ? 0 : size * 0.4;
  403. }else{
  404. labelAlign = "end";
  405. labelOffset.y = size * 0.4;
  406. }
  407. }
  408. if(leftBottom){
  409. start.x = stop.x = offsets.l;
  410. titleRotation = (taTitleOrientation && taTitleOrientation == "away") ? 90 : 270;
  411. titlePos.x = offsets.l - titleOffset + (titleRotation == 270 ? tsize : 0);
  412. tickVector.x = -1;
  413. anchorOffset.x = -anchorOffset.x;
  414. }else{
  415. start.x = stop.x = dim.width - offsets.r;
  416. titleRotation = (taTitleOrientation && taTitleOrientation == "axis") ? 90 : 270;
  417. titlePos.x = dim.width - offsets.r + titleOffset - (titleRotation == 270 ? 0 : tsize);
  418. switch(labelAlign){
  419. case "start":
  420. labelAlign = "end";
  421. break;
  422. case "end":
  423. labelAlign = "start";
  424. break;
  425. case "middle":
  426. labelOffset.x += size;
  427. break;
  428. }
  429. }
  430. }else{
  431. start = {x: offsets.l};
  432. stop = {x: dim.width - offsets.r};
  433. titlePos = {x: (dim.width - offsets.r + offsets.l)/2};
  434. titleOffset = size * cosr + (this._cachedLabelWidth || 0) * sinr + labelGap + Math.max(taMajorTick.length, taMinorTick.length) + tsize + taTitleGap;
  435. axisVector = {x: 1, y: 0};
  436. labelOffset = {x: 0, y: 0};
  437. tickVector = {x: 0, y: 1};
  438. anchorOffset = {x: 0, y: labelGap};
  439. switch(rotation){
  440. case 0:
  441. labelAlign = "middle";
  442. labelOffset.y = size;
  443. break;
  444. case 90:
  445. labelAlign = "start";
  446. labelOffset.x = -size * 0.4;
  447. break;
  448. case 180:
  449. labelAlign = "middle";
  450. break;
  451. case 270:
  452. labelAlign = "end";
  453. labelOffset.x = size * 0.4;
  454. break;
  455. default:
  456. if(rotation < (90 - centerAnchorLimit)){
  457. labelAlign = "start";
  458. labelOffset.y = leftBottom ? size : 0;
  459. }else if(rotation < (90 + centerAnchorLimit)){
  460. labelAlign = "start";
  461. labelOffset.x = -size * 0.4;
  462. }else if(rotation < 180){
  463. labelAlign = "start";
  464. labelOffset.y = leftBottom ? 0 : -size;
  465. }else if(rotation < (270 - centerAnchorLimit)){
  466. labelAlign = "end";
  467. labelOffset.y = leftBottom ? 0 : -size;
  468. }else if(rotation < (270 + centerAnchorLimit)){
  469. labelAlign = "end";
  470. labelOffset.y = leftBottom ? size * 0.4 : 0;
  471. }else{
  472. labelAlign = "end";
  473. labelOffset.y = leftBottom ? size : 0;
  474. }
  475. }
  476. if(leftBottom){
  477. start.y = stop.y = dim.height - offsets.b;
  478. titleRotation = (taTitleOrientation && taTitleOrientation == "axis") ? 180 : 0;
  479. titlePos.y = dim.height - offsets.b + titleOffset - (titleRotation ? tsize : 0);
  480. }else{
  481. start.y = stop.y = offsets.t;
  482. titleRotation = (taTitleOrientation && taTitleOrientation == "away") ? 180 : 0;
  483. titlePos.y = offsets.t - titleOffset + (titleRotation ? 0 : tsize);
  484. tickVector.y = -1;
  485. anchorOffset.y = -anchorOffset.y;
  486. switch(labelAlign){
  487. case "start":
  488. labelAlign = "end";
  489. break;
  490. case "end":
  491. labelAlign = "start";
  492. break;
  493. case "middle":
  494. labelOffset.y -= size;
  495. break;
  496. }
  497. }
  498. }
  499. // render shapes
  500. this.cleanGroup();
  501. try{
  502. var s = this.group,
  503. c = this.scaler,
  504. t = this.ticks,
  505. canLabel,
  506. f = lin.getTransformerFromModel(this.scaler),
  507. // GFX Canvas now supports labels, so let's _not_ fallback to HTML anymore on canvas, just use
  508. // HTML labels if explicitly asked + no rotation + no IE + no Opera
  509. labelType = !titleRotation && !rotation && this.opt.htmlLabels && !dojo.isIE && !dojo.isOpera ? "html" : "gfx",
  510. dx = tickVector.x * taMajorTick.length,
  511. dy = tickVector.y * taMajorTick.length;
  512. s.createLine({
  513. x1: start.x,
  514. y1: start.y,
  515. x2: stop.x,
  516. y2: stop.y
  517. }).setStroke(taStroke);
  518. //create axis title
  519. if(o.title){
  520. var axisTitle = dc.axis2d.common.createText[labelType](
  521. this.chart,
  522. s,
  523. titlePos.x,
  524. titlePos.y,
  525. "middle",
  526. o.title,
  527. taTitleFont,
  528. taTitleFontColor
  529. );
  530. if(labelType == "html"){
  531. this.htmlElements.push(axisTitle);
  532. }else{
  533. //as soon as rotation is provided, labelType won't be "html"
  534. //rotate gfx labels
  535. axisTitle.setTransform(g.matrix.rotategAt(titleRotation, titlePos.x, titlePos.y));
  536. }
  537. }
  538. dojo.forEach(t.major, function(tick){
  539. var offset = f(tick.value), elem,
  540. x = start.x + axisVector.x * offset,
  541. y = start.y + axisVector.y * offset;
  542. s.createLine({
  543. x1: x, y1: y,
  544. x2: x + dx,
  545. y2: y + dy
  546. }).setStroke(taMajorTick);
  547. if(tick.label){
  548. var label = o.maxLabelCharCount ? this.getTextWithLimitCharCount(tick.label, taFont, o.maxLabelCharCount) : {
  549. text: tick.label,
  550. truncated: false
  551. };
  552. label = o.maxLabelSize ? this.getTextWithLimitLength(label.text, taFont, o.maxLabelSize, label.truncated) : label;
  553. elem = dc.axis2d.common.createText[labelType](
  554. this.chart,
  555. s,
  556. x + dx + anchorOffset.x + (rotation ? 0 : labelOffset.x),
  557. y + dy + anchorOffset.y + (rotation ? 0 : labelOffset.y),
  558. labelAlign,
  559. label.text,
  560. taFont,
  561. taFontColor
  562. //this._cachedLabelWidth
  563. );
  564. label.truncated && this.labelTooltip(elem, this.chart, tick.label, label.text, taFont, labelType);
  565. if(labelType == "html"){
  566. this.htmlElements.push(elem);
  567. }else if(rotation){
  568. elem.setTransform([
  569. {dx: labelOffset.x, dy: labelOffset.y},
  570. g.matrix.rotategAt(
  571. rotation,
  572. x + dx + anchorOffset.x,
  573. y + dy + anchorOffset.y
  574. )
  575. ]);
  576. }
  577. }
  578. }, this);
  579. dx = tickVector.x * taMinorTick.length;
  580. dy = tickVector.y * taMinorTick.length;
  581. canLabel = c.minMinorStep <= c.minor.tick * c.bounds.scale;
  582. dojo.forEach(t.minor, function(tick){
  583. var offset = f(tick.value), elem,
  584. x = start.x + axisVector.x * offset,
  585. y = start.y + axisVector.y * offset;
  586. s.createLine({
  587. x1: x, y1: y,
  588. x2: x + dx,
  589. y2: y + dy
  590. }).setStroke(taMinorTick);
  591. if(canLabel && tick.label){
  592. var label = o.maxLabelCharCount ? this.getTextWithLimitCharCount(tick.label, taFont, o.maxLabelCharCount) : {
  593. text: tick.label,
  594. truncated: false
  595. };
  596. label = o.maxLabelSize ? this.getTextWithLimitLength(label.text, taFont, o.maxLabelSize, label.truncated) : label;
  597. elem = dc.axis2d.common.createText[labelType](
  598. this.chart,
  599. s,
  600. x + dx + anchorOffset.x + (rotation ? 0 : labelOffset.x),
  601. y + dy + anchorOffset.y + (rotation ? 0 : labelOffset.y),
  602. labelAlign,
  603. label.text,
  604. taFont,
  605. taFontColor
  606. //this._cachedLabelWidth
  607. );
  608. label.truncated && this.labelTooltip(elem, this.chart, tick.label, label.text, taFont, labelType);
  609. if(labelType == "html"){
  610. this.htmlElements.push(elem);
  611. }else if(rotation){
  612. elem.setTransform([
  613. {dx: labelOffset.x, dy: labelOffset.y},
  614. g.matrix.rotategAt(
  615. rotation,
  616. x + dx + anchorOffset.x,
  617. y + dy + anchorOffset.y
  618. )
  619. ]);
  620. }
  621. }
  622. }, this);
  623. dx = tickVector.x * taMicroTick.length;
  624. dy = tickVector.y * taMicroTick.length;
  625. dojo.forEach(t.micro, function(tick){
  626. var offset = f(tick.value), elem,
  627. x = start.x + axisVector.x * offset,
  628. y = start.y + axisVector.y * offset;
  629. s.createLine({
  630. x1: x, y1: y,
  631. x2: x + dx,
  632. y2: y + dy
  633. }).setStroke(taMicroTick);
  634. }, this);
  635. }catch(e){
  636. // squelch
  637. }
  638. this.dirty = false;
  639. return this; // dojox.charting.axis2d.Default
  640. },
  641. labelTooltip: function(elem, chart, label, truncatedLabel, font, elemType){
  642. // to avoid requiring dijit module for that feature, let's test that
  643. // dynamically and return if we can't do it
  644. if(!dijit || !dijit.Tooltip){
  645. return;
  646. }
  647. var aroundRect = {type: "rect"}, position = ["above", "below"],
  648. fontWidth = dojox.gfx._base._getTextBox(truncatedLabel, {font: font}).w || 0;
  649. fontHeight = font ? g.normalizedLength(g.splitFontString(font).size) : 0;
  650. if(elemType == "html"){
  651. dojo.mixin(aroundRect, dojo.coords(elem.firstChild, true));
  652. aroundRect.width = Math.ceil(fontWidth);
  653. aroundRect.height = Math.ceil(fontHeight);
  654. this._events.push({
  655. shape: dojo,
  656. handle: dojo.connect(elem.firstChild, "onmouseover", this, function(e){
  657. dijit.showTooltip(label, aroundRect, position);
  658. })
  659. });
  660. this._events.push({
  661. shape: dojo,
  662. handle: dojo.connect(elem.firstChild, "onmouseout", this, function(e){
  663. dijit.hideTooltip(aroundRect);
  664. })
  665. });
  666. }else{
  667. var shp = elem.getShape(),
  668. lt = dojo.coords(chart.node, true);
  669. aroundRect = dojo.mixin(aroundRect, {
  670. x: shp.x - fontWidth / 2,
  671. y: shp.y
  672. });
  673. aroundRect.x += lt.x;
  674. aroundRect.y += lt.y;
  675. aroundRect.x = Math.round(aroundRect.x);
  676. aroundRect.y = Math.round(aroundRect.y);
  677. aroundRect.width = Math.ceil(fontWidth);
  678. aroundRect.height = Math.ceil(fontHeight);
  679. this._events.push({
  680. shape: elem,
  681. handle: elem.connect("onmouseenter", this, function(e){
  682. dijit.showTooltip(label, aroundRect, position);
  683. })
  684. });
  685. this._events.push({
  686. shape: elem,
  687. handle: elem.connect("onmouseleave", this, function(e){
  688. dijit.hideTooltip(aroundRect);
  689. })
  690. });
  691. }
  692. }
  693. });
  694. })();
  695. }