/* * Flot plugin to order bars side by side. * * Released under the MIT license by Benjamin BUFFET, 20-Sep-2010. * Modifications made by Steven Hall , 01-May-2013. * * This plugin is an alpha version. * * To activate the plugin you must specify the parameter "order" for the specific serie : * * $.plot($("#placeholder"), [{ data: [ ... ], bars :{ order = null or integer }]) * * If 2 series have the same order param, they are ordered by the position in the array; * * The plugin adjust the point by adding a value depanding of the barwidth * Exemple for 3 series (barwidth : 0.1) : * * first bar décalage : -0.15 * second bar décalage : -0.05 * third bar décalage : 0.05 * */ // INFO: decalage/decallage is French for gap. It's used to denote the spacing applied to each // bar. (function($){ function init(plot){ var orderedBarSeries; var nbOfBarsToOrder; var borderWidth; var borderWidthInXabsWidth; var pixelInXWidthEquivalent = 1; var isHorizontal = false; // A mapping of order integers to decallage. var decallageByOrder = {}; /* * This method add shift to x values */ function reOrderBars(plot, serie, datapoints){ var shiftedPoints = null; if(serieNeedToBeReordered(serie)){ checkIfGraphIsHorizontal(serie); calculPixel2XWidthConvert(plot); retrieveBarSeries(plot); calculBorderAndBarWidth(serie); if(nbOfBarsToOrder >= 2){ var position = findPosition(serie); var decallage = 0; var centerBarShift = calculCenterBarShift(); // If we haven't already calculated the decallage for this order value, do it. if(typeof decallageByOrder[serie.bars.order] === 'undefined') { if (isBarAtLeftOfCenter(position)){ decallageByOrder[serie.bars.order] = -1*(sumWidth(orderedBarSeries,position-1,Math.floor(nbOfBarsToOrder / 2)-1)) - centerBarShift; }else{ decallageByOrder[serie.bars.order] = sumWidth(orderedBarSeries,Math.ceil(nbOfBarsToOrder / 2),position-2) + centerBarShift + borderWidthInXabsWidth*2; } } // Lookup the decallage based on the series' order value. decallage = decallageByOrder[serie.bars.order]; shiftedPoints = shiftPoints(datapoints,serie,decallage); datapoints.points = shiftedPoints; } } return shiftedPoints; } function serieNeedToBeReordered(serie){ return serie.bars != null && serie.bars.show && serie.bars.order != null; } function calculPixel2XWidthConvert(plot){ var gridDimSize = isHorizontal ? plot.getPlaceholder().innerHeight() : plot.getPlaceholder().innerWidth(); var minMaxValues = isHorizontal ? getAxeMinMaxValues(plot.getData(),1) : getAxeMinMaxValues(plot.getData(),0); var AxeSize = minMaxValues[1] - minMaxValues[0]; pixelInXWidthEquivalent = AxeSize / gridDimSize; } function getAxeMinMaxValues(series,AxeIdx){ var minMaxValues = new Array(); for(var i = 0; i < series.length; i++){ minMaxValues[0] = series[i].data[0][AxeIdx]; minMaxValues[1] = series[i].data[series[i].data.length - 1][AxeIdx]; } return minMaxValues; } function retrieveBarSeries(plot){ orderedBarSeries = findOthersBarsToReOrders(plot.getData()); nbOfBarsToOrder = orderedBarSeries.length; } function findOthersBarsToReOrders(series){ var retSeries = new Array(); var orderValuesSeen = []; for(var i = 0; i < series.length; i++){ if(series[i].bars.order != null && series[i].bars.show && orderValuesSeen.indexOf(series[i].bars.order) < 0){ orderValuesSeen.push(series[i].bars.order); retSeries.push(series[i]); } } return retSeries.sort(sortByOrder); } function sortByOrder(serie1,serie2){ var x = serie1.bars.order; var y = serie2.bars.order; return ((x < y) ? -1 : ((x > y) ? 1 : 0)); } function calculBorderAndBarWidth(serie){ borderWidth = typeof serie.bars.lineWidth !== 'undefined' ? serie.bars.lineWidth : 2; borderWidthInXabsWidth = borderWidth * pixelInXWidthEquivalent; } function checkIfGraphIsHorizontal(serie){ if(serie.bars.horizontal){ isHorizontal = true; } } function findPosition(serie){ var pos = 0 for (var i = 0; i < orderedBarSeries.length; ++i) { if (serie == orderedBarSeries[i]){ pos = i; break; } } return pos+1; } function calculCenterBarShift(){ var width = 0; if(nbOfBarsToOrder%2 != 0) width = (orderedBarSeries[Math.ceil(nbOfBarsToOrder / 2)].bars.barWidth)/2; return width; } function isBarAtLeftOfCenter(position){ return position <= Math.ceil(nbOfBarsToOrder / 2); } function sumWidth(series,start,end){ var totalWidth = 0; for(var i = start; i <= end; i++){ totalWidth += series[i].bars.barWidth+borderWidthInXabsWidth*2; } return totalWidth; } function shiftPoints(datapoints,serie,dx){ var ps = datapoints.pointsize; var points = datapoints.points; var j = 0; for(var i = isHorizontal ? 1 : 0;i < points.length; i += ps){ points[i] += dx; //Adding the new x value in the serie to be abble to display the right tooltip value, //using the index 3 to not overide the third index. serie.data[j][3] = points[i]; j++; } return points; } plot.hooks.processDatapoints.push(reOrderBars); } var options = { series : { bars: {order: null} // or number/string } }; $.plot.plugins.push({ init: init, options: options, name: "orderBars", version: "0.2" }); })(jQuery);