chart.jssharepoint-onlinespfxprimereactsharepointframework

How do we add labels like the image?


I have created the SPFx React project.

I have implemented a bar chart using PrimeReact charts.

To my knowledge, PrimeReact uses the ChartJs library on the back end.

I need to add a label and value mark in red and blue to the image below. Bar Chart

Below is my code snippet,

import { Chart } from 'primereact';
import { Chart as ChartJS, ArcElement, Tooltip, Legend } from "chart.js";
ChartJS.register(ArcElement, Tooltip, Legend, ChartDataLabels);

    <Chart type="bar" data={barChartData} options={barChartOptions} />
    
    const barChartData = {
                        labels: ["Excellent", "Very Good", "Good", "Average"],
                        datasets: [
                          {
                            label: "Count",
                            data: [40, 50, 30, 10],
                            backgroundColor: ["#E74C3C", "#3498DB", "#F1C40F", "#27AE60"],
                            borderColor: ["#E74C3C", "#3498DB", "#F1C40F", "#27AE60"],
                            borderWidth: 1,
                            borderRadius: 10, // Rounded bar edges
                            barPercentage: 0.5,
                            barThickness: 6,
                            maxBarThickness: 8,
                          }
                        ],
                      };
    
                      const barChartOptions = {
                        indexAxis: "y", // Horizontal chart
                        scales: {
                          x: {
                            beginAtZero: true,
                            ticks: {
                              display: false,
                            },
                            grid: {
                              display: false,
                              drawBorder: false
                            }
                          },
                          y: {
                            beginAtZero: true,
                            grid: {
                              display: false,
                              drawBorder: false
                            }
                          }
                        },
                        plugins: {
                          datalabels: {
                            color: '#000',
                            anchor: 'end',
                            align: 'end',
                            font: {
                              weight: 'bold',
                            }
                          },
                          tooltip: {
                            callbacks: {
                              label: function (context) {
                                const dataset = context.dataset;
                                const total = dataset.data.reduce((a, b) => a + b, 0); // Sum of all data
                                const value = dataset.data[context.dataIndex]; // Current value
                                const percentage = ((value / total) * 100).toFixed(2); // Calculate percentage
                                // return `${context.label}: ${percentage}%`; // Display label and percentage
                                return [`${context.label}: ${value} (${percentage}%)`]; // Display label and percentage
                              }
                            }
                          },
                          legend: {
                            display: false, // Hide the legend
                          },
                        },
                        layout: {
                          padding: {
                            right: 20, // Add padding to the top
                          },
                        },
                        responsive: true,
                        maintainAspectRatio: false,
                        animation: { duration: 0 }
                      };

Can anyone help me with the same?

Thanks in Advance.


Solution

  • The labels on the left can be set through barChartData.labels:

    const labels = [...barChartData.labels];
    barChartData.labels = barChartData.datasets[0].data.map(v => `${v}%`);
    

    This implies changing the original code in a few places to use the "global" variable labels as the source for original labels.

    The tooltip options will require some changes:

    tooltip: {
       callbacks: {
          title: function(context){
             return labels[context[0].dataIndex];
          },
          label: function (context) {
             const dataset = context.dataset;
             const total = dataset.data.reduce((a, b) => a + b, 0); // Sum of all data
             const value = dataset.data[context.dataIndex]; // Current value
             const percentage = ((value / total) * 100).toFixed(2); // Calculate percentage
             return [`${labels[context.dataIndex]}: ${value} (${percentage}%)`]; // Display label and percentage
          }
       }
    }
    

    For the labels on top of the bars, one can use (or should I say hijack) the plugin chartjs-plugin-datalabels that, by looking at the original code, seems to be already available. The plugin options for those labels could be:

    datalabels: {
       color: '#777',
       anchor: 'start',
       align: 315,
       offset: -4,
       formatter: function(value, context) {
          return labels[context.dataIndex]
       },
       font: {
          weight: 'bold',
       }
    },
    

    The full code in a stackblitz, forked from PrimeReact playground.


    An alternative solution, if one doesn't want to mess with the labels in the original data, is to hide the y axis and show the left values as another data label, so the datalabels options would be:

    datalabels: {
       labels: {
          left:{
             anchor: 'start',
             align: 205,
             offset: -2,
             formatter: function(value){
                return `${value}%`
             },
             font: {
                size: 13
             }
          },
          top: {
             color: '#777',
             anchor: 'start',
             align: 315,
             offset: -4,
             formatter: function(value, context){
                return barChartData.labels[context.dataIndex]
             },
             font: {
                weight: 'bold',
             }
          }
       }
    }
    

    The tooltip options will be those from the original code, and a left padding has to be added. Here's the stackblitz fork with this version.