Chartjs-Chart.js Fill color at null line and null points Tooltip

0👍

Instead of drawing the lines within the beforeDraw hook, you can compute and define the borderColor and backgroundColor of the dataset inside the afterLayout hook using CanvasRenderingContext2D.createLinearGradient(). This has the advantage that the lineTension option will also be considered and you’ll obtain a nice looking Bezier curve.

To make it work, you’ll also have to define spanGaps: true on the dataset. This instructs Chart.js to draw lines between points, even if there are null values in between.

afterLayout: chart => {
  let ctx = chart.chart.ctx;
  ctx.save();
  let xAxis = chart.scales['x-axis-0'];
  let borderGradient = ctx.createLinearGradient(xAxis.left, 0, xAxis.right, 0);
  let bgGradient = ctx.createLinearGradient(xAxis.left, 0, xAxis.right, 0);
  let dataset = chart.data.datasets[0];
  dataset.data.forEach((value, index) => {
    if (index > 0) { 
      let valueFrom = dataset.data[index - 1];
      let valueTo = dataset.data[index + 1]; 
      let xFrom = xAxis.getPixelForValue(valueFrom);
      let xTo = xAxis.getPixelForTick(index);         
      let offset = 1 / (xAxis.right - xAxis.left) * (xTo - xAxis.left);         
      borderGradient.addColorStop(offset, valueFrom == null || value == null ? '#ff0000' : '#3d93a8'); 
      borderGradient.addColorStop(offset, value == null || valueTo == null ? '#ff0000' : '#3d93a8');
      bgGradient.addColorStop(offset, valueFrom == null || value == null ? 'rgba(255, 0, 0, 0.5)' : 'rgba(61, 147, 168, 0.5)'); 
      bgGradient.addColorStop(offset, value == null || valueTo == null ? 'rgba(255, 0, 0, 0.5)' : 'rgba(61, 147, 168, 0.5)'); 
    }
  });            
  dataset.borderColor = borderGradient;
  dataset.backgroundColor = bgGradient;
  ctx.restore();
}

Please take a look at your amended and runnable code below:

new Chart('canvas', {
  type: 'line',
  plugins: [{
    afterLayout: chart => {
      let ctx = chart.chart.ctx;
      ctx.save();
      let xAxis = chart.scales['x-axis-0'];
      let borderGradient = ctx.createLinearGradient(xAxis.left, 0, xAxis.right, 0);
      let bgGradient = ctx.createLinearGradient(xAxis.left, 0, xAxis.right, 0);
      let dataset = chart.data.datasets[0];
      dataset.data.forEach((value, index) => {
        if (index > 0) { 
          let valueFrom = dataset.data[index - 1];
          let valueTo = dataset.data[index + 1]; 
          let xFrom = xAxis.getPixelForValue(valueFrom);
          let xTo = xAxis.getPixelForTick(index);         
          let offset = 1 / (xAxis.right - xAxis.left) * (xTo - xAxis.left);         
          borderGradient.addColorStop(offset, valueFrom == null || value == null ? '#ff0000' : '#3d93a8'); 
          borderGradient.addColorStop(offset, value == null || valueTo == null ? '#ff0000' : '#3d93a8');
          bgGradient.addColorStop(offset, valueFrom == null || value == null ? 'rgba(255, 0, 0, 0.5)' : 'rgba(61, 147, 168, 0.5)'); 
          bgGradient.addColorStop(offset, value == null || valueTo == null ? 'rgba(255, 0, 0, 0.5)' : 'rgba(61, 147, 168, 0.5)'); 
        }
      });            
      dataset.borderColor = borderGradient;
      dataset.backgroundColor = bgGradient;
      ctx.restore();
    }
  }],
  data: {
    labels: ["1", "2", "3", "4", "5", "6", "7", "8"],
    datasets: [{
      label: "Number",
      data: [20, 15, null, 18, 21, null, 8, 16],
      pointRadius: 0.0,
      pointHoverRadius: 0.0,
      lineTension: 0.6,
      borderWidth: 2.5,
      spanGaps: true
    }]
  },
  options: {
    title: {
      display: true,
      fontStyle: 'bold',
      fontSize: '20',
      fontColor: '#000',
      position: 'top',
      lineHeight: 1.0,
      text: 'Description',
    },
    legend: {
      display: false,
      position: "butt",
      labels: {}
    },
    tooltips: {
      enabled: true,
      mode: 'index',
      intersect: false,
      xPadding: 15,
      bodySpacing: 0,
      cornerRadius: 10,
      titleMarginBottom: 5,
      position: 'nearest',
      titleAlign: 'center',
    },
    animation: {
      duration: 0
    },
    scales: {
      xAxes: [{
        stacked: true,
        barThickness: 'flex',
        maxBarThickness: 100,
        gridLines: {
          display: false
        },
        ticks: {
          autoSkip: true,
          maxTicksLimit: 24
        },
      }],
      yAxes: [{
        ticks: {
          beginAtZero: true,
        }
      }]
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="canvas" width="auto" height="100%"></canvas>

Leave a comment