jquery.flot.orderBars.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. /*
  2. * Flot plugin to order bars side by side.
  3. *
  4. * Released under the MIT license by Benjamin BUFFET, 20-Sep-2010.
  5. * Modifications made by Steven Hall <github.com/emmerich>, 01-May-2013.
  6. *
  7. * This plugin is an alpha version.
  8. *
  9. * To activate the plugin you must specify the parameter "order" for the specific serie :
  10. *
  11. * $.plot($("#placeholder"), [{ data: [ ... ], bars :{ order = null or integer }])
  12. *
  13. * If 2 series have the same order param, they are ordered by the position in the array;
  14. *
  15. * The plugin adjust the point by adding a value depanding of the barwidth
  16. * Exemple for 3 series (barwidth : 0.1) :
  17. *
  18. * first bar décalage : -0.15
  19. * second bar décalage : -0.05
  20. * third bar décalage : 0.05
  21. *
  22. */
  23. // INFO: decalage/decallage is French for gap. It's used to denote the spacing applied to each
  24. // bar.
  25. (function($){
  26. function init(plot){
  27. var orderedBarSeries;
  28. var nbOfBarsToOrder;
  29. var borderWidth;
  30. var borderWidthInXabsWidth;
  31. var pixelInXWidthEquivalent = 1;
  32. var isHorizontal = false;
  33. // A mapping of order integers to decallage.
  34. var decallageByOrder = {};
  35. /*
  36. * This method add shift to x values
  37. */
  38. function reOrderBars(plot, serie, datapoints){
  39. var shiftedPoints = null;
  40. if(serieNeedToBeReordered(serie)){
  41. checkIfGraphIsHorizontal(serie);
  42. calculPixel2XWidthConvert(plot);
  43. retrieveBarSeries(plot);
  44. calculBorderAndBarWidth(serie);
  45. if(nbOfBarsToOrder >= 2){
  46. var position = findPosition(serie);
  47. var decallage = 0;
  48. var centerBarShift = calculCenterBarShift();
  49. // If we haven't already calculated the decallage for this order value, do it.
  50. if(typeof decallageByOrder[serie.bars.order] === 'undefined') {
  51. if (isBarAtLeftOfCenter(position)){
  52. decallageByOrder[serie.bars.order] = -1*(sumWidth(orderedBarSeries,position-1,Math.floor(nbOfBarsToOrder / 2)-1)) - centerBarShift;
  53. }else{
  54. decallageByOrder[serie.bars.order] = sumWidth(orderedBarSeries,Math.ceil(nbOfBarsToOrder / 2),position-2) + centerBarShift + borderWidthInXabsWidth*2;
  55. }
  56. }
  57. // Lookup the decallage based on the series' order value.
  58. decallage = decallageByOrder[serie.bars.order];
  59. shiftedPoints = shiftPoints(datapoints,serie,decallage);
  60. datapoints.points = shiftedPoints;
  61. }
  62. }
  63. return shiftedPoints;
  64. }
  65. function serieNeedToBeReordered(serie){
  66. return serie.bars != null
  67. && serie.bars.show
  68. && serie.bars.order != null;
  69. }
  70. function calculPixel2XWidthConvert(plot){
  71. var gridDimSize = isHorizontal ? plot.getPlaceholder().innerHeight() : plot.getPlaceholder().innerWidth();
  72. var minMaxValues = isHorizontal ? getAxeMinMaxValues(plot.getData(),1) : getAxeMinMaxValues(plot.getData(),0);
  73. var AxeSize = minMaxValues[1] - minMaxValues[0];
  74. pixelInXWidthEquivalent = AxeSize / gridDimSize;
  75. }
  76. function getAxeMinMaxValues(series,AxeIdx){
  77. var minMaxValues = new Array();
  78. for(var i = 0; i < series.length; i++){
  79. minMaxValues[0] = (series[i].data[0]) ? series[i].data[0][AxeIdx]: null;
  80. minMaxValues[1] = (series[i].data[series[i].data.length - 1]) ? series[i].data[series[i].data.length - 1][AxeIdx]: null;
  81. }
  82. return minMaxValues;
  83. }
  84. function retrieveBarSeries(plot){
  85. orderedBarSeries = findOthersBarsToReOrders(plot.getData());
  86. nbOfBarsToOrder = orderedBarSeries.length;
  87. }
  88. function findOthersBarsToReOrders(series){
  89. var retSeries = new Array();
  90. var orderValuesSeen = [];
  91. for(var i = 0; i < series.length; i++){
  92. if(series[i].bars.order != null && series[i].bars.show &&
  93. orderValuesSeen.indexOf(series[i].bars.order) < 0){
  94. orderValuesSeen.push(series[i].bars.order);
  95. retSeries.push(series[i]);
  96. }
  97. }
  98. return retSeries.sort(sortByOrder);
  99. }
  100. function sortByOrder(serie1,serie2){
  101. var x = serie1.bars.order;
  102. var y = serie2.bars.order;
  103. return ((x < y) ? -1 : ((x > y) ? 1 : 0));
  104. }
  105. function calculBorderAndBarWidth(serie){
  106. borderWidth = typeof serie.bars.lineWidth !== 'undefined' ? serie.bars.lineWidth : 2;
  107. borderWidthInXabsWidth = borderWidth * pixelInXWidthEquivalent;
  108. }
  109. function checkIfGraphIsHorizontal(serie){
  110. if(serie.bars.horizontal){
  111. isHorizontal = true;
  112. }
  113. }
  114. function findPosition(serie){
  115. var pos = 0
  116. for (var i = 0; i < orderedBarSeries.length; ++i) {
  117. if (serie == orderedBarSeries[i]){
  118. pos = i;
  119. break;
  120. }
  121. }
  122. return pos+1;
  123. }
  124. function calculCenterBarShift(){
  125. var width = 0;
  126. if(nbOfBarsToOrder%2 != 0)
  127. width = (orderedBarSeries[Math.ceil(nbOfBarsToOrder / 2)].bars.barWidth)/2;
  128. return width;
  129. }
  130. function isBarAtLeftOfCenter(position){
  131. return position <= Math.ceil(nbOfBarsToOrder / 2);
  132. }
  133. function sumWidth(series,start,end){
  134. var totalWidth = 0;
  135. for(var i = start; i <= end; i++){
  136. totalWidth += series[i].bars.barWidth+borderWidthInXabsWidth*2;
  137. }
  138. return totalWidth;
  139. }
  140. function shiftPoints(datapoints,serie,dx){
  141. var ps = datapoints.pointsize;
  142. var points = datapoints.points;
  143. var j = 0;
  144. for(var i = isHorizontal ? 1 : 0;i < points.length; i += ps){
  145. points[i] += dx;
  146. //Adding the new x value in the serie to be abble to display the right tooltip value,
  147. //using the index 3 to not overide the third index.
  148. serie.data[j][3] = points[i];
  149. j++;
  150. }
  151. return points;
  152. }
  153. plot.hooks.processDatapoints.push(reOrderBars);
  154. }
  155. var options = {
  156. series : {
  157. bars: {order: null} // or number/string
  158. }
  159. };
  160. $.plot.plugins.push({
  161. init: init,
  162. options: options,
  163. name: "orderBars",
  164. version: "0.2"
  165. });
  166. })(jQuery);