Search code examples
javascripttypescriptchartschart.js

Chartjs: How can stack the label of a different dataset on top of each bar in my bar chart?


chart.js 4.4.2 chartjs-plugin-datalabels this is the effect id like to achieve

 const chartCtr = document.querySelector('#temp-chart1') as HTMLCanvasElement;
  new Chart(chartCtr, {
    type: 'line',
    plugins: [ChartDataLabels],
    options: {
      layout: {
        padding: {
          bottom: 10.15,
        },
      },
      maintainAspectRatio: false,
      animation: false,
      plugins: {
        // zoom: {
        //   pan: {
        //     // pan options and/or events
        //     enabled: true,
        //     mode: 'x',
        //   },
        //   limits: {
        //     // axis limits
        //   },
        //   zoom: {
        //     // zoom options and/or events
        //   },
        // },
        legend: {
          display: false,
        },
      },
      scales: {
        x: {
          adapters: {
            date: {
              locale: enUS,
            },
          },
          type: 'time',
          ticks: {
            stepSize: 3,
            major: {
              enabled: true,
            },
          },
          time: {
            unit: 'hour',
            tooltipFormat: 'HH:mm',
          },
          position: 'top',
        },
        yTemp: {
          ticks: {
            display: false,
          },
          grid: {
            drawTicks: false,
          },
          border: {
            display: false,
          },
        },
        yPop: {
          display: false,
          max: getMaxValueWithPadding(),
        },
        yLev: {
          display: false,
        },
      },
    },
    data: {
      labels: forecast.map((row) => row.date),
      datasets: [
        {
          label: 'temp every 3 hrs',
          data: forecast.map((row) => row.temp),
          yAxisID: 'yTemp',
          datalabels: {
            display: false,
          },
        },
        {
          label: 'probability of preciptation',
          data: forecast.map((row) => row.pop),
          yAxisID: 'yPop',
          type: 'bar',
          datalabels: {
            anchor: 'end',
            align: 'end',
            font: {
              weight: 'bold',
            },
            formatter: (value) => `${((value as number) * 100).toFixed()}%`,
          },
        },
        {
          label: '3h rain',
          yAxisID: 'yLev',
          data: forecast.map((row) => {
            const sum = (row.rain ?? 0) + (row.snow ?? 0);
            if (sum) return sum;
            else return '';
          }),
          hidden: true,
        },
      ],
    },
  });

I'd like to get the values of the last data set ('3h rain'), sitting on each bar. I've used the datalabels plugin place the values of the 'probability of precipitation' dataset on each bar. How do I do the same for '3hrain'?

current chart


Solution

  • I figured it out! Adding my solution to help anybody, that is struggling with this. The formatter option (the datalabels plugin) accepts two arguments. value and context. The context variable has a property called dataIndex which returns the index of the value in your dataset. Leveraging that you're able to return to the relevant index of your dataset and cherrypick other the data you may be interested while working from a different dataset.

    formatter: (value, context) => {
                  const bar = forecast[context.dataIndex];
                  const sum = (bar.rain ?? 0) + (bar.snow ?? 0);
                  if (sum)
                    return `${sum} mm/h\n${((value as number) * 100).toFixed()}%`;
                  else return `${((value as number) * 100).toFixed()}%`;
                },
    

    https://chartjs-plugin-datalabels.netlify.app/guide/options.html#option-context