Invisible.js 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. define("dojox/charting/axis2d/Invisible", ["dojo/_base/lang", "dojo/_base/declare", "./Base", "../scaler/linear",
  2. "dojox/gfx", "dojox/lang/utils", "dojox/lang/functional", "dojo/string"],
  3. function(lang, declare, Base, lin, g, du, df, dstring){
  4. /*=====
  5. var Base = dojox.charting.axis2d.Base;
  6. =====*/
  7. var merge = du.merge,
  8. labelGap = 4, // in pixels
  9. centerAnchorLimit = 45; // in degrees
  10. return declare("dojox.charting.axis2d.Invisible", Base, {
  11. // summary:
  12. // The default axis object used in dojox.charting. See dojox.charting.Chart.addAxis for details.
  13. //
  14. // defaultParams: Object
  15. // The default parameters used to define any axis.
  16. // optionalParams: Object
  17. // Any optional parameters needed to define an axis.
  18. /*
  19. // TODO: the documentation tools need these to be pre-defined in order to pick them up
  20. // correctly, but the code here is partially predicated on whether or not the properties
  21. // actually exist. For now, we will leave these undocumented but in the code for later. -- TRT
  22. // opt: Object
  23. // The actual options used to define this axis, created at initialization.
  24. // scalar: Object
  25. // The calculated helper object to tell charts how to draw an axis and any data.
  26. // ticks: Object
  27. // The calculated tick object that helps a chart draw the scaling on an axis.
  28. // dirty: Boolean
  29. // The state of the axis (whether it needs to be redrawn or not)
  30. // scale: Number
  31. // The current scale of the axis.
  32. // offset: Number
  33. // The current offset of the axis.
  34. opt: null,
  35. scalar: null,
  36. ticks: null,
  37. dirty: true,
  38. scale: 1,
  39. offset: 0,
  40. */
  41. defaultParams: {
  42. vertical: false, // true for vertical axis
  43. fixUpper: "none", // align the upper on ticks: "major", "minor", "micro", "none"
  44. fixLower: "none", // align the lower on ticks: "major", "minor", "micro", "none"
  45. natural: false, // all tick marks should be made on natural numbers
  46. leftBottom: true, // position of the axis, used with "vertical"
  47. includeZero: false, // 0 should be included
  48. fixed: true, // all labels are fixed numbers
  49. majorLabels: true, // draw major labels
  50. minorTicks: true, // draw minor ticks
  51. minorLabels: true, // draw minor labels
  52. microTicks: false, // draw micro ticks
  53. rotation: 0 // label rotation angle in degrees
  54. },
  55. optionalParams: {
  56. min: 0, // minimal value on this axis
  57. max: 1, // maximal value on this axis
  58. from: 0, // visible from this value
  59. to: 1, // visible to this value
  60. majorTickStep: 4, // major tick step
  61. minorTickStep: 2, // minor tick step
  62. microTickStep: 1, // micro tick step
  63. labels: [], // array of labels for major ticks
  64. // with corresponding numeric values
  65. // ordered by values
  66. labelFunc: null, // function to compute label values
  67. maxLabelSize: 0, // size in px. For use with labelFunc
  68. maxLabelCharCount: 0, // size in word count.
  69. trailingSymbol: null
  70. // TODO: add support for minRange!
  71. // minRange: 1, // smallest distance from min allowed on the axis
  72. },
  73. constructor: function(chart, kwArgs){
  74. // summary:
  75. // The constructor for an axis.
  76. // chart: dojox.charting.Chart
  77. // The chart the axis belongs to.
  78. // kwArgs: dojox.charting.axis2d.__AxisCtorArgs?
  79. // Any optional keyword arguments to be used to define this axis.
  80. this.opt = lang.clone(this.defaultParams);
  81. du.updateWithObject(this.opt, kwArgs);
  82. du.updateWithPattern(this.opt, kwArgs, this.optionalParams);
  83. },
  84. dependOnData: function(){
  85. // summary:
  86. // Find out whether or not the axis options depend on the data in the axis.
  87. return !("min" in this.opt) || !("max" in this.opt); // Boolean
  88. },
  89. clear: function(){
  90. // summary:
  91. // Clear out all calculated properties on this axis;
  92. // returns: dojox.charting.axis2d.Default
  93. // The reference to the axis for functional chaining.
  94. delete this.scaler;
  95. delete this.ticks;
  96. this.dirty = true;
  97. return this; // dojox.charting.axis2d.Default
  98. },
  99. initialized: function(){
  100. // summary:
  101. // Finds out if this axis has been initialized or not.
  102. // returns: Boolean
  103. // Whether a scaler has been calculated and if the axis is not dirty.
  104. return "scaler" in this && !(this.dirty && this.dependOnData());
  105. },
  106. setWindow: function(scale, offset){
  107. // summary:
  108. // Set the drawing "window" for the axis.
  109. // scale: Number
  110. // The new scale for the axis.
  111. // offset: Number
  112. // The new offset for the axis.
  113. // returns: dojox.charting.axis2d.Default
  114. // The reference to the axis for functional chaining.
  115. this.scale = scale;
  116. this.offset = offset;
  117. return this.clear(); // dojox.charting.axis2d.Default
  118. },
  119. getWindowScale: function(){
  120. // summary:
  121. // Get the current windowing scale of the axis.
  122. return "scale" in this ? this.scale : 1; // Number
  123. },
  124. getWindowOffset: function(){
  125. // summary:
  126. // Get the current windowing offset for the axis.
  127. return "offset" in this ? this.offset : 0; // Number
  128. },
  129. _groupLabelWidth: function(labels, font, wcLimit){
  130. if(!labels.length){
  131. return 0;
  132. }
  133. if(lang.isObject(labels[0])){
  134. labels = df.map(labels, function(label){ return label.text; });
  135. }
  136. if (wcLimit) {
  137. labels = df.map(labels, function(label){
  138. return lang.trim(label).length == 0 ? "" : label.substring(0, wcLimit) + this.trailingSymbol;
  139. }, this);
  140. }
  141. var s = labels.join("<br>");
  142. return g._base._getTextBox(s, {font: font}).w || 0;
  143. },
  144. calculate: function(min, max, span, labels){
  145. // summary:
  146. // Perform all calculations needed to render this axis.
  147. // min: Number
  148. // The smallest value represented on this axis.
  149. // max: Number
  150. // The largest value represented on this axis.
  151. // span: Number
  152. // The span in pixels over which axis calculations are made.
  153. // labels: String[]
  154. // Optional list of labels.
  155. // returns: dojox.charting.axis2d.Default
  156. // The reference to the axis for functional chaining.
  157. if(this.initialized()){
  158. return this;
  159. }
  160. var o = this.opt;
  161. this.labels = "labels" in o ? o.labels : labels;
  162. this.scaler = lin.buildScaler(min, max, span, o);
  163. var tsb = this.scaler.bounds;
  164. if("scale" in this){
  165. // calculate new range
  166. o.from = tsb.lower + this.offset;
  167. o.to = (tsb.upper - tsb.lower) / this.scale + o.from;
  168. // make sure that bounds are correct
  169. if( !isFinite(o.from) ||
  170. isNaN(o.from) ||
  171. !isFinite(o.to) ||
  172. isNaN(o.to) ||
  173. o.to - o.from >= tsb.upper - tsb.lower
  174. ){
  175. // any error --- remove from/to bounds
  176. delete o.from;
  177. delete o.to;
  178. delete this.scale;
  179. delete this.offset;
  180. }else{
  181. // shift the window, if we are out of bounds
  182. if(o.from < tsb.lower){
  183. o.to += tsb.lower - o.from;
  184. o.from = tsb.lower;
  185. }else if(o.to > tsb.upper){
  186. o.from += tsb.upper - o.to;
  187. o.to = tsb.upper;
  188. }
  189. // update the offset
  190. this.offset = o.from - tsb.lower;
  191. }
  192. // re-calculate the scaler
  193. this.scaler = lin.buildScaler(min, max, span, o);
  194. tsb = this.scaler.bounds;
  195. // cleanup
  196. if(this.scale == 1 && this.offset == 0){
  197. delete this.scale;
  198. delete this.offset;
  199. }
  200. }
  201. var ta = this.chart.theme.axis, labelWidth = 0, rotation = o.rotation % 360,
  202. // TODO: we use one font --- of major tick, we need to use major and minor fonts
  203. taFont = o.font || (ta.majorTick && ta.majorTick.font) || (ta.tick && ta.tick.font),
  204. size = taFont ? g.normalizedLength(g.splitFontString(taFont).size) : 0,
  205. cosr = Math.abs(Math.cos(rotation * Math.PI / 180)),
  206. sinr = Math.abs(Math.sin(rotation * Math.PI / 180));
  207. if(rotation < 0){
  208. rotation += 360;
  209. }
  210. if(size){
  211. if(this.vertical ? rotation != 0 && rotation != 180 : rotation != 90 && rotation != 270){
  212. // we need width of all labels
  213. if(this.labels){
  214. labelWidth = this._groupLabelWidth(this.labels, taFont, o.maxLabelCharCount);
  215. }else{
  216. var labelLength = Math.ceil(
  217. Math.log(
  218. Math.max(
  219. Math.abs(tsb.from),
  220. Math.abs(tsb.to)
  221. )
  222. ) / Math.LN10
  223. ),
  224. t = [];
  225. if(tsb.from < 0 || tsb.to < 0){
  226. t.push("-");
  227. }
  228. t.push(dstring.rep("9", labelLength));
  229. var precision = Math.floor(
  230. Math.log( tsb.to - tsb.from ) / Math.LN10
  231. );
  232. if(precision > 0){
  233. t.push(".");
  234. t.push(dstring.rep("9", precision));
  235. }
  236. labelWidth = g._base._getTextBox(
  237. t.join(""),
  238. { font: taFont }
  239. ).w;
  240. }
  241. labelWidth = o.maxLabelSize ? Math.min(o.maxLabelSize, labelWidth) : labelWidth;
  242. }else{
  243. labelWidth = size;
  244. }
  245. switch(rotation){
  246. case 0:
  247. case 90:
  248. case 180:
  249. case 270:
  250. // trivial cases: use labelWidth
  251. break;
  252. default:
  253. // rotated labels
  254. var gap1 = Math.sqrt(labelWidth * labelWidth + size * size), // short labels
  255. gap2 = this.vertical ? size * cosr + labelWidth * sinr : labelWidth * cosr + size * sinr; // slanted labels
  256. labelWidth = Math.min(gap1, gap2);
  257. break;
  258. }
  259. }
  260. this.scaler.minMinorStep = labelWidth + labelGap;
  261. this.ticks = lin.buildTicks(this.scaler, o);
  262. return this; // dojox.charting.axis2d.Default
  263. },
  264. getScaler: function(){
  265. // summary:
  266. // Get the pre-calculated scaler object.
  267. return this.scaler; // Object
  268. },
  269. getTicks: function(){
  270. // summary:
  271. // Get the pre-calculated ticks object.
  272. return this.ticks; // Object
  273. }
  274. });
  275. });