[Chartjs]-Changing tooltip color in Chart.js

3👍

Pretty much anytime you want to customize the look and feel of the tooltip beyond the configuration options provided by chart.js, you will have to use custom tooltips. The good thing about custom tooltips is that they are html/css based so your styling options are endless.

In this case, since you are trying to change the tooltip background color based upon the value of your data, you can simply define some css classes to handle both styling options and then implement logic in your custom tooltip function to assign the appropriate css class based upon a value.

Here is an example.

custom: function(tooltip) {
  // get the tooltip element
  var tooltipEl = document.getElementById('chartjs-tooltip');

  // create one if it does not yet exist
  if (!tooltipEl) {
    tooltipEl = document.createElement('div');
    tooltipEl.id = 'chartjs-tooltip';
    tooltipEl.innerHTML = "<table></table>"
    document.body.appendChild(tooltipEl);
  }

  // hide the tooltip and restore the cursor
  // if there isn't one to display yet
  if (tooltip.opacity === 0) {
    tooltipEl.style.opacity = 0;
    $(this._chart.canvas).css("cursor", "default");
    return;
  } else {
    // otherwise change the cursor to pointer
    $(this._chart.canvas).css("cursor", "pointer");
  }

  // clear all classes and add the correct background color
  tooltipEl.classList.remove('active', 'normal');
  if (tooltip.dataPoints[0].yLabel === 2) {
    tooltipEl.classList.add('active');
  } else {
    tooltipEl.classList.add('normal');
  }

  function getBody(bodyItem) {
    return bodyItem.lines;
  }

  // set tooltip text
  if (tooltip.body) {
    var titleLines = tooltip.title || [];
    var bodyLines = tooltip.body.map(getBody);
    var innerHtml = '<thead>';

    titleLines.forEach(function(title) {
      innerHtml += '<tr><th>' + title + '</th></tr>';
    });
    innerHtml += '</thead><tbody>';

    bodyLines.forEach(function(body, i) {
      // map the number that is going to be displayed state value
      if (tooltip.dataPoints[0].yLabel === 2) {
        body = 'Active';
      } else {
        body = 'Normal';
      }

      var colors = tooltip.labelColors[i];
      var style = 'background:' + colors.backgroundColor;
      style += '; border-color:' + colors.borderColor;
      style += '; border-width: 2px'; 
      var span = '<span class="chartjs-tooltip-key" style="' + style + '"></span>';
      innerHtml += '<tr><td>' + span + body + '</td></tr>';
    });
    innerHtml += '</tbody>';

    var tableRoot = tooltipEl.querySelector('table');
    tableRoot.innerHTML = innerHtml;
  }

  // get the position of tooltip
  var position = this._chart.canvas.getBoundingClientRect();

  // set display, position, and font styles
  tooltipEl.style.opacity = 1;
  tooltipEl.style.left = position.left + tooltip.caretX + 'px';
  tooltipEl.style.top = position.top + tooltip.caretY + 'px';
  tooltipEl.style.fontFamily = tooltip._fontFamily;
  tooltipEl.style.fontSize = tooltip.fontSize;
  tooltipEl.style.fontStyle = tooltip._fontStyle;
  tooltipEl.style.padding = tooltip.yPadding + 'px ' + tooltip.xPadding + 'px';
}

It also sounds like you want to customize the point color based upon the data value. This is actually quite simple to do and does not require using any sort of callback. You can simply pass an array of colors to the pointBackgroundColor and pointBorderColor properties where each index in the array maps to the index in your data array.

For example, if you want the first and third points to be a different color then your array might look like this [blue, red, blue, red]. You can just build your color array while you are building your chart data object (e.g. in the prepareDataForChart() function.

Here is an example of that.

// this function processess our raw data and converts
// it to a format that chart.js can understand
var prepareDataForChart = function(data) {
  var chartData = {
    data: [],
    pointColors: [],
  };

  data.forEach(function(d) {
    var yValue;
    var pointColor;

    // since we cannot use a category scale on the y-axis,
    // lets map the eventState to an arbitrary numerical value
    // and set the point color
    if (d.eventState === 'A') {
      yValue = 2;
      pointColor = chartColors.red;
    } else if (d.eventState === 'N') {
      yValue = 1;
      pointColor = chartColors.blue;
    }

    // we have to use the 'alternate' dataset format
    // in order to graph this correctly
    chartData.data.push({
      x: d.eventTime,
      y: yValue,
    });

    // add our point color to the colors array
    chartData.pointColors.push(pointColor);
  });

  return chartData;
};

Then when you create you chart just use the pointColors array that was returned by your function.

var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
  type: 'line',
  data: {
    datasets: [{
      label: "Object 1",
      fill: false,
      borderColor: chartColors.red,
      borderWidth: 2,
      backgroundColor: chartColors.white,
      pointBorderColor: chartData.pointColors,
      pointBackgroundColor: chartData.pointColors,
      pointBorderWidth: 1,
      pointHoverRadius: 5,
      pointHitRadius: 20,
      steppedLine: true,
      data: chartData.data,
    }]
  },
// ...rest of chart options...

Here is a codepen example demonstrating everything that was discussed (colored tooltips and points).

4👍

Alternatively, you can use the label Color function.

tooltips: {
     callbacks: {
       labelColor: function(tooltipItem,data) {
           if (tooltipItem.datasetIndex === 0) {
                return {
                    borderColor: "#FFFFFF",
                    backgroundColor: "#FFCD2E"
                        };
                 }

Leave a comment