linear.js 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. define("dojox/charting/scaler/linear", ["dojo/_base/lang", "./common"],
  2. function(lang, common){
  3. var linear = lang.getObject("dojox.charting.scaler.linear", true);
  4. var deltaLimit = 3, // pixels
  5. findString = common.findString,
  6. getLabel = common.getNumericLabel;
  7. var calcTicks = function(min, max, kwArgs, majorTick, minorTick, microTick, span){
  8. kwArgs = lang.delegate(kwArgs);
  9. if(!majorTick){
  10. if(kwArgs.fixUpper == "major"){ kwArgs.fixUpper = "minor"; }
  11. if(kwArgs.fixLower == "major"){ kwArgs.fixLower = "minor"; }
  12. }
  13. if(!minorTick){
  14. if(kwArgs.fixUpper == "minor"){ kwArgs.fixUpper = "micro"; }
  15. if(kwArgs.fixLower == "minor"){ kwArgs.fixLower = "micro"; }
  16. }
  17. if(!microTick){
  18. if(kwArgs.fixUpper == "micro"){ kwArgs.fixUpper = "none"; }
  19. if(kwArgs.fixLower == "micro"){ kwArgs.fixLower = "none"; }
  20. }
  21. var lowerBound = findString(kwArgs.fixLower, ["major"]) ?
  22. Math.floor(kwArgs.min / majorTick) * majorTick :
  23. findString(kwArgs.fixLower, ["minor"]) ?
  24. Math.floor(kwArgs.min / minorTick) * minorTick :
  25. findString(kwArgs.fixLower, ["micro"]) ?
  26. Math.floor(kwArgs.min / microTick) * microTick : kwArgs.min,
  27. upperBound = findString(kwArgs.fixUpper, ["major"]) ?
  28. Math.ceil(kwArgs.max / majorTick) * majorTick :
  29. findString(kwArgs.fixUpper, ["minor"]) ?
  30. Math.ceil(kwArgs.max / minorTick) * minorTick :
  31. findString(kwArgs.fixUpper, ["micro"]) ?
  32. Math.ceil(kwArgs.max / microTick) * microTick : kwArgs.max;
  33. if(kwArgs.useMin){ min = lowerBound; }
  34. if(kwArgs.useMax){ max = upperBound; }
  35. var majorStart = (!majorTick || kwArgs.useMin && findString(kwArgs.fixLower, ["major"])) ?
  36. min : Math.ceil(min / majorTick) * majorTick,
  37. minorStart = (!minorTick || kwArgs.useMin && findString(kwArgs.fixLower, ["major", "minor"])) ?
  38. min : Math.ceil(min / minorTick) * minorTick,
  39. microStart = (! microTick || kwArgs.useMin && findString(kwArgs.fixLower, ["major", "minor", "micro"])) ?
  40. min : Math.ceil(min / microTick) * microTick,
  41. majorCount = !majorTick ? 0 : (kwArgs.useMax && findString(kwArgs.fixUpper, ["major"]) ?
  42. Math.round((max - majorStart) / majorTick) :
  43. Math.floor((max - majorStart) / majorTick)) + 1,
  44. minorCount = !minorTick ? 0 : (kwArgs.useMax && findString(kwArgs.fixUpper, ["major", "minor"]) ?
  45. Math.round((max - minorStart) / minorTick) :
  46. Math.floor((max - minorStart) / minorTick)) + 1,
  47. microCount = !microTick ? 0 : (kwArgs.useMax && findString(kwArgs.fixUpper, ["major", "minor", "micro"]) ?
  48. Math.round((max - microStart) / microTick) :
  49. Math.floor((max - microStart) / microTick)) + 1,
  50. minorPerMajor = minorTick ? Math.round(majorTick / minorTick) : 0,
  51. microPerMinor = microTick ? Math.round(minorTick / microTick) : 0,
  52. majorPrecision = majorTick ? Math.floor(Math.log(majorTick) / Math.LN10) : 0,
  53. minorPrecision = minorTick ? Math.floor(Math.log(minorTick) / Math.LN10) : 0,
  54. scale = span / (max - min);
  55. if(!isFinite(scale)){ scale = 1; }
  56. return {
  57. bounds: {
  58. lower: lowerBound,
  59. upper: upperBound,
  60. from: min,
  61. to: max,
  62. scale: scale,
  63. span: span
  64. },
  65. major: {
  66. tick: majorTick,
  67. start: majorStart,
  68. count: majorCount,
  69. prec: majorPrecision
  70. },
  71. minor: {
  72. tick: minorTick,
  73. start: minorStart,
  74. count: minorCount,
  75. prec: minorPrecision
  76. },
  77. micro: {
  78. tick: microTick,
  79. start: microStart,
  80. count: microCount,
  81. prec: 0
  82. },
  83. minorPerMajor: minorPerMajor,
  84. microPerMinor: microPerMinor,
  85. scaler: linear
  86. };
  87. };
  88. return lang.mixin(linear, {
  89. buildScaler: function(/*Number*/ min, /*Number*/ max, /*Number*/ span, /*Object*/ kwArgs){
  90. var h = {fixUpper: "none", fixLower: "none", natural: false};
  91. if(kwArgs){
  92. if("fixUpper" in kwArgs){ h.fixUpper = String(kwArgs.fixUpper); }
  93. if("fixLower" in kwArgs){ h.fixLower = String(kwArgs.fixLower); }
  94. if("natural" in kwArgs){ h.natural = Boolean(kwArgs.natural); }
  95. }
  96. // update bounds
  97. if("min" in kwArgs){ min = kwArgs.min; }
  98. if("max" in kwArgs){ max = kwArgs.max; }
  99. if(kwArgs.includeZero){
  100. if(min > 0){ min = 0; }
  101. if(max < 0){ max = 0; }
  102. }
  103. h.min = min;
  104. h.useMin = true;
  105. h.max = max;
  106. h.useMax = true;
  107. if("from" in kwArgs){
  108. min = kwArgs.from;
  109. h.useMin = false;
  110. }
  111. if("to" in kwArgs){
  112. max = kwArgs.to;
  113. h.useMax = false;
  114. }
  115. // check for erroneous condition
  116. if(max <= min){
  117. return calcTicks(min, max, h, 0, 0, 0, span); // Object
  118. }
  119. var mag = Math.floor(Math.log(max - min) / Math.LN10),
  120. major = kwArgs && ("majorTickStep" in kwArgs) ? kwArgs.majorTickStep : Math.pow(10, mag),
  121. minor = 0, micro = 0, ticks;
  122. // calculate minor ticks
  123. if(kwArgs && ("minorTickStep" in kwArgs)){
  124. minor = kwArgs.minorTickStep;
  125. }else{
  126. do{
  127. minor = major / 10;
  128. if(!h.natural || minor > 0.9){
  129. ticks = calcTicks(min, max, h, major, minor, 0, span);
  130. if(ticks.bounds.scale * ticks.minor.tick > deltaLimit){ break; }
  131. }
  132. minor = major / 5;
  133. if(!h.natural || minor > 0.9){
  134. ticks = calcTicks(min, max, h, major, minor, 0, span);
  135. if(ticks.bounds.scale * ticks.minor.tick > deltaLimit){ break; }
  136. }
  137. minor = major / 2;
  138. if(!h.natural || minor > 0.9){
  139. ticks = calcTicks(min, max, h, major, minor, 0, span);
  140. if(ticks.bounds.scale * ticks.minor.tick > deltaLimit){ break; }
  141. }
  142. return calcTicks(min, max, h, major, 0, 0, span); // Object
  143. }while(false);
  144. }
  145. // calculate micro ticks
  146. if(kwArgs && ("microTickStep" in kwArgs)){
  147. micro = kwArgs.microTickStep;
  148. ticks = calcTicks(min, max, h, major, minor, micro, span);
  149. }else{
  150. do{
  151. micro = minor / 10;
  152. if(!h.natural || micro > 0.9){
  153. ticks = calcTicks(min, max, h, major, minor, micro, span);
  154. if(ticks.bounds.scale * ticks.micro.tick > deltaLimit){ break; }
  155. }
  156. micro = minor / 5;
  157. if(!h.natural || micro > 0.9){
  158. ticks = calcTicks(min, max, h, major, minor, micro, span);
  159. if(ticks.bounds.scale * ticks.micro.tick > deltaLimit){ break; }
  160. }
  161. micro = minor / 2;
  162. if(!h.natural || micro > 0.9){
  163. ticks = calcTicks(min, max, h, major, minor, micro, span);
  164. if(ticks.bounds.scale * ticks.micro.tick > deltaLimit){ break; }
  165. }
  166. micro = 0;
  167. }while(false);
  168. }
  169. return micro ? ticks : calcTicks(min, max, h, major, minor, 0, span); // Object
  170. },
  171. buildTicks: function(/*Object*/ scaler, /*Object*/ kwArgs){
  172. var step, next, tick,
  173. nextMajor = scaler.major.start,
  174. nextMinor = scaler.minor.start,
  175. nextMicro = scaler.micro.start;
  176. if(kwArgs.microTicks && scaler.micro.tick){
  177. step = scaler.micro.tick, next = nextMicro;
  178. }else if(kwArgs.minorTicks && scaler.minor.tick){
  179. step = scaler.minor.tick, next = nextMinor;
  180. }else if(scaler.major.tick){
  181. step = scaler.major.tick, next = nextMajor;
  182. }else{
  183. // no ticks
  184. return null;
  185. }
  186. // make sure that we have finite bounds
  187. var revScale = 1 / scaler.bounds.scale;
  188. if(scaler.bounds.to <= scaler.bounds.from || isNaN(revScale) || !isFinite(revScale) ||
  189. step <= 0 || isNaN(step) || !isFinite(step)){
  190. // no ticks
  191. return null;
  192. }
  193. // loop over all ticks
  194. var majorTicks = [], minorTicks = [], microTicks = [];
  195. while(next <= scaler.bounds.to + revScale){
  196. if(Math.abs(nextMajor - next) < step / 2){
  197. // major tick
  198. tick = {value: nextMajor};
  199. if(kwArgs.majorLabels){
  200. tick.label = getLabel(nextMajor, scaler.major.prec, kwArgs);
  201. }
  202. majorTicks.push(tick);
  203. nextMajor += scaler.major.tick;
  204. nextMinor += scaler.minor.tick;
  205. nextMicro += scaler.micro.tick;
  206. }else if(Math.abs(nextMinor - next) < step / 2){
  207. // minor tick
  208. if(kwArgs.minorTicks){
  209. tick = {value: nextMinor};
  210. if(kwArgs.minorLabels && (scaler.minMinorStep <= scaler.minor.tick * scaler.bounds.scale)){
  211. tick.label = getLabel(nextMinor, scaler.minor.prec, kwArgs);
  212. }
  213. minorTicks.push(tick);
  214. }
  215. nextMinor += scaler.minor.tick;
  216. nextMicro += scaler.micro.tick;
  217. }else{
  218. // micro tick
  219. if(kwArgs.microTicks){
  220. microTicks.push({value: nextMicro});
  221. }
  222. nextMicro += scaler.micro.tick;
  223. }
  224. next += step;
  225. }
  226. return {major: majorTicks, minor: minorTicks, micro: microTicks}; // Object
  227. },
  228. getTransformerFromModel: function(/*Object*/ scaler){
  229. var offset = scaler.bounds.from, scale = scaler.bounds.scale;
  230. return function(x){ return (x - offset) * scale; }; // Function
  231. },
  232. getTransformerFromPlot: function(/*Object*/ scaler){
  233. var offset = scaler.bounds.from, scale = scaler.bounds.scale;
  234. return function(x){ return x / scale + offset; }; // Function
  235. }
  236. });
  237. });