As I've found strikethrough to be very annoying as it obscures the text so it's sometimes difficult to tell what the legend label is when hidden, I wanted to change the behavior and so that, instead of strikethrough, the label just changes to a gray color.
I'm using this for the onclick function:
legend:{
onClick:function(e,legendItem,legend){
toggleDatasetVisibility(e,legendItem,legend);
}
}
For the function, I've tried this:
function toggleDatasetVisibility(e, legendItem, legend) {
const index = legendItem.datasetIndex;
const ci = mychart;
const mydataset = ci.data.datasets[index];
const isVisible = ci.isDatasetVisible(index);
ci.setDatasetVisibility(index, !isVisible);
if (ci.isDatasetVisible(index)) {
legendItem.fontColor = 'red';
legendItem.hidden = false;
} else {
legendItem.fontColor = 'gray';
legendItem.hidden = false;
}
const legendItems = legend.legendItems;
legendItems[index].textDecoration = 'none';
}
But, the behavior I get now is that the label does change color when I click on it and the mouse cursor is still over the label, but once I move the mouse away, the dataset hides and the label goes back to strikethrough.
Any help that can be provided would be greatly appreciated.
You haven't specified the version of Chart.js you are using, so I assumed the latest, but with that your code gets some errors, which are easily corrected, and then nothing happens when one clicks on the legend color boxes. In any case, the solution should be the same, even wih a slightly older version.
Changing the legendItem
sent as an argument to onClick
handler
is not the way to change the appearance of the legend item. Nor is
the legend.legendItems[index]
, which is actually the same object.
At the time of the execution of onClick
, the legendItem
is only
for reading information.
To make any of the changes in toggleDatasetVisibility
appear on the
chart, one has to call ci.update()
; or functions like ci.hide()
or
ci.show()
that call update
themselves.
However, calls to update
result in calls to
generateLabels
,
(source code plugin.legend.js#L675)
and there the legend items are recomputed and those recomputed values
are used to display the legend label.
The solution then is to implement any alterations to the labelItems
in the function options.plugins.legend.labels.generateLabels
, taking into
account the state of the label (i.e., hidden):
const _defaultGenerateLabels = Chart.defaults.plugins.legend.labels.generateLabels;
function generateLabels(...args){
const labelItems = _defaultGenerateLabels.apply(this, args);
labelItems.forEach(labelItem => {
if(labelItem.hidden){
labelItem.hidden = false;
labelItem.fontColor = '#aaa';
labelItem.fillStyle = '#ddd';
labelItem.strokeStyle = '#ccc';
}
else{
labelItem.fontColor = 'red';
}
});
return labelItems;
}
the lines labelItem.fillStyle = '#ddd';
and
labelItem.strokeStyle = '#ccc';
set the adjacent color box to gray too.
For this application, there's no need to implement a handler for legend onClick
.
Demo snippet:
const _defaultGenerateLabels = Chart.defaults.plugins.legend.labels.generateLabels;
function generateLabels(...args){
const labelItems = _defaultGenerateLabels.apply(this, args);
labelItems.forEach(labelItem => {
if(labelItem.hidden ){
labelItem.hidden = false;
labelItem.fontColor = '#aaa';
labelItem.fillStyle = '#ddd';
labelItem.strokeStyle = '#ccc';
}
else{
//labelItem.fontColor = 'red';
// better set "normal" color in options.plugins.legend.label.color
}
})
return labelItems
}
const data = {
labels: [
'January', 'February', 'March', 'April', 'May', 'June'
],
datasets: [
{
label: 'Dataset 1',
data: Array.from({length: 6}, () => Math.random()*10 - 5),
},
{
label: 'Dataset 2',
data: Array.from({length: 6}, () => Math.random()*10 - 5),
},
]
};
const config = {
type: 'line',
data: data,
options: {
responsive: true,
plugins: {
legend: {
position: 'top',
labels: {
//color: 'red',
generateLabels
}
}
}
},
};
new Chart("myChart", config);
<div style="height: 200px">
<canvas id="myChart"></canvas>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>