Using chart.js 4.4.2 how to add items to the canvas along with the chart being created?

58 Views Asked by At

I am trying to recreate a chart.js pie chart using the latest version of chart.js. The image below is how I'm trying to get the additional labels to show around the chart, as you can see from the image below, each of the data points has a legend label with an indication line using the colour of the segment it belongs to.

enter image description here

I currently have a js fiddle with the code in and can get the labels to show on the canvas, but I don't know where to start with getting the lines to start at the right point of the pie chart and to get to the correct label.

The code I have provided in the JS fiddle can be found here - this has the labels being created on the canvas, I have added the segment's colour as a box around the label but with smaller data the labels/ boxes start to overlap on the canvas.: https://jsfiddle.net/r6aykL5v/102/

const ctx = document.getElementById('BookingDurationChart');
if (ctx !== null) {
  // debugger;
  //var ChartData = document.getElementById('cWeb_Report_BookingData').value;
  const SliceLabel = {
    id: 'SliceLabel',
    beforeDatasetsDraw(chart, args, plugins) {
      const {
        ctx,
        data
      } = chart;
      var startpoint = -40;
      var outerRadiusAdd = 100;

      chart.getDatasetMeta(0).data.forEach((dataPoint, index) => {
        ctx.save();

        const xCenter = chart.getDatasetMeta(0).data[index].x;
        const yCenter = chart.getDatasetMeta(0).data[index].y;
        const startAngle = chart.getDatasetMeta(0).data[index].startAngle;
        const endAngle = chart.getDatasetMeta(0).data[index].endAngle;
        const centerAngle = (startAngle + endAngle) / 2;
        const outerRadius = chart.getDatasetMeta(0).data[index].outerRadius + outerRadiusAdd;
        const xCoordinate = startpoint + outerRadius * Math.cos(centerAngle);
        const yCoordinate = startpoint + outerRadius * Math.sin(centerAngle);

        ctx.font = '14px sans-serif';
        const textWidth = ctx.measureText(data.labels[index]).width + 10;
        const centerWidth = textWidth / 2;

        ctx.beginPath();
        ctx.translate(xCenter, yCenter);
        //ctx.fillStyle = data.datasets[0].backgroundColor[index];
        //ctx.roundRect(xCoordinate, yCoordinate, textWidth, 30, 10);
        ctx.fill();

        ctx.fillStyle = 'black';
        ctx.textAlign = 'center';
        ctx.textBaseline = 'middle';
        ctx.fillText(data.labels[index], xCoordinate + centerWidth, yCoordinate + 15);

        ctx.restore();
        startpoint = (startpoint + 10)
        outerRadiusAdd = (outerRadiusAdd - 15)
      });
    }
  }

  /*
  var ChartData = {
      title: "Booking duration between 01/06/2023 and 31/12/2024",
      labels: ["0 - 6 days", "7 - 13 days", "14 - 20 days", "21 - 27 days", "28 - 34 days"],
      datasets: [{
          data: [4130, 964, 98, 27, 61], // actual data
          //data: [4130, 964, 980, 270, 610], // altered data
          backgroundColor: ["#82B6EB", "#434348", "#94EE7E", "#F3A15E", "#8385E8"],
          percentLabels: ["78.22%", "18.26%", "1.86%", "0.51%", "1.16%"],
          databooking: ["(4130 bookings)", "(964 bookings)", "(98 bookings)", "(27 bookings)", "(61 bookings)"]
      }],
      hoverOffset: 40
  }
  */

  ChartData = JSON.parse(ChartData);
  chartTitle = ChartData.title;

  myChart = new Chart(ctx, {
    type: 'pie',
    data: ChartData,
    plugins: [SliceLabel],
    options: {
      maintainAspectRatio: true,
      responsive: true,
      //layout: {
      //padding: {
      //top: 50,
      //bottom: 50
      //}
      //},
      animation: {
        duration: 1000,
      },
      plugins: {
        datalabels: {
          display: false,
        },
        legend: {
          padding: {
            top: 100
          },
          display: true,
          position: 'bottom',
        },
        title: {
          display: true,
          text: chartTitle,
          position: 'top',
          align: 'centre',
          padding: {
            bottom: 125
          },
          font: {
            weight: 300,
            size: '22'
          }
        },
        zoom: {
          pan: {
            enabled: false,
            mode: 'x'
          },
          zoom: {
            wheel: {
              enabled: false,
            },
            mode: 'x'
          }
        },
        tooltip: {
          enabled: true,
          titleFont: {
            size: 14
          },
          bodyFont: {
            size: 14
          },
          callbacks: {
            title: function(ctx) {
              return ctx[0].label;
            },
            label: function(ctx) {
              return ctx.dataset.percentLabels[ctx.dataIndex]
            },
            afterLabel: function(ctx) {
              return ctx.dataset.databooking[ctx.dataIndex]
            },
          }
        }
      }
    }
  });
}
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/chart.js/dist/chart.umd.min.js"></script>

<div id="bookingDuration_Chart">

  <canvas id="BookingDurationChart" style="width:1700px; max-height: 750px;"></canvas>
</div>
0

There are 0 best solutions below