jqplot.barRenderer.js 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791
  1. /**
  2. * jqPlot
  3. * Pure JavaScript plotting plugin using jQuery
  4. *
  5. * Version: 1.0.2
  6. * Revision: 1108
  7. *
  8. * Copyright (c) 2009-2011 Chris Leonello
  9. * jqPlot is currently available for use in all personal or commercial projects
  10. * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
  11. * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
  12. * choose the license that best suits your project and use it accordingly.
  13. *
  14. * Although not required, the author would appreciate an email letting him
  15. * know of any substantial use of jqPlot. You can reach the author at:
  16. * chris at jqplot dot com or see http://www.jqplot.com/info.php .
  17. *
  18. * If you are feeling kind and generous, consider supporting the project by
  19. * making a donation at: http://www.jqplot.com/donate.php .
  20. *
  21. * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
  22. *
  23. * version 2007.04.27
  24. * author Ash Searle
  25. * http://hexmen.com/blog/2007/03/printf-sprintf/
  26. * http://hexmen.com/js/sprintf.js
  27. * The author (Ash Searle) has placed this code in the public domain:
  28. * "This code is unrestricted: you are free to use it however you like."
  29. *
  30. */
  31. (function($) {
  32. // Class: $.jqplot.BarRenderer
  33. // A plugin renderer for jqPlot to draw a bar plot.
  34. // Draws series as a line.
  35. $.jqplot.BarRenderer = function(){
  36. $.jqplot.LineRenderer.call(this);
  37. };
  38. $.jqplot.BarRenderer.prototype = new $.jqplot.LineRenderer();
  39. $.jqplot.BarRenderer.prototype.constructor = $.jqplot.BarRenderer;
  40. // called with scope of series.
  41. $.jqplot.BarRenderer.prototype.init = function(options, plot) {
  42. // Group: Properties
  43. //
  44. // prop: barPadding
  45. // Number of pixels between adjacent bars at the same axis value.
  46. this.barPadding = 8;
  47. // prop: barMargin
  48. // Number of pixels between groups of bars at adjacent axis values.
  49. this.barMargin = 10;
  50. // prop: barDirection
  51. // 'vertical' = up and down bars, 'horizontal' = side to side bars
  52. this.barDirection = 'vertical';
  53. // prop: barWidth
  54. // Width of the bar in pixels (auto by devaul). null = calculated automatically.
  55. this.barWidth = null;
  56. // prop: shadowOffset
  57. // offset of the shadow from the slice and offset of
  58. // each succesive stroke of the shadow from the last.
  59. this.shadowOffset = 2;
  60. // prop: shadowDepth
  61. // number of strokes to apply to the shadow,
  62. // each stroke offset shadowOffset from the last.
  63. this.shadowDepth = 5;
  64. // prop: shadowAlpha
  65. // transparency of the shadow (0 = transparent, 1 = opaque)
  66. this.shadowAlpha = 0.08;
  67. // prop: waterfall
  68. // true to enable waterfall plot.
  69. this.waterfall = false;
  70. // prop: groups
  71. // group bars into this many groups
  72. this.groups = 1;
  73. // prop: varyBarColor
  74. // true to color each bar of a series separately rather than
  75. // have every bar of a given series the same color.
  76. // If used for non-stacked multiple series bar plots, user should
  77. // specify a separate 'seriesColors' array for each series.
  78. // Otherwise, each series will set their bars to the same color array.
  79. // This option has no Effect for stacked bar charts and is disabled.
  80. this.varyBarColor = false;
  81. // prop: highlightMouseOver
  82. // True to highlight slice when moused over.
  83. // This must be false to enable highlightMouseDown to highlight when clicking on a slice.
  84. this.highlightMouseOver = true;
  85. // prop: highlightMouseDown
  86. // True to highlight when a mouse button is pressed over a slice.
  87. // This will be disabled if highlightMouseOver is true.
  88. this.highlightMouseDown = false;
  89. // prop: highlightColors
  90. // an array of colors to use when highlighting a bar.
  91. this.highlightColors = [];
  92. // prop: transposedData
  93. // NOT IMPLEMENTED YET. True if this is a horizontal bar plot and
  94. // x and y values are "transposed". Tranposed, or "swapped", data is
  95. // required prior to rev. 894 builds of jqPlot with horizontal bars.
  96. // Allows backward compatability of bar renderer horizontal bars with
  97. // old style data sets.
  98. this.transposedData = true;
  99. this.renderer.animation = {
  100. show: false,
  101. direction: 'down',
  102. speed: 3000,
  103. _supported: true
  104. };
  105. this._type = 'bar';
  106. // if user has passed in highlightMouseDown option and not set highlightMouseOver, disable highlightMouseOver
  107. if (options.highlightMouseDown && options.highlightMouseOver == null) {
  108. options.highlightMouseOver = false;
  109. }
  110. //////
  111. // This is probably wrong here.
  112. // After going back and forth on wether renderer should be the thing
  113. // or extend the thing, it seems that it it best if it is a property
  114. // on the thing. This should be something that is commonized
  115. // among series renderers in the future.
  116. //////
  117. $.extend(true, this, options);
  118. // really should probably do this
  119. $.extend(true, this.renderer, options);
  120. // fill is still needed to properly draw the legend.
  121. // bars have to be filled.
  122. this.fill = true;
  123. // if horizontal bar and animating, reset the default direction
  124. if (this.barDirection === 'horizontal' && this.rendererOptions.animation && this.rendererOptions.animation.direction == null) {
  125. this.renderer.animation.direction = 'left';
  126. }
  127. if (this.waterfall) {
  128. this.fillToZero = false;
  129. this.disableStack = true;
  130. }
  131. if (this.barDirection == 'vertical' ) {
  132. this._primaryAxis = '_xaxis';
  133. this._stackAxis = 'y';
  134. this.fillAxis = 'y';
  135. }
  136. else {
  137. this._primaryAxis = '_yaxis';
  138. this._stackAxis = 'x';
  139. this.fillAxis = 'x';
  140. }
  141. // index of the currenty highlighted point, if any
  142. this._highlightedPoint = null;
  143. // total number of values for all bar series, total number of bar series, and position of this series
  144. this._plotSeriesInfo = null;
  145. // Array of actual data colors used for each data point.
  146. this._dataColors = [];
  147. this._barPoints = [];
  148. // set the shape renderer options
  149. var opts = {lineJoin:'miter', lineCap:'round', fill:true, isarc:false, strokeStyle:this.color, fillStyle:this.color, closePath:this.fill};
  150. this.renderer.shapeRenderer.init(opts);
  151. // set the shadow renderer options
  152. var sopts = {lineJoin:'miter', lineCap:'round', fill:true, isarc:false, angle:this.shadowAngle, offset:this.shadowOffset, alpha:this.shadowAlpha, depth:this.shadowDepth, closePath:this.fill};
  153. this.renderer.shadowRenderer.init(sopts);
  154. plot.postInitHooks.addOnce(postInit);
  155. plot.postDrawHooks.addOnce(postPlotDraw);
  156. plot.eventListenerHooks.addOnce('jqplotMouseMove', handleMove);
  157. plot.eventListenerHooks.addOnce('jqplotMouseDown', handleMouseDown);
  158. plot.eventListenerHooks.addOnce('jqplotMouseUp', handleMouseUp);
  159. plot.eventListenerHooks.addOnce('jqplotClick', handleClick);
  160. plot.eventListenerHooks.addOnce('jqplotRightClick', handleRightClick);
  161. };
  162. // called with scope of series
  163. function barPreInit(target, data, seriesDefaults, options) {
  164. if (this.rendererOptions.barDirection == 'horizontal') {
  165. this._stackAxis = 'x';
  166. this._primaryAxis = '_yaxis';
  167. }
  168. if (this.rendererOptions.waterfall == true) {
  169. this._data = $.extend(true, [], this.data);
  170. var sum = 0;
  171. var pos = (!this.rendererOptions.barDirection || this.rendererOptions.barDirection === 'vertical' || this.transposedData === false) ? 1 : 0;
  172. for(var i=0; i<this.data.length; i++) {
  173. sum += this.data[i][pos];
  174. if (i>0) {
  175. this.data[i][pos] += this.data[i-1][pos];
  176. }
  177. }
  178. this.data[this.data.length] = (pos == 1) ? [this.data.length+1, sum] : [sum, this.data.length+1];
  179. this._data[this._data.length] = (pos == 1) ? [this._data.length+1, sum] : [sum, this._data.length+1];
  180. }
  181. if (this.rendererOptions.groups > 1) {
  182. this.breakOnNull = true;
  183. var l = this.data.length;
  184. var skip = parseInt(l/this.rendererOptions.groups, 10);
  185. var count = 0;
  186. for (var i=skip; i<l; i+=skip) {
  187. this.data.splice(i+count, 0, [null, null]);
  188. count++;
  189. }
  190. for (i=0; i<this.data.length; i++) {
  191. if (this._primaryAxis == '_xaxis') {
  192. this.data[i][0] = i+1;
  193. }
  194. else {
  195. this.data[i][1] = i+1;
  196. }
  197. }
  198. }
  199. }
  200. $.jqplot.preSeriesInitHooks.push(barPreInit);
  201. // needs to be called with scope of series, not renderer.
  202. $.jqplot.BarRenderer.prototype.calcSeriesNumbers = function() {
  203. var nvals = 0;
  204. var nseries = 0;
  205. var paxis = this[this._primaryAxis];
  206. var s, series, pos;
  207. // loop through all series on this axis
  208. for (var i=0; i < paxis._series.length; i++) {
  209. series = paxis._series[i];
  210. if (series === this) {
  211. pos = i;
  212. }
  213. // is the series rendered as a bar?
  214. if (series.renderer.constructor == $.jqplot.BarRenderer) {
  215. // gridData may not be computed yet, use data length insted
  216. nvals += series.data.length;
  217. nseries += 1;
  218. }
  219. }
  220. // return total number of values for all bar series, total number of bar series, and position of this series
  221. return [nvals, nseries, pos];
  222. };
  223. $.jqplot.BarRenderer.prototype.setBarWidth = function() {
  224. // need to know how many data values we have on the approprate axis and figure it out.
  225. var i;
  226. var nvals = 0;
  227. var nseries = 0;
  228. var paxis = this[this._primaryAxis];
  229. var s, series, pos;
  230. var temp = this._plotSeriesInfo = this.renderer.calcSeriesNumbers.call(this);
  231. nvals = temp[0];
  232. nseries = temp[1];
  233. var nticks = paxis.numberTicks;
  234. var nbins = (nticks-1)/2;
  235. // so, now we have total number of axis values.
  236. if (paxis.name == 'xaxis' || paxis.name == 'x2axis') {
  237. if (this._stack) {
  238. this.barWidth = (paxis._offsets.max - paxis._offsets.min) / nvals * nseries - this.barMargin;
  239. }
  240. else {
  241. this.barWidth = ((paxis._offsets.max - paxis._offsets.min)/nbins - this.barPadding * (nseries-1) - this.barMargin*2)/nseries;
  242. // this.barWidth = (paxis._offsets.max - paxis._offsets.min) / nvals - this.barPadding - this.barMargin/nseries;
  243. }
  244. }
  245. else {
  246. if (this._stack) {
  247. this.barWidth = (paxis._offsets.min - paxis._offsets.max) / nvals * nseries - this.barMargin;
  248. }
  249. else {
  250. this.barWidth = ((paxis._offsets.min - paxis._offsets.max)/nbins - this.barPadding * (nseries-1) - this.barMargin*2)/nseries;
  251. // this.barWidth = (paxis._offsets.min - paxis._offsets.max) / nvals - this.barPadding - this.barMargin/nseries;
  252. }
  253. }
  254. return [nvals, nseries];
  255. };
  256. function computeHighlightColors (colors) {
  257. var ret = [];
  258. for (var i=0; i<colors.length; i++){
  259. var rgba = $.jqplot.getColorComponents(colors[i]);
  260. var newrgb = [rgba[0], rgba[1], rgba[2]];
  261. var sum = newrgb[0] + newrgb[1] + newrgb[2];
  262. for (var j=0; j<3; j++) {
  263. // when darkening, lowest color component can be is 60.
  264. newrgb[j] = (sum > 570) ? newrgb[j] * 0.8 : newrgb[j] + 0.3 * (255 - newrgb[j]);
  265. newrgb[j] = parseInt(newrgb[j], 10);
  266. }
  267. ret.push('rgb('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+')');
  268. }
  269. return ret;
  270. }
  271. function getStart(sidx, didx, comp, plot, axis) {
  272. // check if sign change
  273. var seriesIndex = sidx,
  274. prevSeriesIndex = sidx - 1,
  275. start,
  276. prevVal,
  277. aidx = (axis === 'x') ? 0 : 1;
  278. // is this not the first series?
  279. if (seriesIndex > 0) {
  280. prevVal = plot.series[prevSeriesIndex]._plotData[didx][aidx];
  281. // is there a sign change
  282. if ((comp * prevVal) < 0) {
  283. start = getStart(prevSeriesIndex, didx, comp, plot, axis);
  284. }
  285. // no sign change.
  286. else {
  287. start = plot.series[prevSeriesIndex].gridData[didx][aidx];
  288. }
  289. }
  290. // if first series, return value at 0
  291. else {
  292. start = (aidx === 0) ? plot.series[seriesIndex]._xaxis.series_u2p(0) : plot.series[seriesIndex]._yaxis.series_u2p(0);
  293. }
  294. return start;
  295. }
  296. $.jqplot.BarRenderer.prototype.draw = function(ctx, gridData, options, plot) {
  297. var i;
  298. // Ughhh, have to make a copy of options b/c it may be modified later.
  299. var opts = $.extend({}, options);
  300. var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow;
  301. var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine;
  302. var fill = (opts.fill != undefined) ? opts.fill : this.fill;
  303. var xaxis = this.xaxis;
  304. var yaxis = this.yaxis;
  305. var xp = this._xaxis.series_u2p;
  306. var yp = this._yaxis.series_u2p;
  307. var pointx, pointy;
  308. // clear out data colors.
  309. this._dataColors = [];
  310. this._barPoints = [];
  311. if (this.barWidth == null) {
  312. this.renderer.setBarWidth.call(this);
  313. }
  314. var temp = this._plotSeriesInfo = this.renderer.calcSeriesNumbers.call(this);
  315. var nvals = temp[0];
  316. var nseries = temp[1];
  317. var pos = temp[2];
  318. var points = [];
  319. if (this._stack) {
  320. this._barNudge = 0;
  321. }
  322. else {
  323. this._barNudge = (-Math.abs(nseries/2 - 0.5) + pos) * (this.barWidth + this.barPadding);
  324. }
  325. if (showLine) {
  326. var negativeColors = new $.jqplot.ColorGenerator(this.negativeSeriesColors);
  327. var positiveColors = new $.jqplot.ColorGenerator(this.seriesColors);
  328. var negativeColor = negativeColors.get(this.index);
  329. if (! this.useNegativeColors) {
  330. negativeColor = opts.fillStyle;
  331. }
  332. var positiveColor = opts.fillStyle;
  333. var base;
  334. var xstart;
  335. var ystart;
  336. if (this.barDirection == 'vertical') {
  337. for (var i=0; i<gridData.length; i++) {
  338. if (!this._stack && this.data[i][1] == null) {
  339. continue;
  340. }
  341. points = [];
  342. base = gridData[i][0] + this._barNudge;
  343. // stacked
  344. if (this._stack && this._prevGridData.length) {
  345. ystart = getStart(this.index, i, this._plotData[i][1], plot, 'y');
  346. }
  347. // not stacked and first series in stack
  348. else {
  349. if (this.fillToZero) {
  350. ystart = this._yaxis.series_u2p(0);
  351. }
  352. else if (this.waterfall && i > 0 && i < this.gridData.length-1) {
  353. ystart = this.gridData[i-1][1];
  354. }
  355. else if (this.waterfall && i == 0 && i < this.gridData.length-1) {
  356. if (this._yaxis.min <= 0 && this._yaxis.max >= 0) {
  357. ystart = this._yaxis.series_u2p(0);
  358. }
  359. else if (this._yaxis.min > 0) {
  360. ystart = ctx.canvas.height;
  361. }
  362. else {
  363. ystart = 0;
  364. }
  365. }
  366. else if (this.waterfall && i == this.gridData.length - 1) {
  367. if (this._yaxis.min <= 0 && this._yaxis.max >= 0) {
  368. ystart = this._yaxis.series_u2p(0);
  369. }
  370. else if (this._yaxis.min > 0) {
  371. ystart = ctx.canvas.height;
  372. }
  373. else {
  374. ystart = 0;
  375. }
  376. }
  377. else {
  378. ystart = ctx.canvas.height;
  379. }
  380. }
  381. if ((this.fillToZero && this._plotData[i][1] < 0) || (this.waterfall && this._data[i][1] < 0)) {
  382. if (this.varyBarColor && !this._stack) {
  383. if (this.useNegativeColors) {
  384. opts.fillStyle = negativeColors.next();
  385. }
  386. else {
  387. opts.fillStyle = positiveColors.next();
  388. }
  389. }
  390. else {
  391. opts.fillStyle = negativeColor;
  392. }
  393. }
  394. else {
  395. if (this.varyBarColor && !this._stack) {
  396. opts.fillStyle = positiveColors.next();
  397. }
  398. else {
  399. opts.fillStyle = positiveColor;
  400. }
  401. }
  402. if (!this.fillToZero || this._plotData[i][1] >= 0) {
  403. points.push([base-this.barWidth/2, ystart]);
  404. points.push([base-this.barWidth/2, gridData[i][1]]);
  405. points.push([base+this.barWidth/2, gridData[i][1]]);
  406. points.push([base+this.barWidth/2, ystart]);
  407. }
  408. // for negative bars make sure points are always ordered clockwise
  409. else {
  410. points.push([base-this.barWidth/2, gridData[i][1]]);
  411. points.push([base-this.barWidth/2, ystart]);
  412. points.push([base+this.barWidth/2, ystart]);
  413. points.push([base+this.barWidth/2, gridData[i][1]]);
  414. }
  415. this._barPoints.push(points);
  416. // now draw the shadows if not stacked.
  417. // for stacked plots, they are predrawn by drawShadow
  418. if (shadow && !this._stack) {
  419. var sopts = $.extend(true, {}, opts);
  420. // need to get rid of fillStyle on shadow.
  421. delete sopts.fillStyle;
  422. this.renderer.shadowRenderer.draw(ctx, points, sopts);
  423. }
  424. var clr = opts.fillStyle || this.color;
  425. this._dataColors.push(clr);
  426. this.renderer.shapeRenderer.draw(ctx, points, opts);
  427. }
  428. }
  429. else if (this.barDirection == 'horizontal'){
  430. for (var i=0; i<gridData.length; i++) {
  431. if (this.data[i][0] == null) {
  432. continue;
  433. }
  434. points = [];
  435. base = gridData[i][1] - this._barNudge;
  436. xstart;
  437. if (this._stack && this._prevGridData.length) {
  438. xstart = getStart(this.index, i, this._plotData[i][0], plot, 'x');
  439. }
  440. // not stacked and first series in stack
  441. else {
  442. if (this.fillToZero) {
  443. xstart = this._xaxis.series_u2p(0);
  444. }
  445. else if (this.waterfall && i > 0 && i < this.gridData.length-1) {
  446. xstart = this.gridData[i-1][1];
  447. }
  448. else if (this.waterfall && i == 0 && i < this.gridData.length-1) {
  449. if (this._xaxis.min <= 0 && this._xaxis.max >= 0) {
  450. xstart = this._xaxis.series_u2p(0);
  451. }
  452. else if (this._xaxis.min > 0) {
  453. xstart = 0;
  454. }
  455. else {
  456. xstart = ctx.canvas.width;
  457. }
  458. }
  459. else if (this.waterfall && i == this.gridData.length - 1) {
  460. if (this._xaxis.min <= 0 && this._xaxis.max >= 0) {
  461. xstart = this._xaxis.series_u2p(0);
  462. }
  463. else if (this._xaxis.min > 0) {
  464. xstart = 0;
  465. }
  466. else {
  467. xstart = ctx.canvas.width;
  468. }
  469. }
  470. else {
  471. xstart = 0;
  472. }
  473. }
  474. if ((this.fillToZero && this._plotData[i][1] < 0) || (this.waterfall && this._data[i][1] < 0)) {
  475. if (this.varyBarColor && !this._stack) {
  476. if (this.useNegativeColors) {
  477. opts.fillStyle = negativeColors.next();
  478. }
  479. else {
  480. opts.fillStyle = positiveColors.next();
  481. }
  482. }
  483. }
  484. else {
  485. if (this.varyBarColor && !this._stack) {
  486. opts.fillStyle = positiveColors.next();
  487. }
  488. else {
  489. opts.fillStyle = positiveColor;
  490. }
  491. }
  492. if (!this.fillToZero || this._plotData[i][0] >= 0) {
  493. points.push([xstart, base + this.barWidth / 2]);
  494. points.push([xstart, base - this.barWidth / 2]);
  495. points.push([gridData[i][0], base - this.barWidth / 2]);
  496. points.push([gridData[i][0], base + this.barWidth / 2]);
  497. }
  498. else {
  499. points.push([gridData[i][0], base + this.barWidth / 2]);
  500. points.push([gridData[i][0], base - this.barWidth / 2]);
  501. points.push([xstart, base - this.barWidth / 2]);
  502. points.push([xstart, base + this.barWidth / 2]);
  503. }
  504. this._barPoints.push(points);
  505. // now draw the shadows if not stacked.
  506. // for stacked plots, they are predrawn by drawShadow
  507. if (shadow && !this._stack) {
  508. var sopts = $.extend(true, {}, opts);
  509. delete sopts.fillStyle;
  510. this.renderer.shadowRenderer.draw(ctx, points, sopts);
  511. }
  512. var clr = opts.fillStyle || this.color;
  513. this._dataColors.push(clr);
  514. this.renderer.shapeRenderer.draw(ctx, points, opts);
  515. }
  516. }
  517. }
  518. if (this.highlightColors.length == 0) {
  519. this.highlightColors = $.jqplot.computeHighlightColors(this._dataColors);
  520. }
  521. else if (typeof(this.highlightColors) == 'string') {
  522. var temp = this.highlightColors;
  523. this.highlightColors = [];
  524. for (var i=0; i<this._dataColors.length; i++) {
  525. this.highlightColors.push(temp);
  526. }
  527. }
  528. };
  529. // for stacked plots, shadows will be pre drawn by drawShadow.
  530. $.jqplot.BarRenderer.prototype.drawShadow = function(ctx, gridData, options, plot) {
  531. var i;
  532. var opts = (options != undefined) ? options : {};
  533. var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow;
  534. var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine;
  535. var fill = (opts.fill != undefined) ? opts.fill : this.fill;
  536. var xaxis = this.xaxis;
  537. var yaxis = this.yaxis;
  538. var xp = this._xaxis.series_u2p;
  539. var yp = this._yaxis.series_u2p;
  540. var pointx, points, pointy, nvals, nseries, pos;
  541. if (this._stack && this.shadow) {
  542. if (this.barWidth == null) {
  543. this.renderer.setBarWidth.call(this);
  544. }
  545. var temp = this._plotSeriesInfo = this.renderer.calcSeriesNumbers.call(this);
  546. nvals = temp[0];
  547. nseries = temp[1];
  548. pos = temp[2];
  549. if (this._stack) {
  550. this._barNudge = 0;
  551. }
  552. else {
  553. this._barNudge = (-Math.abs(nseries/2 - 0.5) + pos) * (this.barWidth + this.barPadding);
  554. }
  555. if (showLine) {
  556. if (this.barDirection == 'vertical') {
  557. for (var i=0; i<gridData.length; i++) {
  558. if (this.data[i][1] == null) {
  559. continue;
  560. }
  561. points = [];
  562. var base = gridData[i][0] + this._barNudge;
  563. var ystart;
  564. if (this._stack && this._prevGridData.length) {
  565. ystart = getStart(this.index, i, this._plotData[i][1], plot, 'y');
  566. }
  567. else {
  568. if (this.fillToZero) {
  569. ystart = this._yaxis.series_u2p(0);
  570. }
  571. else {
  572. ystart = ctx.canvas.height;
  573. }
  574. }
  575. points.push([base-this.barWidth/2, ystart]);
  576. points.push([base-this.barWidth/2, gridData[i][1]]);
  577. points.push([base+this.barWidth/2, gridData[i][1]]);
  578. points.push([base+this.barWidth/2, ystart]);
  579. this.renderer.shadowRenderer.draw(ctx, points, opts);
  580. }
  581. }
  582. else if (this.barDirection == 'horizontal'){
  583. for (var i=0; i<gridData.length; i++) {
  584. if (this.data[i][0] == null) {
  585. continue;
  586. }
  587. points = [];
  588. var base = gridData[i][1] - this._barNudge;
  589. var xstart;
  590. if (this._stack && this._prevGridData.length) {
  591. xstart = getStart(this.index, i, this._plotData[i][0], plot, 'x');
  592. }
  593. else {
  594. if (this.fillToZero) {
  595. xstart = this._xaxis.series_u2p(0);
  596. }
  597. else {
  598. xstart = 0;
  599. }
  600. }
  601. points.push([xstart, base+this.barWidth/2]);
  602. points.push([gridData[i][0], base+this.barWidth/2]);
  603. points.push([gridData[i][0], base-this.barWidth/2]);
  604. points.push([xstart, base-this.barWidth/2]);
  605. this.renderer.shadowRenderer.draw(ctx, points, opts);
  606. }
  607. }
  608. }
  609. }
  610. };
  611. function postInit(target, data, options) {
  612. for (var i=0; i<this.series.length; i++) {
  613. if (this.series[i].renderer.constructor == $.jqplot.BarRenderer) {
  614. // don't allow mouseover and mousedown at same time.
  615. if (this.series[i].highlightMouseOver) {
  616. this.series[i].highlightMouseDown = false;
  617. }
  618. }
  619. }
  620. }
  621. // called within context of plot
  622. // create a canvas which we can draw on.
  623. // insert it before the eventCanvas, so eventCanvas will still capture events.
  624. function postPlotDraw() {
  625. // Memory Leaks patch
  626. if (this.plugins.barRenderer && this.plugins.barRenderer.highlightCanvas) {
  627. this.plugins.barRenderer.highlightCanvas.resetCanvas();
  628. this.plugins.barRenderer.highlightCanvas = null;
  629. }
  630. this.plugins.barRenderer = {highlightedSeriesIndex:null};
  631. this.plugins.barRenderer.highlightCanvas = new $.jqplot.GenericCanvas();
  632. this.eventCanvas._elem.before(this.plugins.barRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-barRenderer-highlight-canvas', this._plotDimensions, this));
  633. this.plugins.barRenderer.highlightCanvas.setContext();
  634. this.eventCanvas._elem.bind('mouseleave', {plot:this}, function (ev) { unhighlight(ev.data.plot); });
  635. }
  636. function highlight (plot, sidx, pidx, points) {
  637. var s = plot.series[sidx];
  638. var canvas = plot.plugins.barRenderer.highlightCanvas;
  639. canvas._ctx.clearRect(0,0,canvas._ctx.canvas.width, canvas._ctx.canvas.height);
  640. s._highlightedPoint = pidx;
  641. plot.plugins.barRenderer.highlightedSeriesIndex = sidx;
  642. var opts = {fillStyle: s.highlightColors[pidx]};
  643. s.renderer.shapeRenderer.draw(canvas._ctx, points, opts);
  644. canvas = null;
  645. }
  646. function unhighlight (plot) {
  647. var canvas = plot.plugins.barRenderer.highlightCanvas;
  648. canvas._ctx.clearRect(0,0, canvas._ctx.canvas.width, canvas._ctx.canvas.height);
  649. for (var i=0; i<plot.series.length; i++) {
  650. plot.series[i]._highlightedPoint = null;
  651. }
  652. plot.plugins.barRenderer.highlightedSeriesIndex = null;
  653. plot.target.trigger('jqplotDataUnhighlight');
  654. canvas = null;
  655. }
  656. function handleMove(ev, gridpos, datapos, neighbor, plot) {
  657. if (neighbor) {
  658. var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
  659. var evt1 = jQuery.Event('jqplotDataMouseOver');
  660. evt1.pageX = ev.pageX;
  661. evt1.pageY = ev.pageY;
  662. plot.target.trigger(evt1, ins);
  663. if (plot.series[ins[0]].highlightMouseOver && !(ins[0] == plot.plugins.barRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
  664. var evt = jQuery.Event('jqplotDataHighlight');
  665. evt.which = ev.which;
  666. evt.pageX = ev.pageX;
  667. evt.pageY = ev.pageY;
  668. plot.target.trigger(evt, ins);
  669. highlight (plot, neighbor.seriesIndex, neighbor.pointIndex, neighbor.points);
  670. }
  671. }
  672. else if (neighbor == null) {
  673. unhighlight (plot);
  674. }
  675. }
  676. function handleMouseDown(ev, gridpos, datapos, neighbor, plot) {
  677. if (neighbor) {
  678. var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
  679. if (plot.series[ins[0]].highlightMouseDown && !(ins[0] == plot.plugins.barRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
  680. var evt = jQuery.Event('jqplotDataHighlight');
  681. evt.which = ev.which;
  682. evt.pageX = ev.pageX;
  683. evt.pageY = ev.pageY;
  684. plot.target.trigger(evt, ins);
  685. highlight (plot, neighbor.seriesIndex, neighbor.pointIndex, neighbor.points);
  686. }
  687. }
  688. else if (neighbor == null) {
  689. unhighlight (plot);
  690. }
  691. }
  692. function handleMouseUp(ev, gridpos, datapos, neighbor, plot) {
  693. var idx = plot.plugins.barRenderer.highlightedSeriesIndex;
  694. if (idx != null && plot.series[idx].highlightMouseDown) {
  695. unhighlight(plot);
  696. }
  697. }
  698. function handleClick(ev, gridpos, datapos, neighbor, plot) {
  699. if (neighbor) {
  700. var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
  701. var evt = jQuery.Event('jqplotDataClick');
  702. evt.which = ev.which;
  703. evt.pageX = ev.pageX;
  704. evt.pageY = ev.pageY;
  705. plot.target.trigger(evt, ins);
  706. }
  707. }
  708. function handleRightClick(ev, gridpos, datapos, neighbor, plot) {
  709. if (neighbor) {
  710. var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
  711. var idx = plot.plugins.barRenderer.highlightedSeriesIndex;
  712. if (idx != null && plot.series[idx].highlightMouseDown) {
  713. unhighlight(plot);
  714. }
  715. var evt = jQuery.Event('jqplotDataRightClick');
  716. evt.which = ev.which;
  717. evt.pageX = ev.pageX;
  718. evt.pageY = ev.pageY;
  719. plot.target.trigger(evt, ins);
  720. }
  721. }
  722. })(jQuery);