您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 
 
 

446 行
19 KiB

  1. /**
  2. * jqPlot
  3. * Pure JavaScript plotting plugin using jQuery
  4. *
  5. * Version: 1.0.0b2_r792
  6. *
  7. * Copyright (c) 2009-2011 Chris Leonello
  8. * jqPlot is currently available for use in all personal or commercial projects
  9. * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
  10. * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
  11. * choose the license that best suits your project and use it accordingly.
  12. *
  13. * Although not required, the author would appreciate an email letting him
  14. * know of any substantial use of jqPlot. You can reach the author at:
  15. * chris at jqplot dot com or see http://www.jqplot.com/info.php .
  16. *
  17. * If you are feeling kind and generous, consider supporting the project by
  18. * making a donation at: http://www.jqplot.com/donate.php .
  19. *
  20. * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
  21. *
  22. * version 2007.04.27
  23. * author Ash Searle
  24. * http://hexmen.com/blog/2007/03/printf-sprintf/
  25. * http://hexmen.com/js/sprintf.js
  26. * The author (Ash Searle) has placed this code in the public domain:
  27. * "This code is unrestricted: you are free to use it however you like."
  28. *
  29. */
  30. (function($) {
  31. /**
  32. * class: $.jqplot.LogAxisRenderer
  33. * A plugin for a jqPlot to render a logarithmic axis.
  34. *
  35. * To use this renderer, include the plugin in your source
  36. * > <script type="text/javascript" language="javascript" src="plugins/jqplot.logAxisRenderer.js"></script>
  37. *
  38. * and supply the appropriate options to your plot
  39. *
  40. * > {axes:{xaxis:{renderer:$.jqplot.LogAxisRenderer}}}
  41. **/
  42. $.jqplot.LogAxisRenderer = function() {
  43. $.jqplot.LinearAxisRenderer.call(this);
  44. // prop: axisDefaults
  45. // Default properties which will be applied directly to the series.
  46. //
  47. // Group: Properties
  48. //
  49. // Properties
  50. //
  51. /// base - the logarithmic base, commonly 2, 10 or Math.E
  52. // tickDistribution - 'even' or 'power'. 'even' gives equal pixel
  53. // spacing of the ticks on the plot. 'power' gives ticks in powers
  54. // of 10.
  55. this.axisDefaults = {
  56. base : 10,
  57. tickDistribution :'even'
  58. };
  59. };
  60. $.jqplot.LogAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer();
  61. $.jqplot.LogAxisRenderer.prototype.constructor = $.jqplot.LogAxisRenderer;
  62. $.jqplot.LogAxisRenderer.prototype.init = function(options) {
  63. // prop: tickRenderer
  64. // A class of a rendering engine for creating the ticks labels displayed on the plot,
  65. // See <$.jqplot.AxisTickRenderer>.
  66. // this.tickRenderer = $.jqplot.AxisTickRenderer;
  67. // this.labelRenderer = $.jqplot.AxisLabelRenderer;
  68. $.extend(true, this.renderer, options);
  69. for (var d in this.renderer.axisDefaults) {
  70. if (this[d] == null) {
  71. this[d] = this.renderer.axisDefaults[d];
  72. }
  73. }
  74. var db = this._dataBounds;
  75. // Go through all the series attached to this axis and find
  76. // the min/max bounds for this axis.
  77. for (var i=0; i<this._series.length; i++) {
  78. var s = this._series[i];
  79. var d = s.data;
  80. for (var j=0; j<d.length; j++) {
  81. if (this.name == 'xaxis' || this.name == 'x2axis') {
  82. if ((d[j][0] != null && d[j][0] < db.min) || db.min == null) {
  83. db.min = d[j][0];
  84. }
  85. if ((d[j][0] != null && d[j][0] > db.max) || db.max == null) {
  86. db.max = d[j][0];
  87. }
  88. }
  89. else {
  90. if ((d[j][1] != null && d[j][1] < db.min) || db.min == null) {
  91. db.min = d[j][1];
  92. }
  93. if ((d[j][1] != null && d[j][1] > db.max) || db.max == null) {
  94. db.max = d[j][1];
  95. }
  96. }
  97. }
  98. }
  99. };
  100. $.jqplot.LogAxisRenderer.prototype.createTicks = function() {
  101. // we're are operating on an axis here
  102. var ticks = this._ticks;
  103. var userTicks = this.ticks;
  104. var name = this.name;
  105. var db = this._dataBounds;
  106. var dim, interval;
  107. var min, max;
  108. var pos1, pos2;
  109. var tt, i;
  110. // if we already have ticks, use them.
  111. // ticks must be in order of increasing value.
  112. if (userTicks.length) {
  113. // ticks could be 1D or 2D array of [val, val, ,,,] or [[val, label], [val, label], ...] or mixed
  114. for (i=0; i<userTicks.length; i++){
  115. var ut = userTicks[i];
  116. var t = new this.tickRenderer(this.tickOptions);
  117. if (ut.constructor == Array) {
  118. t.value = ut[0];
  119. t.label = ut[1];
  120. if (!this.showTicks) {
  121. t.showLabel = false;
  122. t.showMark = false;
  123. }
  124. else if (!this.showTickMarks) {
  125. t.showMark = false;
  126. }
  127. t.setTick(ut[0], this.name);
  128. this._ticks.push(t);
  129. }
  130. else {
  131. t.value = ut;
  132. if (!this.showTicks) {
  133. t.showLabel = false;
  134. t.showMark = false;
  135. }
  136. else if (!this.showTickMarks) {
  137. t.showMark = false;
  138. }
  139. t.setTick(ut, this.name);
  140. this._ticks.push(t);
  141. }
  142. }
  143. this.numberTicks = userTicks.length;
  144. this.min = this._ticks[0].value;
  145. this.max = this._ticks[this.numberTicks-1].value;
  146. }
  147. // we don't have any ticks yet, let's make some!
  148. else {
  149. if (name == 'xaxis' || name == 'x2axis') {
  150. dim = this._plotDimensions.width;
  151. }
  152. else {
  153. dim = this._plotDimensions.height;
  154. }
  155. min = ((this.min != null) ? this.min : db.min);
  156. max = ((this.max != null) ? this.max : db.max);
  157. // if min and max are same, space them out a bit
  158. if (min == max) {
  159. var adj = 0.05;
  160. min = min*(1-adj);
  161. max = max*(1+adj);
  162. }
  163. // perform some checks
  164. if (this.min != null && this.min <= 0) {
  165. throw('log axis minimum must be greater than 0');
  166. }
  167. if (this.max != null && this.max <= 0) {
  168. throw('log axis maximum must be greater than 0');
  169. }
  170. // if (this.pad >1.99) this.pad = 1.99;
  171. var range = max - min;
  172. var rmin, rmax;
  173. if (this.tickDistribution == 'even') {
  174. rmin = (this.min != null) ? this.min : min - min*((this.padMin-1)/2);
  175. rmax = (this.max != null) ? this.max : max + max*((this.padMax-1)/2);
  176. this.min = rmin;
  177. this.max = rmax;
  178. range = this.max - this.min;
  179. if (this.numberTicks == null){
  180. if (dim > 100) {
  181. this.numberTicks = parseInt(3+(dim-100)/75, 10);
  182. }
  183. else {
  184. this.numberTicks = 2;
  185. }
  186. }
  187. var u = Math.pow(this.base, (1/(this.numberTicks-1)*Math.log(this.max/this.min)/Math.log(this.base)));
  188. for (var i=0; i<this.numberTicks; i++){
  189. tt = this.min * Math.pow(u, i);
  190. var t = new this.tickRenderer(this.tickOptions);
  191. if (!this.showTicks) {
  192. t.showLabel = false;
  193. t.showMark = false;
  194. }
  195. else if (!this.showTickMarks) {
  196. t.showMark = false;
  197. }
  198. t.setTick(tt, this.name);
  199. this._ticks.push(t);
  200. }
  201. }
  202. else if (this.tickDistribution == 'power'){
  203. // for power distribution, open up range to get a nice power of axis.renderer.base.
  204. // power distribution won't respect the user's min/max settings.
  205. rmin = Math.pow(this.base, Math.ceil(Math.log(min*(2-this.padMin))/Math.log(this.base))-1);
  206. rmax = Math.pow(this.base, Math.floor(Math.log(max*this.padMax)/Math.log(this.base))+1);
  207. this.min = rmin;
  208. this.max = rmax;
  209. range = this.max - this.min;
  210. var fittedTicks = 0;
  211. var minorTicks = 0;
  212. if (this.numberTicks == null){
  213. if (dim > 100) {
  214. this.numberTicks = Math.round(Math.log(this.max/this.min)/Math.log(this.base) + 1);
  215. if (this.numberTicks < 2) {
  216. this.numberTicks = 2;
  217. }
  218. fittedTicks = parseInt(3+(dim-100)/75, 10);
  219. }
  220. else {
  221. this.numberTicks = 2;
  222. fittedTicks = 2;
  223. }
  224. // if we don't have enough ticks, add some intermediate ticks
  225. // how many to have between major ticks.
  226. if (this.numberTicks < fittedTicks-1) {
  227. minorTicks = Math.floor(fittedTicks/this.numberTicks);
  228. }
  229. }
  230. for (var i=0; i<this.numberTicks; i++){
  231. tt = Math.pow(this.base, i - this.numberTicks + 1) * this.max;
  232. var t = new this.tickRenderer(this.tickOptions);
  233. if (!this.showTicks) {
  234. t.showLabel = false;
  235. t.showMark = false;
  236. }
  237. else if (!this.showTickMarks) {
  238. t.showMark = false;
  239. }
  240. t.setTick(tt, this.name);
  241. this._ticks.push(t);
  242. if (minorTicks && i<this.numberTicks-1) {
  243. var tt1 = Math.pow(this.base, i - this.numberTicks + 2) * this.max;
  244. var spread = tt1 - tt;
  245. var interval = tt1 / (minorTicks+1);
  246. for (var j=minorTicks-1; j>=0; j--) {
  247. var val = tt1-interval*(j+1);
  248. var t = new this.tickRenderer(this.tickOptions);
  249. if (!this.showTicks) {
  250. t.showLabel = false;
  251. t.showMark = false;
  252. }
  253. else if (!this.showTickMarks) {
  254. t.showMark = false;
  255. }
  256. t.setTick(val, this.name);
  257. this._ticks.push(t);
  258. }
  259. }
  260. }
  261. }
  262. }
  263. };
  264. $.jqplot.LogAxisRenderer.prototype.pack = function(pos, offsets) {
  265. var lb = parseInt(this.base, 10);
  266. var ticks = this._ticks;
  267. var trans = function (v) { return Math.log(v)/Math.log(lb); };
  268. var invtrans = function (v) { return Math.pow(Math.E, (Math.log(lb)*v)); };
  269. var max = trans(this.max);
  270. var min = trans(this.min);
  271. var offmax = offsets.max;
  272. var offmin = offsets.min;
  273. var lshow = (this._label == null) ? false : this._label.show;
  274. for (var p in pos) {
  275. this._elem.css(p, pos[p]);
  276. }
  277. this._offsets = offsets;
  278. // pixellength will be + for x axes and - for y axes becasue pixels always measured from top left.
  279. var pixellength = offmax - offmin;
  280. var unitlength = max - min;
  281. // point to unit and unit to point conversions references to Plot DOM element top left corner.
  282. this.p2u = function(p){
  283. return invtrans((p - offmin) * unitlength / pixellength + min);
  284. };
  285. this.u2p = function(u){
  286. return (trans(u) - min) * pixellength / unitlength + offmin;
  287. };
  288. if (this.name == 'xaxis' || this.name == 'x2axis'){
  289. this.series_u2p = function(u){
  290. return (trans(u) - min) * pixellength / unitlength;
  291. };
  292. this.series_p2u = function(p){
  293. return invtrans(p * unitlength / pixellength + min);
  294. };
  295. }
  296. // yaxis is max at top of canvas.
  297. else {
  298. this.series_u2p = function(u){
  299. return (trans(u) - max) * pixellength / unitlength;
  300. };
  301. this.series_p2u = function(p){
  302. return invtrans(p * unitlength / pixellength + max);
  303. };
  304. }
  305. if (this.show) {
  306. if (this.name == 'xaxis' || this.name == 'x2axis') {
  307. for (var i=0; i<ticks.length; i++) {
  308. var t = ticks[i];
  309. if (t.show && t.showLabel) {
  310. var shim;
  311. if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) {
  312. switch (t.labelPosition) {
  313. case 'auto':
  314. // position at end
  315. if (t.angle < 0) {
  316. shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
  317. }
  318. // position at start
  319. else {
  320. shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2;
  321. }
  322. break;
  323. case 'end':
  324. shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
  325. break;
  326. case 'start':
  327. shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2;
  328. break;
  329. case 'middle':
  330. shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
  331. break;
  332. default:
  333. shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
  334. break;
  335. }
  336. }
  337. else {
  338. shim = -t.getWidth()/2;
  339. }
  340. // var shim = t.getWidth()/2;
  341. var val = this.u2p(t.value) + shim + 'px';
  342. t._elem.css('left', val);
  343. t.pack();
  344. }
  345. }
  346. if (lshow) {
  347. var w = this._label._elem.outerWidth(true);
  348. this._label._elem.css('left', offmin + pixellength/2 - w/2 + 'px');
  349. if (this.name == 'xaxis') {
  350. this._label._elem.css('bottom', '0px');
  351. }
  352. else {
  353. this._label._elem.css('top', '0px');
  354. }
  355. this._label.pack();
  356. }
  357. }
  358. else {
  359. for (var i=0; i<ticks.length; i++) {
  360. var t = ticks[i];
  361. if (t.show && t.showLabel) {
  362. var shim;
  363. if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) {
  364. switch (t.labelPosition) {
  365. case 'auto':
  366. // position at end
  367. case 'end':
  368. if (t.angle < 0) {
  369. shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2;
  370. }
  371. else {
  372. shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2;
  373. }
  374. break;
  375. case 'start':
  376. if (t.angle > 0) {
  377. shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2;
  378. }
  379. else {
  380. shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2;
  381. }
  382. break;
  383. case 'middle':
  384. // if (t.angle > 0) {
  385. // shim = -t.getHeight()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
  386. // }
  387. // else {
  388. // shim = -t.getHeight()/2 - t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2;
  389. // }
  390. shim = -t.getHeight()/2;
  391. break;
  392. default:
  393. shim = -t.getHeight()/2;
  394. break;
  395. }
  396. }
  397. else {
  398. shim = -t.getHeight()/2;
  399. }
  400. var val = this.u2p(t.value) + shim + 'px';
  401. t._elem.css('top', val);
  402. t.pack();
  403. }
  404. }
  405. if (lshow) {
  406. var h = this._label._elem.outerHeight(true);
  407. this._label._elem.css('top', offmax - pixellength/2 - h/2 + 'px');
  408. if (this.name == 'yaxis') {
  409. this._label._elem.css('left', '0px');
  410. }
  411. else {
  412. this._label._elem.css('right', '0px');
  413. }
  414. this._label.pack();
  415. }
  416. }
  417. }
  418. };
  419. })(jQuery);