Search code examples
vue.jsvuejs3chart.jslinechartvue-chartjs

Why isn't the 'labelColor' callback for the Chart.js Tooltip applying any changes?


I'm using vue-chartjs to display a line chart, and right now I'm customizing the appearance. I'm finding that certain attributes to style the Tooltip are not working. I'm currently trying the following approach to select a background color based on the value of the data. I've copied the code straight from the Chart.js documentation and put in my ternary operator to select a background color.

const options = {
        elements: {
          line: {
            borderColor: '#15c63c',
            borderCapStyle: 'round',
          },
        },
        scales: {
          y: {
            suggestedMin: 0,
            grid: {
              display: false,
              color: 'rgba(150,150,150,.3)',
            },
          },
          x: {
            grid: {
              color: 'rgba(150,150,150,0.1)',
            },
          },
        },
        responsive: true,
        plugins: {
          legend: {
            display: false,
          },
          title: {
            display: true,
            text: 'April 2024',
          },
          tooltip: {
            backgroundColor: 'rgba(225,225,225,0.75)',
            displayColors: false,
            padding: 12,
            titleAlign: 'center',
            caretPadding: 4,
            callbacks: {
              label: function (context) {
                let label = context.dataset.label || ''

                if (context.parsed.y !== null && context.parsed.y >= 0) {
                  const suffix = context.parsed.y === 1 ? '' : 's'
                  label += '+' + context.parsed.y + ' unit' + suffix
                }

                return label
              },
              labelColor: function(context) {
                let backgroundColor = context.parsed.y >= 0 ? 'rgba(21,198,60,0.7)' : 'rgba(204,0,0,0.7)'
                return {
                  borderColor: 'rgb(255,253,250)',
                  backgroundColor: backgroundColor,
                  borderWidth: 2,
                  borderDash: [2, 2],
                  borderRadius: 8,
                }
              },
              labelTextColor: function () {
                return 'rgb(255,253,250)'
              },
            },
          },
        },
        maintainAspectRatio: false,
      }

If I remove the options.plugins.tooltip.backgroundColor, then the tooltip uses the default values. The 'labelTextColor' callback works as intended. I've also noticed that no matter what I do, I can't change the borderColor of the tooltip. I've tried options.plugins.tooltip.borderColor = 'rgb(255,253,250)' but that doesn't work either.

I've also done console.log(context.parsed.y) within the labelColor callback and confirmed that the rgb values are showing up in the console.

I've tried looking on SO, as well as the GH but everything I've found seems to be from 4 or 6 years ago and is no longer relevant.


Solution

  • @kikon provided the roadmap for the answer. The labelColor callback was trying to style an element I was wanting hidden. I moved all border settings up to the top level of the tooltip object. Then using @kikon's fiddle example I did an afterBody callback to dynamically set the backgroundColor of the tooltip.

    tooltip: {
                backgroundColor: 'rgba(225,225,225,0.75)',
                borderWidth: 2,
                borderColor: 'rgb(255,253,250)',
                displayColors: false,
                padding: 12,
                titleAlign: 'center',
                caretPadding: 4,
                callbacks: {
                  label: context => {
                    let label = context.dataset.label || ''
    
                    if (context.parsed.y !== null && context.parsed.y >= 0) {
                      label += '+' + context.parsed.y
                    }
    
                    const suffix = context.parsed.y === 1 ? '' : 's'
                    label += ' unit' + suffix
    
                    return label
                  },
                  labelTextColor: () => {
                    return 'rgb(255,253,250)'
                  },
                  afterBody: context => {
                    const backgroundColor = context[0].parsed.y >= 0 ? 'rgba(21,198,60,0.7)' : 'rgba(204,0,0,0.7)'
                    context[0].chart.tooltip.options.backgroundColor = backgroundColor
                  },
                },
              }