[Chartjs]-Gradient line chart with ChartJS

6πŸ‘

βœ…

It is somehow doable. A simple approach presented below assumes one dataset only (it should be easy to extend the approach for handling more datasets, though). The idea is as follows. We will create a plugin that will override the beforeUpdate method (which is called at the start of every update). At the start of every update, the exact Y pixels of the min and max values of the dataset are calculated. A vertical linear gradient is then created from the context of the canvas using createLinearGradient, with a kind of red for the Y pixel that corresponds to the min value of the dataset and a jazzy kind of blue for the Y pixel that corresponds to the max value of the dataset. Look at the commented code for more information. There may be some glitches regarding hovering over points and legend coloring, which I am not very keen on looking into. A working fiddle is here and the code is also available below.

var gradientLinePlugin = {
  // Called at start of update.
  beforeUpdate: function(chartInstance) {
    if (chartInstance.options.linearGradientLine) {
      // The context, needed for the creation of the linear gradient.
      var ctx = chartInstance.chart.ctx;
      // The first (and, assuming, only) dataset.
      var dataset = chartInstance.data.datasets[0];
      // Calculate min and max values of the dataset.
      var minValue = Number.MAX_VALUE;
      var maxValue = Number.MIN_VALUE;
      for (var i = 0; i < dataset.data.length; ++i) {
        if (minValue > dataset.data[i])
          minValue = dataset.data[i];
        if (maxValue < dataset.data[i])
          maxValue = dataset.data[i];
      }
      // Calculate Y pixels for min and max values.
      var yAxis = chartInstance.scales['y-axis-0'];
      var minValueYPixel = yAxis.getPixelForValue(minValue);
      var maxValueYPixel = yAxis.getPixelForValue(maxValue);
      // Create the gradient.
      var gradient = ctx.createLinearGradient(0, minValueYPixel, 0, maxValueYPixel);
      // A kind of red for min.
      gradient.addColorStop(0, 'rgba(231, 18, 143, 1.0)');
      // A kind of blue for max.
      gradient.addColorStop(1, 'rgba(0, 173, 238, 1.0)');
      // Assign the gradient to the dataset's border color.
      dataset.borderColor = gradient;
      // Uncomment this for some effects, especially together with commenting the `fill: false` option below.
      // dataset.backgroundColor = gradient;
    }
  }
};

Chart.pluginService.register(gradientLinePlugin);

var ctx = document.getElementById("myChart");

var myChart = new Chart(ctx, {
  type: 'line',
  data: {
    labels: ["First", "Second", "Third", "Fourth", "Fifth"],
    datasets: [{
      label: 'My Sample Dataset',
      data: [20, 30, 50, 10, 40],
      // No curves.
      tension: 0,
      // No fill under the line.
      fill: false
    }],
  },
  options: {
    // Option for coloring the line with a gradient.
    linearGradientLine: true,
    scales: {
      yAxes: [{
        ticks: {
          min: 0,
          max: 100,
          stepSize: 20
        }
      }]
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.4.0/Chart.min.js"></script>
<canvas id="myChart" width="400" height="200"></canvas>

There is also a pluginless method, mentioned here, but that method is lacking. According to that method, one would have to set the borderColor to a gradient that should have been created before the creation of the chart. The gradient is calculated statically and will never fit an arbitrary range or respond to resizing as is.

Leave a comment