Search code examples
javascripthtmljquerycanvaschart.js

Bar dashed chart is overlapping in chartjs


I have data and I am creating a stacked bar chart, I want one of the datasets to be a dashed bar chart.

The live: demo

Here is what I have done so far.

HTML.

<canvas id="myChart"></canvas>

And Js.

var ctx = document.getElementById("myChart").getContext('2d');
var myChart = new Chart(ctx, {
    type: 'bar',
    data: {
        labels: ["January", "February", "March", "April", "May", "June", "July"],
        datasets: [{
            label: 'Employee',
            backgroundColor: "blue",
            data: [12, 59, 5, 56, 58,12, 59, 87, 45],
      borderColor:"#45c490",
      borderWidth: 0
        }, {
            label: 'Engineer',
            backgroundColor: "orange",
            data: [12, 59, 5, 56, 58,12, 59, 85, 23],
      borderColor:"#caf270",
      borderWidth: 0
        }, {
            label: 'Government',
            backgroundColor: "pink",
            data: [12, 59, 5, 56, 58,12, 59, 65, 51],
      borderColor: "rgba(255,99,132,1)",
      borderWidth: 0
        }, {
            label: 'Political parties',
            backgroundColor: "gray",
            data: [12, 59, 5, 56, 58, 12, 59, 12, 74],
      borderColor:"#caf270",
      borderWidth: 0
        }],
    },
options: {
    tooltips: {
      displayColors: true,
      callbacks:{
        mode: 'x',
      },
    },
    scales: {
      xAxes: [{
        stacked: true,
        gridLines: {
          display: false,
        }
      }],
      yAxes: [{
        stacked: true,
        ticks: {
          beginAtZero: true,
        },
        type: 'linear',
      }]
    },
        responsive: true,
        maintainAspectRatio: false,
        legend: { position: 'bottom' },
   
    },
  plugins: [{
    afterDatasetDraw: function(chart, args, options) {
       args.meta.data.forEach(function(element) {
         var borderWidth = 3;
         var ctx = chart.ctx;
         var vm = element._view;
         var half = vm.width / 2;
         var left = vm.x - half;
         var right = vm.x + half;
         var top = vm.y;
         var width = right - left;
         var height = chart.chartArea.bottom - top + (borderWidth / 2) - 1;
         let label = vm.datasetLabel;
         if(label.includes("Government")){
          ctx.setLineDash([5,5]);
          borderWidth=1;
         }else{
          ctx.setLineDash([0,0]);
          borderWidth=1
         }
         ctx.beginPath();
         ctx.lineWidth = borderWidth;
         ctx.strokeStyle = vm.borderColor;
         ctx.moveTo(left, top);
         ctx.lineTo(left, top + height);
         ctx.moveTo(left, top);
         ctx.lineTo(left + width, top);
         ctx.moveTo(left + width, top);
         ctx.lineTo(left + width, top + height);
         ctx.stroke();
         ctx.save();
   });
     }
   }]
});

I want only if the dataset label is Government then create the dashed bar otherwise just normal

The problem enter image description here

In the picture above you can see the government dataset has dashed and the blue border.

How can I eliminate this blue border here?


Solution

  • The issue should be in the height calculation because the plugin was thought for no-stacked bar.:

    var height = chart.chartArea.bottom - top + (borderWidth / 2) - 1;
    

    As you can see, the height is calculated assuming to go to the bottom of chart area. You can try the following, overriding the above row:

    const valueTop = element._yScale.getValueForPixel(top);
    const value = chart.data.datasets[element._datasetIndex].data[element._index];
    const bottom = element._yScale.getPixelForValue(valueTop - value);
    var height = bottom - top + (borderWidth / 2) - 1;