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>
Source:stackexchange.com