0

I have been searching around and can't find a solution to disable the view of each individual bar.

I have a bar chart with a wide range of values: Bar-chart

And I want to be able to toggle the viewing of individual values as one can do in the doughnut chart: doughnut-char with disabled values

This doughnut-char is using the same dataset, but I have disabled the top-3 values.

How can this behaviour be applied to the bar-chart?

Edit/Clarification: With disabling I mean by clicking the corresponding label; as one can do in the doughnut chart: enter image description here enter image description here

Sondre
  • 105
  • 2
  • 11
  • Have you tried removing the data from the dataset for the values you wish to remove? – Dean Meehan Oct 12 '20 at 13:20
  • I want the user to be able to toggle the information, so removing it from viewing will not help; replaced disable with toggle in my question for clarification. – Sondre Oct 12 '20 at 13:36

2 Answers2

1

As you already mention in the title of your question, each bar must be defined in a separate dataset. Also data.labels should be defined as an array that contains a single empty string ([""]).

Please take a look at below runnable code and see how it works.

new Chart("chart", {
  type: "bar",
  data: {
    labels: [""],    
    datasets: [{
      label: "A",
      data: [65],
      backgroundColor: "rgba(255, 99, 132, 0.2)",
      borderColor: "rgb(255, 99, 132)",
      borderWidth: 1
    },
    {
      label: "B",
      data: [59],
      backgroundColor: "rgba(255, 159, 64, 0.2)",
      borderColor: "rgb(255, 159, 64)",
      borderWidth: 1
    },
    {
      label: "C",
      data: [80],
      backgroundColor: "rgba(255, 205, 86, 0.2)",
      borderColor: "rgb(255, 205, 86)",
      borderWidth: 1
    },
    {
      label: "D",
      data: [56],
      backgroundColor: "rgba(75, 192, 192, 0.2)",
      borderColor: "rgb(75, 192, 192)",
      borderWidth: 1
    },
    {
      label: "E",
      data: [55],
      backgroundColor: "rgba(54, 162, 235, 0.2)",
      borderColor: "rgb(54, 162, 235)",
      borderWidth: 1
    }]
  },
  options: {
    scales: {
      yAxes: [{
        ticks: {
          beginAtZero: true
        }
      }]
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="chart" height="80"></canvas>

UPDATE (13. May 2021)

Meanwhile I answered a similar question and improved the code I posted here. This solution is cleaner and now also displays the tick labels on the x-axis.

uminder
  • 23,831
  • 5
  • 37
  • 72
  • Thank you for providing me a working example :) However, the labels under each bar are now missing with this approach and displays empty space on each side of the graphs(This does not nearly look as bad with 5 graphs compared to 10+ graphs) – Sondre Oct 13 '20 at 05:54
1

It seems that you'll have to generate custom HTML legend using legendCallback together with some CSS.

legendCallback: chart => {
  let html = '<ul>';
  chart.data.labels.forEach((l, i) => {
    const ds = chart.data.datasets[0];
    const bgColor = ds.backgroundColor[i];
    const border = ds.borderWidth + 'px solid ' + ds.borderColor[i];
    html += '<li>' +
      '<span style="width: 36px; height: 14px; background-color:' + bgColor + '; border:' + border + '" onclick="onLegendClicked(event, \'' + i + '\')">&nbsp;</span>' +
      '<span id="legend-label-' + i + '" onclick="onLegendClicked(event, \'' + i + '\')">' +
      (Array.isArray(l) ? l.join('<br/>') : l) + '</span>' +
      '</li>';
  });
  return html + '</ul>';
},

To make this behave the same as standard Chart.js charts, the function onLegendClicked is invoked when a mouse click occurs on a legend label. This function redefines data.labels and the dataset (data, backgroundColor and borderColor) by keeping trak of the hidden state of individual bars. It also changes the legend labels text style between normal and strike-through.

Please take a look at the following code snippet and see how it works.

const labels = ["January", "February", "March", "April", "May", "June", "July"];
const data = [65, 59, 80, 81, 56, 55, 40];
const backgroundColor = ["rgba(255, 99, 132, 0.2)", "rgba(255, 159, 64, 0.2)", "rgba(255, 205, 86, 0.2)", "rgba(75, 192, 192, 0.2)", "rgba(54, 162, 235, 0.2)", "rgba(153, 102, 255, 0.2)", "rgba(201, 203, 207, 0.2)"];
const borderColor = ["rgb(255, 99, 132)", "rgb(255, 159, 64)", "rgb(255, 205, 86)", "rgb(75, 192, 192)", "rgb(54, 162, 235)", "rgb(153, 102, 255)", "rgb(201, 203, 207)"];

const states = labels.map((l, i) => ({index: i, hidden: false}));

function onLegendClicked(e, i) {
  let hidden = !states[i].hidden; 
  states[i].hidden = hidden;  
  let nonHiddenIndexes = states.filter(s => !s.hidden).map(s => s.index);
  chart.data.labels = nonHiddenIndexes.map(i => labels[i]);
  chart.data.datasets[0].data = nonHiddenIndexes.map(i => data[i]);
  chart.data.datasets[0].backgroundColor = nonHiddenIndexes.map(i => backgroundColor[i]);
  chart.data.datasets[0].borderColor = nonHiddenIndexes.map(i => borderColor[i]);
  const legendLabelSpan = document.getElementById("legend-label-" + i);
  legendLabelSpan.style.textDecoration = hidden ? 'line-through' : '';
  chart.update();
};

const chart = new Chart("chart", {
  type: "bar",
  data: {
    labels: labels,
    datasets: [{
      label: "My First Dataset",
      data: [65, 59, 80, 81, 56, 55, 40],
      backgroundColor: ["rgba(255, 99, 132, 0.2)", "rgba(255, 159, 64, 0.2)", "rgba(255, 205, 86, 0.2)", "rgba(75, 192, 192, 0.2)", "rgba(54, 162, 235, 0.2)", "rgba(153, 102, 255, 0.2)", "rgba(201, 203, 207, 0.2)"],
      borderColor: ["rgb(255, 99, 132)", "rgb(255, 159, 64)", "rgb(255, 205, 86)", "rgb(75, 192, 192)", "rgb(54, 162, 235)", "rgb(153, 102, 255)", "rgb(201, 203, 207)"],
      borderWidth: 1
    }]
  },
  options: {
    legend: {
      display: false
    },
    legendCallback: chart => {
      let html = '<ul>';
      chart.data.labels.forEach((l, i) => {
        const ds = chart.data.datasets[0];
        const bgColor = ds.backgroundColor[i];
        const border = ds.borderWidth + 'px solid ' + ds.borderColor[i];
        html += '<li>' +
          '<span style="width: 36px; height: 14px; background-color:' + bgColor + '; border:' + border + '" onclick="onLegendClicked(event, \'' + i + '\')">&nbsp;</span>' +
          '<span id="legend-label-' + i + '" onclick="onLegendClicked(event, \'' + i + '\')">' +
          (Array.isArray(l) ? l.join('<br/>') : l) + '</span>' +
          '</li>';
      });
      return html + '</ul>';
    },
    scales: {
      yAxes: [{
        ticks: {
          beginAtZero: true
        }
      }]
    }
  }
});
document.getElementById("legend").innerHTML = chart.generateLegend();
#legend>ul {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
}

#legend li {
  cursor: pointer;
  margin: 10px 10px;
  display: flex;
}

#legend li span {
  padding-left: 8px;
  font-family: Arial, Helvetica, sans-serif;
  font-size: 12px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<div style="width: 500px">
  <div id="legend"></div>
  <canvas id="chart" height="150"></canvas>
</div>
uminder
  • 23,831
  • 5
  • 37
  • 72