I have created SPFx React project and integrate chart js library in that projecct
I have used "chart.js": "^3.3.2" version.
I need to add an image/icon in data labels and legends.
Also, I need to add a border outside of the image/icon added in legends.
Below is my code snippet.
<Chart type="pie" data={chartData} options={chartOptions} plugins={pluginsForShowDataOnPieChart} />
const iconImageArray = [
'.jpg',
'.jpg',
'.jpg',
];
const labelsNameArray = ["Label 1","Label 2","Label 3"]
const pieChartData = () => {
const documentStyle = getComputedStyle(document.documentElement);
const data = {
labels: labelsNameArray,
datasets: [
{
data: percentageDataArray,
backgroundColor: [
'#5066BB',
'#6FC66E',
'#ECAD68',
'#EF876C',
documentStyle.getPropertyValue('--cyan-500'),
documentStyle.getPropertyValue('--teal-500'),
documentStyle.getPropertyValue('--pink-500'),
],
hoverBackgroundColor: [
'#5066BB',
'#6FC66E',
'#ECAD68',
'#EF876C',
documentStyle.getPropertyValue('--cyan-500'),
documentStyle.getPropertyValue('--teal-500'),
documentStyle.getPropertyValue('--pink-500'),
],
toggledVisibility: Array(productArray.length).fill(true)
}
]
};
const options = {
aspectRatio: 2,
plugins: {
legend: {
position: 'right',
labels: {
usePointStyle: true,
padding: 20,
generateLabels: (chart) => {
const dataset = chart.data.datasets[0];
return dataset.data.map((data, i) => {
const img = new Image();
img.src = iconImageArray[i]; // Ensure iconImageArray contains valid image URLs
img.height = 10;
img.width = 10;
img.style.border = '1px solid';
img.style.borderColor = legendColor[i];
return {
text: chart.data.labels[i],
fillStyle: dataset.backgroundColor[i],
hidden: chart.getDatasetMeta(0).data[i].hidden,
index: i,
fontColor: dataset.toggledVisibility[i] ? '#495057' : '#888888',
textDecoration: dataset.toggledVisibility[i] ? 'none' : 'line-through', // Add strikethrough
pointStyle: img // Assign image as the point style
};
});
}
},
onClick: function (event, legendItem, legend) {
const ci = legend.chart;
const index = legendItem.index;
//below 2 lines for toggle visibility for clicked doughnut chart portion
const meta = ci.getDatasetMeta(0);
meta.data[index].hidden = !meta.data[index].hidden;
//below lines for number shown visibility on doughnut chart
const dataset = ci.data.datasets[0];
dataset.toggledVisibility[index] = !dataset.toggledVisibility[index];
ci.update();
}
},
tooltip: {
callbacks: {
label: (tooltipItem) => {
const countValue = productArray[tooltipItem.dataIndex]?.count || 0;
const renewCountValue = productArray[tooltipItem.dataIndex]?.renewCount || 0;
return `${tooltipItem.label}: ${countValue} | ${renewCountValue}`;
},
},
},
datalabels: {
formatter: (value) => `${value}%`,
color: '#fff',
anchor: 'end',
align: 'start',
offset: -10,
font: {
weight: 'bold',
},
},
},
};
setChartData(data);
setChartOptions(options);
};
// Plugin to display percentage inside the Pie Chart
const pluginsForShowDataOnPieChart = [
{
afterDraw: (chart) => {
const { ctx } = chart;
chart.data.datasets.forEach((dataset, i) => {
// Convert data values from string to number
const numericData = dataset.data.map(value => parseFloat(value) || 0);
const total = numericData.reduce((sum, value) => sum + value, 0);
chart.getDatasetMeta(i).data.forEach((datapoint, index) => {
if (dataset.toggledVisibility[index] && dataset.data[index] != 0) {
if (numericData[index] !== 0) {
const { x, y } = datapoint.tooltipPosition();
const percentage = ((numericData[index] / total) * 100).toFixed(1);
ctx.fillStyle = '#495057';
ctx.font = 'bold 12px Open Sans';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(`${percentage}%`, x, y + 7);
}
}
});
});
},
beforeDraw: (chart) => {
const { ctx } = chart;
ctx.restore();
ctx.fillStyle = '#495057';
ctx.font = 'bold 12px Open Sans';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
let total = 0;
let isTotalVisible = false;
if (chart.data.datasets[0] && chart.data.datasets[0].data) {
total = chart.data.datasets[0].data.reduce((sum, value) => sum + value, 0);
chart.data.datasets.forEach((dataset, i) => {
chart.getDatasetMeta(i).data.forEach((datapoint, index) => {
if (dataset.data[index] !== 0) {
isTotalVisible = true;
return;
}
});
});
}
ctx.save();
}
}
];
Can anyone help with the same?
Thanks in Advance.