How can I set different colours for each bar in an

2019-02-12 08:24发布

I've looked at How to change colours for Angular-Chart.js, but it relates to colours for an entire (dataset), not a specific bar.

What I'm looking for is a way to apply Different color for each bar in a bar chart; ChartJS to Angular.

So, I've got a bar chart:

<canvas id="locationBar" class="chart chart-bar" data="chartParams.votes" labels="chartParams.listOfLocations" series="chartParams.series" colours="chartParams.colours" options="chartParams.options"></canvas> 

With the following angular code (in a controller of course)

$scope.chartParams = {
    listOfLocations: ['Trenzalore','Earth','Caprica','Sol','Tau Ceti'],
    votes: [[5,10,6,7,2]],
    series: ["Nice Places"],
    colours: [{fillColor:getRandomColour()}],
    options: {barShowStroke : false}
};

where getRandomColour() would return a random colour.

Right now, the colours field applies this colour to all the bars:

same colour :( different colours

when I actually want a different colour for each bar:

Plunker

3条回答
smile是对你的礼貌
2楼-- · 2019-02-12 09:05

Using the latest version of angular-chart.js, here's an example that changes the colours based on a condition, without modifying the library itself. Instead, it uses the chart-dataset-override feature.

The trick is to use a series with only one data set.

HTML

<div ng-controller="chartControl">
  <canvas id="bar" class="chart chart-bar" 
    chart-data="goal.data" 
    chart-labels="goal.labels" 
    chart-options="goal.options" 
    chart-series="goal.series" 
    chart-dataset-override="goal.datasetOverride"></canvas>
</div>

JavaScript

Add the following code to the controller:

  var exceeded = '#27ae60';
  var achieved = '#bdc3c7';
  var defeated = '#e74c3c';

  $scope.goal = [];
  $scope.goal.goal = 3;

  $scope.goal.series = [ 'Visits' ];
  $scope.goal.labels = [
    'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep'
  ];
  $scope.goal.data = [
    [5, 2, 3, 3, 3, 4, 2, 3, 4],
  ];

  var backgroundColours = [];

  // Assign the background colour based on whether the goal was achieved.
  for( var i = 0; i < $scope.goal.data[0].length; i++ ) {
    var v = $scope.goal.data[0][i];

    if( v > $scope.goal.goal ) {
      backgroundColours[i] = exceeded;
    }
    else if( v < $scope.goal.goal ) {
      backgroundColours[i] = defeated;
    }
    else {
      backgroundColours[i] = achieved;
    }
  } 

  // Create a place to hold the background colours.
  $scope.goal.datasetOverride = [{ backgroundColor: [] }];

  // Assign the colours to the pre-populated array.
  $scope.goal.datasetOverride[0].backgroundColor = backgroundColours;

  $scope.goal.options = {
    barShowStroke: false,
    scales: {
      yAxes: [{
        ticks: {
          min: 0,
          max: 7,
          stepSize: 1
        }
      }]
    }
  };

Output

Produces:

Chart Output

Related Links

查看更多
何必那么认真
3楼-- · 2019-02-12 09:15

Plunker Demo

The easiest thing to do was to modify the chart.js source file to accept an array of colors for fillColor rather than a single color string.

If you could get one of the other proposed solutions working, I think it would end up having to be done in a very un-angular way.

Some people may not like tweaking the source, but for how simple and easy it was to do, and it achieves the desired result, and it isn't any less 'angular' in it's solution...let's just call it an improvement to chart.js.

Note that I only modified the "bar" chart to accept an array of colors, because it seems chart.js references the fillColor separately in each chart type. So you should be able to make this modification to work for any of the charts types.

The place you need to modify:

            helpers.each(dataset.data,function(dataPoint,index){
                //Add a new point for each piece of data, passing any required data to draw.
                datasetObject.bars.push(new this.BarClass({
                    value : dataPoint,
                    label : data.labels[index],
                    datasetLabel: dataset.label,
                    strokeColor : dataset.strokeColor,
                    fillColor : dataset.fillColor[index],   // <- added [index] here
                    highlightFill : dataset.highlightFill || dataset.fillColor,
                    highlightStroke : dataset.highlightStroke || dataset.strokeColor
                }));
            },this);

This block of code can be found in the Chart.type.extend function for the bar chart. Just look for this:

Chart.Type.extend({
        name: "Bar",

and look further down inside that function for the place where it pushes the fillColor to the datasetObject.bars.

Now just set up your chart like before, except feed it an array for fillColor:

function($scope){
          $scope.chartParams = {
        listOfLocations: ['Trenzalore','Earth','Caprica','Sol','Tau Ceti'],
        votes: [[5,10,6,7,2]],
        series: ["Nice Places"],
        colours: [{fillColor:["#FF0000", "#00FF00", "#0000FF", "#00FFFF", "#FFFF00"]}],
        options: {barShowStroke : false}
      };
        }
查看更多
霸刀☆藐视天下
4楼-- · 2019-02-12 09:18

One of the bigger problems with Chart libraries is that sooner or later you hit a wall, which can only be breached by hacking or extending the library. Knowing you hit that wall and what to could be the answer to this question.

Even though you can create a custom chart.js graph you could also solve it with d3.js. I've taken one of the basic angular d3.js barchart examples and added the behavior you want:

var colors = d3.scale.category10();

// ...

bars.enter().append('rect')
    .classed('bar', true)
    .attr({x: chartW,
           width: barW,
           y: function(d, i) { return y1(d); },
           height: function(d, i) { return chartH - y1(d); },
           fill: function(d,i) { return colors(i) }
    })
// ...

http://plnkr.co/edit/9RCYAPCEj9iRsxkkYPaV?p=preview

Customizing a chart in any way, like changing fill, stroke or anything else is within reach. It is of cause still though a lot more code, but if you want to customize beyond library support, it is always a lot more code.

查看更多
登录 后发表回答