2015-08-21 131 views
0

我需要呈現一組連續塊的時間序列數據。Chart.js動態欄寬度

我需要描述一系列可能跨越很多小時,或僅僅幾分鐘,具有自己的Y值的酒吧。

我不確定ChartJS是否應該用於此目的,但我已經看過擴展Bar類型,但它似乎非常硬編碼爲每個欄是相同的寬度。 Scale Class內部用於標籤,圖表寬度等,而不僅僅是條形本身。

我想實現這樣的事情在Excel工作:http://peltiertech.com/variable-width-column-charts/

任何人都有拿出類似的東西?

enter image description here

+0

http://stackoverflow.com/questions/13058195?這是highcharts順便說一句(需要一個許可證,如果商業使用),而不是chart.js – potatopeelings

+0

謝謝,如果我找不到D3上建立的版本(我想在欄上繪製其他項目),這是一個很好的選擇。 – James

+0

D3是一個非常好的選擇。並incase你還沒有看到它 - 結帳http://stackoverflow.com/questions/21610828 – potatopeelings

回答

0

對於chart.js之,你可以創建基於該條類做這個新的擴展。這雖然複雜一些 - 但是大部分是直板型庫代碼

Chart.types.Bar.extend({ 
    name: "BarAlt", 
    // all blocks that don't have a comment are a direct copy paste of the Chart.js library code 
    initialize: function (data) { 

     // the sum of all widths 
     var widthSum = data.datasets[0].data2.reduce(function (a, b) { return a + b }, 0); 
     // cumulative sum of all preceding widths 
     var cumulativeSum = [ 0 ]; 
     data.datasets[0].data2.forEach(function (e, i, arr) { 
      cumulativeSum.push(cumulativeSum[i] + e); 
     }) 


     var options = this.options; 

     // completely rewrite this class to calculate the x position and bar width's based on data2 
     this.ScaleClass = Chart.Scale.extend({ 
      offsetGridLines: true, 
      calculateBarX: function (barIndex) { 
       var xSpan = this.width - this.xScalePaddingLeft; 
       var x = this.xScalePaddingLeft + (cumulativeSum[barIndex]/widthSum * xSpan) - this.calculateBarWidth(barIndex)/2; 
       return x + this.calculateBarWidth(barIndex); 
      }, 
      calculateBarWidth: function (index) { 
       var xSpan = this.width - this.xScalePaddingLeft; 
       return (xSpan * data.datasets[0].data2[index]/widthSum); 
      } 
     }); 

     this.datasets = []; 

     if (this.options.showTooltips) { 
      Chart.helpers.bindEvents(this, this.options.tooltipEvents, function (evt) { 
       var activeBars = (evt.type !== 'mouseout') ? this.getBarsAtEvent(evt) : []; 

       this.eachBars(function (bar) { 
        bar.restore(['fillColor', 'strokeColor']); 
       }); 
       Chart.helpers.each(activeBars, function (activeBar) { 
        activeBar.fillColor = activeBar.highlightFill; 
        activeBar.strokeColor = activeBar.highlightStroke; 
       }); 
       this.showTooltip(activeBars); 
      }); 
     } 

     this.BarClass = Chart.Rectangle.extend({ 
      strokeWidth: this.options.barStrokeWidth, 
      showStroke: this.options.barShowStroke, 
      ctx: this.chart.ctx 
     }); 

     Chart.helpers.each(data.datasets, function (dataset, datasetIndex) { 

      var datasetObject = { 
       label: dataset.label || null, 
       fillColor: dataset.fillColor, 
       strokeColor: dataset.strokeColor, 
       bars: [] 
      }; 

      this.datasets.push(datasetObject); 

      Chart.helpers.each(dataset.data, function (dataPoint, index) { 
       datasetObject.bars.push(new this.BarClass({ 
        value: dataPoint, 
        label: data.labels[index], 
        datasetLabel: dataset.label, 
        strokeColor: dataset.strokeColor, 
        fillColor: dataset.fillColor, 
        highlightFill: dataset.highlightFill || dataset.fillColor, 
        highlightStroke: dataset.highlightStroke || dataset.strokeColor 
       })); 
      }, this); 

     }, this); 

     this.buildScale(data.labels); 
     // remove the labels - they won't be positioned correctly anyway 
     this.scale.xLabels.forEach(function (e, i, arr) { 
      arr[i] = ''; 
     }) 

     this.BarClass.prototype.base = this.scale.endPoint; 

     this.eachBars(function (bar, index, datasetIndex) { 
      // change the way the x and width functions are called 
      Chart.helpers.extend(bar, { 
       width: this.scale.calculateBarWidth(index), 
       x: this.scale.calculateBarX(index), 
       y: this.scale.endPoint 
      }); 

      bar.save(); 
     }, this); 

     this.render(); 
    }, 
    draw: function (ease) { 
     var easingDecimal = ease || 1; 
     this.clear(); 

     var ctx = this.chart.ctx; 

     this.scale.draw(1); 

     Chart.helpers.each(this.datasets, function (dataset, datasetIndex) { 
      Chart.helpers.each(dataset.bars, function (bar, index) { 
       if (bar.hasValue()) { 
        bar.base = this.scale.endPoint; 
        // change the way the x and width functions are called 
        bar.transition({ 
         x: this.scale.calculateBarX(index), 
         y: this.scale.calculateY(bar.value), 
         width: this.scale.calculateBarWidth(index) 
        }, easingDecimal).draw(); 

       } 
      }, this); 

     }, this); 
    } 
}); 

你傳入寬度像下面

var data = { 
    labels: ['A', 'B', 'C', 'D', 'E', 'F', 'G'], 
    datasets: [ 
     { 
      label: "My First dataset", 
      fillColor: "rgba(220,220,220,0.5)", 
      strokeColor: "rgba(220,220,220,0.8)", 
      highlightFill: "rgba(220,220,220,0.7)", 
      highlightStroke: "rgba(220,220,220,1)", 
      data: [65, 59, 80, 30, 56, 65, 40], 
      data2: [10, 20, 30, 20, 10, 40, 10] 
     }, 
    ] 
}; 

,並調用它像這樣

的複製粘貼
var ctx = document.getElementById('canvas').getContext('2d'); 
var myLineChart = new Chart(ctx).BarAlt(data); 

小提琴 - http://jsfiddle.net/moye0cp4/


enter image description here

0

我發現我需要做到這一點,通過@potatopeelings答案是偉大的,但過時的Chartjs第2版。我做了類似的事情由通過延伸的杆創造我自己的控制器/圖表類型:

//controller.barw.js 

module.exports = function(Chart) { 

    var helpers = Chart.helpers; 

    Chart.defaults.barw = { 
     hover: { 
      mode: 'label' 
     }, 

     scales: { 
      xAxes: [{ 
       type: 'category', 

       // Specific to Bar Controller 
       categoryPercentage: 0.8, 
       barPercentage: 0.9, 

       // grid line settings 
       gridLines: { 
        offsetGridLines: true 
       } 
      }], 
      yAxes: [{ 
       type: 'linear' 
      }] 
     } 
    }; 

    Chart.controllers.barw = Chart.controllers.bar.extend({ 

     /** 
     * @private 
     */ 
     getRuler: function() { 
      var me = this; 
      var scale = me.getIndexScale(); 
      var options = scale.options; 
      var stackCount = me.getStackCount(); 
      var fullSize = scale.isHorizontal()? scale.width : scale.height; 
      var tickSize = fullSize/scale.ticks.length; 
      var categorySize = tickSize * options.categoryPercentage; 
      var fullBarSize = categorySize/stackCount; 
      var barSize = fullBarSize * options.barPercentage; 

      barSize = Math.min(
       helpers.getValueOrDefault(options.barThickness, barSize), 
       helpers.getValueOrDefault(options.maxBarThickness, Infinity)); 

      return { 
       fullSize: fullSize, 
       stackCount: stackCount, 
       tickSize: tickSize, 
       categorySize: categorySize, 
       categorySpacing: tickSize - categorySize, 
       fullBarSize: fullBarSize, 
       barSize: barSize, 
       barSpacing: fullBarSize - barSize, 
       scale: scale 
      }; 
     }, 


     /** 
     * @private 
     */ 
     calculateBarIndexPixels: function(datasetIndex, index, ruler) { 
      var me = this; 
      var scale = ruler.scale; 
      var options = scale.options; 
      var isCombo = me.chart.isCombo; 
      var stackIndex = me.getStackIndex(datasetIndex); 
      var base = scale.getPixelForValue(null, index, datasetIndex, isCombo); 
      var size = ruler.barSize; 

      var dataset = me.chart.data.datasets[datasetIndex]; 
      if(dataset.weights) { 
       var total = dataset.weights.reduce((m, x) => m + x, 0); 
       var perc = dataset.weights[index]/total; 
       var offset = 0; 
       for(var i = 0; i < index; i++) { 
        offset += dataset.weights[i]/total; 
       } 
       var pixelOffset = Math.round(ruler.fullSize * offset); 
       var base = scale.isHorizontal() ? scale.left : scale.top; 
       base += pixelOffset; 

       size = Math.round(ruler.fullSize * perc); 
       size -= ruler.categorySpacing; 
       size -= ruler.barSpacing; 
      }    

      base -= isCombo? ruler.tickSize/2 : 0; 
      base += ruler.fullBarSize * stackIndex; 
      base += ruler.categorySpacing/2; 
      base += ruler.barSpacing/2; 

      return { 
       size: size, 
       base: base, 
       head: base + size, 
       center: base + size/2 
      }; 
     }, 
    }); 
}; 

然後,你需要把它添加到您的chartjs實例是這樣的:

import Chart from 'chart.js' 
import barw from 'controller.barw' 

barw(Chart); //add plugin to chartjs 

最後,類似於其他答案,需要將條寬的權重添加到數據集中:

var data = { 
    labels: ['A', 'B', 'C', 'D', 'E', 'F', 'G'], 
    datasets: [ 
     { 
      label: "My First dataset", 
      fillColor: "rgba(220,220,220,0.5)", 
      strokeColor: "rgba(220,220,220,0.8)", 
      highlightFill: "rgba(220,220,220,0.7)", 
      highlightStroke: "rgba(220,220,220,1)", 
      data: [65, 59, 80, 30, 56, 65, 40], 
      weights: [1, 0.9, 1, 2, 1, 4, 0.3] 
     }, 
    ] 
}; 

這將有希望讓某人走上正軌。我當然不是完美的,但是如果你確定你的數據權重合適,你應該是對的。

祝你好運。