Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Chart js different background for y axis

I have a line chart in chart js. I want to give it a different background on the y axis say, 0-40 is red,40-70 is yellow and 70-100 is green. The limit for the y axis will always be 100.

   var scatterChart = new Chart(ctx, {
    type: 'line',
    data: {
        datasets: [{
            label: ' Dataset',
            data: [{
                x: 1,
                y: 10
            }, {
                x: 2,
                y: 50
            }, {
                x: 3,
                y: 88
            }, {
                x: 4,
                y: 5
            }]
        }]
    },
    options: {
        scales: {
            xAxes: [{
                type: 'linear',
                position: 'bottom'
            }]
        }
    }
});

How do i set the background?

like image 1000
sea Avatar asked May 19 '17 08:05

sea


Video Answer


2 Answers

There is not a built in option, but we can achieve the result with some code.

var ctx = document.getElementById("chart").getContext("2d");

var scatterChart = new Chart(ctx, {
  type: "line",
  data: {
    datasets: [{
      label: " Dataset",
      data: [{
          x: 1,
          y: 10
        },
        {
          x: 2,
          y: 50
        },
        {
          x: 3,
          y: 88
        },
        {
          x: 4,
          y: 5
        }
      ]
    }]
  },
  options: {
    backgroundRules: [{
        backgroundColor: "red",
        yAxisSegement: 40
      },
      {
        backgroundColor: "yellow",
        yAxisSegement: 70
      },
      {
        backgroundColor: "green",
        yAxisSegement: Infinity
      }
    ],
    scales: {
      xAxes: [{
        type: "linear",
        position: "bottom"
      }],
      yAxes: [{
        color: ["#123456", "#234567"]
      }]
    }
  },
  plugins: [{
    beforeDraw: function(chart) {
      var ctx = chart.chart.ctx;
      var ruleIndex = 0;
      var rules = chart.chart.options.backgroundRules;
      var yaxis = chart.chart.scales["y-axis-0"];
      var xaxis = chart.chart.scales["x-axis-0"];
      var partPercentage = 1 / (yaxis.ticksAsNumbers.length - 1);
      for (var i = yaxis.ticksAsNumbers.length - 1; i > 0; i--) {
        if (yaxis.ticksAsNumbers[i] < rules[ruleIndex].yAxisSegement) {
          ctx.fillStyle = rules[ruleIndex].backgroundColor;
          ctx.fillRect(xaxis.left, yaxis.top + (i - 1) * (yaxis.height * partPercentage), xaxis.width, yaxis.height * partPercentage);
        } else {
          ruleIndex++;
          i++;
        }
      }
    }
  }]
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.bundle.js"></script>
<div class="container">
  <canvas id="chart"></canvas>
</div>
like image 138
Daniele Ricci Avatar answered Sep 22 '22 07:09

Daniele Ricci


Let me present a generic approach that works with any such chart aslong as its dataset contains zero or positive values only.

The background colors together with the upper values can simply be defined inside the dataset as follows:

bgColors: [
  { color: 'red', upTo: 40 },
  { color: 'yellow', upTo: 70 }, 
  { color: 'green', upTo: 100 }
]

Then you could extend an existing line chart (i.e. 'lineDiffBgColors') and overwrite its update function. In there, you would create a linear CanvasGradient and add color stops that correspond to the definitions of bgColors mentioned above. At the end, the linear gradient needs to be assigned to the backgroundColor option of your dataset.

this.chart.data.datasets[0].backgroundColor = gradient;

Please have a look at your enhanced code below.

Chart.defaults.lineDiffBgColors = Chart.defaults.line;
Chart.controllers.lineDiffBgColors = Chart.controllers.line.extend({
  update: function(reset) {
    var yAxis = this.chart.scales['y-axis-0'];
    var bgColors = this.chart.data.datasets[0].bgColors.slice().reverse();
    var max = Math.max.apply(null, bgColors.map(o => o.upTo));
    var min = yAxis.getValueForPixel(yAxis.bottom);
    var yTop = yAxis.getPixelForValue(max);
    var gradient = this.chart.chart.ctx.createLinearGradient(0, yTop, 0, yAxis.bottom);
    let offset = 0;
    bgColors.forEach((bgc, i) => {
      gradient.addColorStop(offset, bgc.color);
      if (i + 1 == bgColors.length) {
        offset = 1;
      } else {         
        offset = (max - bgColors[i + 1].upTo) / (max - min);
      }
      gradient.addColorStop(offset, bgc.color);
    });
    this.chart.data.datasets[0].backgroundColor = gradient;
    return Chart.controllers.line.prototype.update.apply(this, arguments);
  }
});

new Chart('myChart', {
  type: 'lineDiffBgColors',
  data: {
    datasets: [{
      label: 'Dataset',
      data: [
        { x: 1, y: 10 }, 
        { x: 2, y: 50 }, 
        { x: 3, y: 88 }, 
        { x: 4, y: 5 }
      ],
      bgColors: [
        { color: 'red', upTo: 40 },
        { color: 'yellow', upTo: 70 }, 
        { color: 'green', upTo: 100 }
      ]
    }]
  },
  options: {
    scales: {
      xAxes: [{
        type: 'linear'
      }]
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.js"></script>
<canvas id="myChart" height="100"></canvas>

In case you prefer kind of smooth gradient, you could change the bgColors.forEach loop inside the update function as follows.

bgColors.forEach((bgc, i) => {    
  gradient.addColorStop(offset == 0 ? 0 : offset + 0.05, bgc.color);
  if (i + 1 == bgColors.length) {
    offset = 1;
  } else {         
    offset = (max - bgColors[i + 1].upTo) / (max - min);
  }
  gradient.addColorStop(offset == 1 ? 1 : offset - 0.05, bgc.color);
});
like image 22
uminder Avatar answered Sep 23 '22 07:09

uminder