I'm using the ng2-charts library in my Angular application to display charts. I would like to implement a feature where, when hovering over the corresponding legend label of a series, that series gets highlighted in the chart.
How can I achieve this behavior with ng2-charts? Is there a way to modify the styling of the series when the mouse hovers over the associated legend label?
I have already gone through the documentation of ng2-charts but couldn't find specific information about this. Any code snippet examples or detailed guidance would be greatly appreciated.
I am using chart.js version 4.2.1 and ng2-charts version 4.1.1.
Here's my code:
import { Component, Input, OnInit, OnDestroy, ViewChild, ElementRef } from '@angular/core';
import { Chart, ChartData, ChartOptions, ChartType } from 'chart.js';
import { ListService } from '../../services/component-services/list.service';
@Component({
selector: 'app-bar-chart',
templateUrl: './bar-chart.component.html',
styleUrls: ['./bar-chart.component.scss'],
})
export class BarChartComponent implements OnInit, OnDestroy {
subscriptions = [];
@Input()
guiConfig;
@Input()
minValue;
@Input()
maxValue;
ngOnDestroy(): void {
this.subscriptions.forEach((sub) => {
sub.unsubscribe();
});
}
public barChartType: ChartType = 'bar';
public barChartData: ChartData<'bar'>;
constructor(private listService: ListService) { }
ngOnInit() {
this.fetchData();
}
fetchData() {
let sub = this.listService.getBehaviorSubject(this.guiConfig['dataId']).subscribe((data) => {
let barChartDataMap: Map<JSON, object[]> = new Map<JSON, object[]>();
let labels = [];
let values = [];
let captions: JSON[] = [];
if (data !== undefined && data.length !== 0) {
for (let index = 0; index < data.length; index++) {
const element = data[index];
if (!labels.includes(element['xValue'])) {
labels.push(element['xValue']);
}
values.push(element['yValue']);
let caption = element['caption'];
let jsonObj = {};
jsonObj['caption'] = caption;
jsonObj['color'] = element['color'];
let extistsKey = captions.find((caption) => {
return JSON.stringify(caption) == JSON.stringify(jsonObj);
});
if (!extistsKey) {
captions.push(<JSON>jsonObj);
}
}
let datasets = [];
for (let index = 0; index < captions.length; index++) {
const caption = captions[index];
let dataArray = [];
for (let innerIndex = 0; innerIndex < data.length; innerIndex++) {
const dataPoint = data[innerIndex];
if (dataPoint['caption'] == caption['caption']) {
dataArray.push(dataPoint['yValue']);
}
}
barChartDataMap.set(caption, dataArray);
}
for (let el of barChartDataMap.keys()) {
let data = barChartDataMap.get(el);
let dataset = {};
dataset['data'] = data;
dataset['label'] = el['caption'];
dataset['barThickness'] = 20;
dataset['borderRadius'] = 5;
//Adds space between bars
dataset['borderColor'] = "rgba(0,0,0,0)";
dataset['borderWidth'] = 2;
dataset['backgroundColor'] = el['color'];
datasets.push(dataset);
}
let barChartData: ChartData<'bar'> = {
datasets: datasets,
labels: labels
}
this.barChartData = barChartData;
}
});
this.subscriptions.push(sub);
}
public barChartOptions: ChartOptions = {
responsive: true,
maintainAspectRatio: false,
animation: false,
onHover: // ...
}
@ViewChild('canvas')
canvas: ElementRef<HTMLCanvasElement>;
public getCanvas(): HTMLCanvasElement {
return this.canvas.nativeElement;
}
}
Thank you in advance for your assistance!
You need the options.plugins.legend.onHover
callback function to capture the event when the legend has hovered.
To highlight the bar elements, you need to call the setActiveElements
method and provide items of ActivePoints[]
. The key point is the ActivePoints
items must with the datasetIndex
which is the currently selected legend item index (legendItem.datasetIndex
) and index
for each item index in the dataset. Reference: Programmatic Event Triggers
import { Chart, ChartConfiguration, LegendItem } from 'chart.js';
import { BaseChartDirective } from 'ng2-charts';
@ViewChild(BaseChartDirective) baseChart!: BaseChartDirective;
ngAfterViewInit() {
this.barChartOptions = {
...this.barChartOptions,
plugins: {
legend: {
onHover: (evt, legendItem: LegendItem) => {
this.baseChart?.chart?.setActiveElements(
this.baseChart!.chart!.getDatasetMeta(
legendItem.datasetIndex!
).data!.map((x, i) => ({
datasetIndex: legendItem.datasetIndex!,
index: i,
}))
);
this.baseChart.update();
},
},
},
};
}