2

I have this stacked bar chart created using the <Bar /> component from react-chartjs-2 charting library. My chart

I used React to do this. But answers considering the equivalent in vanilla JS would also be very helpful!

Now what I want is, when I hover over the orange section of the 1st Jun stack, then the orange section in all the stacks should be highlighted. Either the opacity of all sections except orange decreases, or the orange sections slightly enlarge. If these are not possible, atleast a border should be drawn around the orange sections.

I've searched through the chartjs documentation and searched through chartjs plugins in npm registry. But I found nothing related to this.

What should be done in order to achieve this?

2 Answers2

1

You can use the onHover callback for it.

Live example:

var options = {
  type: 'bar',
  data: {
    labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
    datasets: [{
        label: '# of Votes',
        data: [12, 19, 3, 5, 2, 3],
        backgroundColor: '#FF0000',
      },
      {
        label: '# of Points',
        data: [7, 11, 5, 8, 3, 7],
        backgroundColor: '#0000FF'
      }
    ]
  },
  options: {
    onHover: (e, activeEls, chart) => {
      if (activeEls.length === 0) {
        chart.data.datasets.forEach((dataset) => {
          dataset.backgroundColor = dataset.backgroundColor.length === 9 ? dataset.backgroundColor.slice(0, -2) : dataset.backgroundColor;
        });
        chart.update();
        return;
      }

      const hoveredEl = chart.getElementsAtEventForMode(e, 'point', {
        intersect: true
      }, true)[0]

      chart.data.datasets.forEach((dataset, i) => {
        dataset.backgroundColor = (hoveredEl.datasetIndex === i || dataset.backgroundColor.length === 9) ? dataset.backgroundColor : dataset.backgroundColor + '4D';
      });

      chart.update();
    },
    scales: {
      y: {
        stacked: true
      },
      x: {
        stacked: true
      }
    }
  }
}

var ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
  <canvas id="chartJSContainer" width="600" height="400"></canvas>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.4.0/chart.js"></script>
</body>
LeeLenalee
  • 27,463
  • 6
  • 45
  • 69
0

With reference to @LeeLenalee's solution, I've come up with the answer for the React implementation

options: {
  onHover: (e, activeEls) => {
    if (activeEls.length === 0) {
      this.chart.chartInstance.config.data.datasets.forEach((dataset) => {
        dataset.backgroundColor =
          dataset.backgroundColor.length === 9
            ? dataset.backgroundColor.slice(0, -2)
            : dataset.backgroundColor;
      });
      this.chart.chartInstance.update();
      return;
    }

    const hoveredEl = this.chart.chartInstance.getDatasetAtEvent(e)[0];

    this.chart.chartInstance.config.data.datasets.forEach((dataset, i) => {
      const [boldColor, lightColor] =
        dataset.backgroundColor.length === 9
          ? [dataset.backgroundColor.slice(0, -2), dataset.backgroundColor]
          : [dataset.backgroundColor, dataset.backgroundColor + "4D"];
      dataset.backgroundColor =
        hoveredEl._datasetIndex === i ? boldColor : lightColor;
    });

    this.chart.chartInstance.update();
  }
}

where this.chart is the ref to my <Bar /> component.

Notice that I have

const [boldColor, lightColor] =
  dataset.backgroundColor.length === 9
    ? [dataset.backgroundColor.slice(0, -2), dataset.backgroundColor]
    : [dataset.backgroundColor, dataset.backgroundColor + "4D"];
  dataset.backgroundColor =
    hoveredEl._datasetIndex === i ? boldColor : lightColor;

from line-17 to line-20. This helps to avoid the unnecessary glitch that I saw in @LeeLenalee's code snippet when the bar's opacity was changing.