3

Using chart.js 2.6 Is there a way to dynamically change the bars in my chart for values above zero and below zero? The graph series data is being generated via a call to a method. Right now its just a random number generator but will be a DB call.

function changeWOWData(chart) {
    var datasets = chart.data.datasets;
    var labelLen = chart.data.labels.length;
    if (datasets[0]) {
        for (i = 0, len = datasets.length; i < len; i++) {
            try {
                for (j = 0, len = labelLen; j < len; j++) {
                    datasets[i].data[j] = getRandomInt(-100, 100);
                }

            } catch (e) {
                console.log(e.message);
            }
        }
    }
}

Chart looks like this:

enter image description here

I want the chart bars above zero to be blue, the bars below zero to be red.

Any/all replies appreciated. Thanks in advance!

Griff

** Edit ** Added the code from the answer below as such:

var myBarChart = new Chart(wowChart, {
    type: 'bar',
    data: wowData,
    plugins: [{
        beforeDraw: function (c) {
            var data = c.data.datasets[0].data;
            for (var i in data) {
                try {
                    var bar = c.data.datasets[0]._meta[0].data[i]._model;
                    if (data[i] > 0) {
                        bar.backgroundColor = '#07C';
                    } else bar.backgroundColor = '#E82020';

                } catch (ex) {
                    console.log(ex.message);
                }
                console.log(data[i]);
            }
        }
    }],
    options: wowOptions
});

Every other line of the console I see the data element along with the exception

enter image description here

Griff
  • 1,796
  • 3
  • 23
  • 48

2 Answers2

4

You could accomplish that using the following chart plugin :

plugins: [{
   beforeDraw: function(c) {
      var data = c.data.datasets[0].data;
      for (let i in data) {
         let bar = c.data.datasets[0]._meta['0'].data[i]._model;
         if (data[i] > 0) {
            bar.backgroundColor = '#07C';
         } else bar.backgroundColor = '#E82020';
      }
   }
}]

add this followed by your chart options

ᴅᴇᴍᴏ

var ctx = document.getElementById("canvas").getContext('2d');
var myChart = new Chart(ctx, {
   type: 'bar',
   data: {
      labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'],
      datasets: [{
         label: 'LEGEND',
         data: [9, 14, -4, 15, -8, 10]
      }]
   },
   options: {},
   plugins: [{
      beforeDraw: function(c) {
         var data = c.data.datasets[0].data;
         for (let i in data) {
            let bar = c.data.datasets[0]._meta['0'].data[i]._model;
            if (data[i] > 0) {
               bar.backgroundColor = '#07C';
            } else bar.backgroundColor = '#E82020';
         }
      }
   }]
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.6.0/Chart.min.js"></script>
<canvas id="canvas" height="180"></canvas>
ɢʀᴜɴᴛ
  • 32,025
  • 15
  • 116
  • 110
  • No question you answered the question, the code in the example runs and that is the exact thing I am trying to do. Awesome! But I get TypeError on this line: var bar = c.data.datasets[0]._meta[0].data[i]._model; I think it may have something to do with the callback. If I wrap the code in a try catch block and add a console.log file it prints the err message between each data item. – Griff Jun 16 '17 at 19:17
  • um.. how you get type error? check your code carefully for any typos. as you can see the code runs perfectly on the snippet and it should also work for you w/o throwing any error. – ɢʀᴜɴᴛ Jun 16 '17 at 19:22
  • g aand, please see my complete code in the edit. Can you see anything wrong with it? – Griff Jun 16 '17 at 19:33
  • strange. I wonder what else can be going on. The code from the JSFidlle throws an exception as shown in the edit above and doesn't color the bars. Bummer. Thanks for the help. – Griff Jun 16 '17 at 19:46
  • 2
    actually, you cannot get `_meta[0]` since it's an object with a single property (some random number) so you need to get it from the keys: `var model = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._model` (see comment from @IrishDubGuy from https://stackoverflow.com/a/37550150/3480671) – bosch Jul 15 '17 at 20:48
  • @bosch Good catch! Haven't noticed that earlier, since this worked fine even w/o that *(atleast for me)*. – ɢʀᴜɴᴛ Jul 25 '17 at 06:45
1

in chartjs v3 you can use Simply scriptable option example:

    datasets: [
          {
            data: this.chartData,
            backgroundColor(context) {
              const index = context.dataIndex
              const value = context.dataset.data[index]
              return value < 0 ? 'red' : 'blue'
            }
          }
        ]

visit https://www.chartjs.org/docs/latest/general/options.html#scriptable-options

Saman
  • 41
  • 3