Chart.js: Bar Chart - Custom Label Colors

Created on 27 May 2016  路  6Comments  路  Source: chartjs/Chart.js

Hi,
as you can see in the image below and in this example on codepen, i can't find a way to customize label's background colors, when there are more colors for bars.
example

Function generateLabels use "dataset.backgroundColor", that in my case is an Array.

generateLabels: function(chart) {
    var data = chart.data;
    return helpers.isArray(data.datasets) ? data.datasets.map(function(dataset, i) {
        return {
            text: dataset.label,
            fillStyle: dataset.backgroundColor,
            hidden: !chart.isDatasetVisible(i),
            lineCap: dataset.borderCapStyle,
            lineDash: dataset.borderDash,
            lineDashOffset: dataset.borderDashOffset,
            lineJoin: dataset.borderJoinStyle,
            lineWidth: dataset.borderWidth,
            strokeStyle: dataset.borderColor,
            // Below is extra data used for toggling the datasets
            datasetIndex: i
        };
    }, this) : [];

Then, in draw() function, "fillStyle" property is used as value for ctx.fillStyle
ctx.fillStyle = itemOrDefault(legendItem.fillStyle, Chart.defaults.global.defaultColor);
But it can be only strings, CanvasGradients, or CanvasPatterns.

Is there any other way to customize label's rect background?

enhancement

Most helpful comment

Unless I've misread, I think I've hit the same scenario; wanting to effectively create an "active" state on the data sets for one of the elements.

I achieved this, by first giving the "active" element a different backgroundColor on the data set. This only got me as far as the above issue - causing the legend fillStyle to be naively populated by the first rgb string in the backgroundColor array (inside dataset).

To get around this, I wrapped the default generateLabels function, and applied the specific fillStyle afterwards. Example below using a male and female dataset:

var MALE_BAR_COLOUR = 'rgba(0, 51, 78, 0.3)';
var MALE_BAR_ACTIVE_COLOUR = 'rgba(0, 51, 78, 1)';
var FEMALE_BAR_COLOUR = 'rgba(248, 142, 40, 0.3)';
var FEMALE_BAR_ACTIVE_COLOUR = 'rgba(248, 142, 40, 1)';

var ctx = $("#myChart");
var myChart = new Chart(ctx, {
  type: 'bar',
  data: {
    datasets: [{
      label: 'Male',
      data: [0, 0, 0, 0, 0],
      backgroundColor: MALE_BAR_COLOUR
    }, {
      label: 'Female',
      data: [0, 0, 0, 0, 0],
      backgroundColor: FEMALE_BAR_COLOUR
    }]
  },
  options: {
    legend: {
      labels: {
        generateLabels: function(chart) {
          labels = Chart.defaults.global.legend.labels.generateLabels(chart);
          labels[0].fillStyle = MALE_BAR_ACTIVE_COLOUR;
          labels[1].fillStyle = FEMALE_BAR_ACTIVE_COLOUR;
          return labels;
        }
      }
    }
  }
});

// Another block of code will update the dataset backgroundColor for the "active" element to X_BAR_ACTIVE_COLOUR

Hope this helps someone else.

All 6 comments

There is no other way to customize it. You might be able to create a canvas pattern of the exact image you wanted and that would work

@etimberg this same example renders labels in darkgrey when browser is Firefox or Safari.
I can't reproduce this in IE for now.

Unless I've misread, I think I've hit the same scenario; wanting to effectively create an "active" state on the data sets for one of the elements.

I achieved this, by first giving the "active" element a different backgroundColor on the data set. This only got me as far as the above issue - causing the legend fillStyle to be naively populated by the first rgb string in the backgroundColor array (inside dataset).

To get around this, I wrapped the default generateLabels function, and applied the specific fillStyle afterwards. Example below using a male and female dataset:

var MALE_BAR_COLOUR = 'rgba(0, 51, 78, 0.3)';
var MALE_BAR_ACTIVE_COLOUR = 'rgba(0, 51, 78, 1)';
var FEMALE_BAR_COLOUR = 'rgba(248, 142, 40, 0.3)';
var FEMALE_BAR_ACTIVE_COLOUR = 'rgba(248, 142, 40, 1)';

var ctx = $("#myChart");
var myChart = new Chart(ctx, {
  type: 'bar',
  data: {
    datasets: [{
      label: 'Male',
      data: [0, 0, 0, 0, 0],
      backgroundColor: MALE_BAR_COLOUR
    }, {
      label: 'Female',
      data: [0, 0, 0, 0, 0],
      backgroundColor: FEMALE_BAR_COLOUR
    }]
  },
  options: {
    legend: {
      labels: {
        generateLabels: function(chart) {
          labels = Chart.defaults.global.legend.labels.generateLabels(chart);
          labels[0].fillStyle = MALE_BAR_ACTIVE_COLOUR;
          labels[1].fillStyle = FEMALE_BAR_ACTIVE_COLOUR;
          return labels;
        }
      }
    }
  }
});

// Another block of code will update the dataset backgroundColor for the "active" element to X_BAR_ACTIVE_COLOUR

Hope this helps someone else.

Thanks cabdesigns - you just solved a similar problem to the one I was having.

My problem was that I wanted to highlight some of my dataset elements, however the legend labels always inherit the first colour specified in the dataset. So if I cannot highlight element 1 it will affect the legend colour too, even if all of the other elements are a different colour.

I wanted a solution where the legend colour was consistent regardless of the colour of the elements. Your code achieves this for me.

So, thank you :-)

@cabdesigns has the best solution to this. The interface of the items returned from generateLabels is in the docs under a heading of 'Legend Item Interface'

@cabdesigns : it is working. Thanks 馃憤

Was this page helpful?
0 / 5 - 0 ratings