Chart.js Fix issue #3589

by SAiTO TOSHiKi

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.4.0/Chart.bundle.js"></script>
<div class="container">
  <div class="chart-container">
    <canvas id="myChart1"></canvas>
  </div>
  <div class="chart-container">
    <canvas id="myChart2"></canvas>
  </div>
  <div class="chart-container">
    <canvas id="myChart3"></canvas>
  </div>
  <div class="chart-container">
    <canvas id="myChart4"></canvas>
  </div>
</div>

<script>
  window.chartColors = {
    red: 'rgb(255, 99, 132)',
    orange: 'rgb(255, 159, 64)',
    yellow: 'rgb(255, 205, 86)',
    green: 'rgb(75, 192, 192)',
    blue: 'rgb(54, 162, 235)',
    purple: 'rgb(153, 102, 255)',
    grey: 'rgb(231,233,237)'
  };

</script>

CSS

.chart-container {
  width: 500px;
  margin-left: 40px;
  margin-right: 40px;
  margin-bottom: 40px;
}

.container {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  justify-content: center;
}

JavaScript

// camvas clipping plugin
   // See
   // https://github.com/chartjs/Chart.js/issues/3506
   // https://github.com/chartjs/Chart.js/issues/3491
   // https://github.com/chartjs/Chart.js/issues/2873
   Chart.plugins.register({
     beforeDatasetsDraw: function(chartInstance) {
       var ctx = chartInstance.chart.ctx;
       var chartArea = chartInstance.chartArea;
       ctx.save();
       ctx.beginPath();
       ctx.rect(chartArea.left, chartArea.top, chartArea.right - chartArea.left, chartArea.bottom - chartArea.top);
       ctx.clip();
     },
     afterDatasetsDraw: function(chartInstance) {
       chartInstance.chart.ctx.restore();
     },
   });

   // temporaly override function for Bar controller
   var oldConBar = Chart.controllers.bar;
   Chart.controllers.bar = oldConBar.extend({

     getRuler: function() {
       var me = this;
       var meta = me.getMeta();
       var xScale = me.getScaleForId(meta.xAxisID);
       var datasetCount = me.getBarCount();

       var tickWidth = xScale.width / xScale.ticks.length;
       var categoryWidth = tickWidth * xScale.options.categoryPercentage;
       var categorySpacing = (tickWidth - (tickWidth * xScale.options.categoryPercentage)) / 2;
       var fullBarWidth = categoryWidth / datasetCount;

       var barWidth = fullBarWidth * xScale.options.barPercentage;
       var barSpacing = fullBarWidth - (fullBarWidth * xScale.options.barPercentage);

       return {
         datasetCount: datasetCount,
         tickWidth: tickWidth,
         categoryWidth: categoryWidth,
         categorySpacing: categorySpacing,
         fullBarWidth: fullBarWidth,
         barWidth: barWidth,
         barSpacing: barSpacing
       };
     },

     calculateBarWidth: function(ruler) {
       var xScale = this.getScaleForId(this.getMeta().xAxisID);
       if (xScale.options.barThickness) {
         return xScale.options.barThickness;
       }
       return xScale.options.stacked ? ruler.categoryWidth * xScale.options.barPercentage...