[Chartjs]-How do I change the colour of a Chart.js line when drawn above/below an arbitary value?

3👍

The Plugin Core API offers a range of hooks that may be used for performing custom code. You can use the afterLayout hook for creating a linear gradients considering the specified threshold. Then you’ll have to assign it to the borderColor property of the dataset.

Please take a look at the runnable code below and see hot it works.

const threshold = 25;

new Chart('myChart', {
  type: 'line',
  plugins: [{
    afterLayout: chart => {
      let ctx = chart.chart.ctx;
      ctx.save();
      let yAxis = chart.scales["y-axis-0"];
      let yThreshold = yAxis.getPixelForValue(threshold);          
      let gradient = ctx.createLinearGradient(0, yAxis.top, 0, yAxis.bottom);   
      gradient.addColorStop(0, 'green'); 
      let offset = 1 / yAxis.bottom * yThreshold; 
      gradient.addColorStop(offset, 'green'); 
      gradient.addColorStop(offset, 'red'); 
      gradient.addColorStop(1, 'red');           
      chart.data.datasets[0].borderColor = gradient;
      ctx.restore();
    }
  }],
  data: {
    labels: ['A', 'B', 'C', 'D', 'E', 'F', 'G'],
    datasets: [{
      label: 'My Dataset',
      data: [32, 44, 29, 33, 18, 15, 30],
      fill: false
    }]
  },
  options: {
    legend: {
      display: false
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.min.js"></script>
<canvas id="myChart" height="100"></canvas>

1👍

To make a graph with two bounds (one upper and one lower) as below, proceed as follows:

1. Set the thresholds

let yThresholdMax = yAxis.getPixelForValue(YOUR_MAX_THRESHOLD);  
let yThresholdMin = yAxis.getPixelForValue(YOUR_MIN_THRESHOLD);  

2. Create offsets

let offsetMax = 1 / yAxis.bottom * yThresholdMax; 
let offsetMin= 1 / yAxis.bottom * yThresholdMin; 

3. Instantiate the gradient

let gradient = ctx.createLinearGradient(0, yAxis.top, 0, yAxis.bottom);

4. Choose colours for each layer (from top to bottom)

//colour of the highest value of the chart
gradient.addColorStop(0, 'red');

//colour at the upper limit 
gradient.addColorStop(offsetMax, 'darkred'); 

//colour from the upper limit to the lower limit
gradient.addColorStop(offsetMax, 'blue'); 
gradient.addColorStop(offsetMin, 'blue');

//colour at the lower limit 
gradient.addColorStop(offsetMin,'darkred');
//colour at the lowest value of the chart
gradient.addColorStop(1,"red");    
  1. Attribute gradient to the line
chart.data.datasets[0].borderColor = gradient;  

Complete code :

var myLineChart = new Chart(ctx, {
  type: 'line',
  plugins: [{
    afterLayout: chart => {
      let ctx = chart.chart.ctx;
      ctx.save();
      let yAxis = chart.scales["y-axis-0"];
      let yThresholdMax = yAxis.getPixelForValue(data.limits.max);  
      let yThresholdMin = yAxis.getPixelForValue(data.limits.min);  

      let offsetMax = 1 / yAxis.bottom * yThresholdMax; 
      let offsetMin= 1 / yAxis.bottom * yThresholdMin; 

      let gradient = ctx.createLinearGradient(0, yAxis.top, 0, yAxis.bottom);   
      
      gradient.addColorStop(0, 'red'); 
      gradient.addColorStop(offsetMax, 'darkred'); 
      gradient.addColorStop(offsetMax, 'blue'); 
      gradient.addColorStop(offsetMin, 'blue');
      gradient.addColorStop(offsetMin,'darkred');
      gradient.addColorStop(1,"red");           
      chart.data.datasets[0].borderColor = gradient;    
      ctx.restore();
    }
  }],
  // The data for our dataset
  data: {
      ......
  },
    options: {
    ........
   }
});

1👍

There’s a small issue with the other answers, the normalization is incorrect.
This line

let offset = 1 / yAxis.bottom * yThreshold;

It should be (Min-max normalization)

let offset = (yThreshold - yAxis.top) / (yAxis.bottom - yAxis.top);

Modifying uminder’s code, now you can see the color changes exactly at 25

const threshold = 25;

new Chart('myChart', {
  type: 'line',
  plugins: [{
    afterLayout: chart => {
      let ctx = chart.ctx;
      ctx.save();
      let yAxis = chart.scales.y;
      let yThreshold = yAxis.getPixelForValue(threshold);
      let gradient = ctx.createLinearGradient(0, yAxis.top, 0, yAxis.bottom);
      gradient.addColorStop(0, 'green');
      let offset = (yThreshold - yAxis.top) / (yAxis.bottom - yAxis.top);
      gradient.addColorStop(offset, 'green');
      gradient.addColorStop(offset, 'red');
      gradient.addColorStop(1, 'red');
      chart.data.datasets[0].borderColor = gradient;
      ctx.restore();
    }
  }],
  data: {
    labels: ['A', 'B', 'C', 'D', 'E', 'F', 'G'],
    datasets: [{
      label: 'My Dataset',
      data: [32, 44, 29, 33, 18, 15, 30],
      fill: false,
      lineTension: 0.2
    }]
  },
  options: {
    plugins: {
      legend: {
        display: false
      }
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.1/chart.min.js"></script>
<canvas id="myChart" height="80"></canvas>

Leave a comment