linear.js 9.0 KB

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