1👍
✅
As described in the documentation here you can specify the fill as an object instead of setting it to true in which you can tell chart.js to fill above a specific value with a different collor as below.
var ctx = document.getElementById("chart").getContext("2d");
var myLine = new Chart(ctx, {
type: 'line',
data: {
labels: ["label1", "label2", "label3", "label4"],
datasets: [{
label: 'Demo',
backgroundColor: function(context) {
const index = context.dataIndex;
const value = context.dataset.data[index];
return value < 0 ? 'rgba(54, 162, 235, 1)' : 'rgba(53, 122, 135, 1)';
},
fill: {
target: {
value: 0
},
below: 'rgba(54, 162, 235, 1)',
above: 'rgba(53, 122, 135, 1)'
},
data: [-2, -3, 4, 6],
}]
},
options: {},
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.2.0/chart.umd.js"></script>
<canvas id="chart"></canvas>
-1👍
Thanks to jordanwillis. His codepen has helped me a lot to solve this problem. Of course, solving this problem is done manually with an explanation as in the code below.
// decimal rounding algorithm
// see: https://plnkr.co/edit/uau8BlS1cqbvWPCHJeOy?p=preview
var roundNumber = function (num, scale) {
var number = Math.round(num * Math.pow(10, scale)) / Math.pow(10, scale);
if(num - number > 0) {
return (number + Math.floor(2 * Math.round((num - number) * Math.pow(10, (scale + 1))) / 10) / Math.pow(10, scale));
} else {
return number;
}
};
// save the original line element so we can still call it's
// draw method after we build the linear gradient
var origLineElement = Chart.elements.Line;
// define a new line draw method so that we can build a linear gradient
// based on the position of each point
Chart.elements.Line = Chart.Element.extend({
draw: function() {
var vm = this._view;
var backgroundColors = this._chart.controller.data.datasets[this._datasetIndex].backgroundColor;
var points = this._children;
var ctx = this._chart.ctx;
var minX = points[0]._model.x;
var maxX = points[points.length - 1]._model.x;
var linearGradient = ctx.createLinearGradient(minX, 0, maxX, 0);
// iterate over each point to build the gradient
points.forEach(function(point, i) {
// `addColorStop` expects a number between 0 and 1, so we
// have to normalize the x position of each point between 0 and 1
// and round to make sure the positioning isn't too percise
// (otherwise it won't line up with the point position)
var colorStopPosition = roundNumber((point._model.x - minX) / (maxX - minX), 2);
// special case for the first color stop
if (i === 0) {
linearGradient.addColorStop(0, backgroundColors[i]);
} else {
// only add a color stop if the color is different
if (backgroundColors[i] !== backgroundColors[i-1]) {
// add a color stop for the prev color and for the new color at the same location
// this gives a solid color gradient instead of a gradient that fades to the next color
linearGradient.addColorStop(colorStopPosition, backgroundColors[i - 1]);
linearGradient.addColorStop(colorStopPosition, backgroundColors[i]);
}
}
});
// save the linear gradient in background color property
// since this is what is used for ctx.fillStyle when the fill is rendered
vm.backgroundColor = linearGradient;
// now draw the lines (using the original draw method)
origLineElement.prototype.draw.apply(this);
}
});
// we have to overwrite the datasetElementType property in the line controller
// because it is set before we can extend the line element (this ensures that
// the line element used by the chart is the one that we extended above)
Chart.controllers.line = Chart.controllers.line.extend({
datasetElementType: Chart.elements.Line,
});
// the labels used by the chart
var labels = ["Year 1", "Year 2", "Year 3", "Year 4", "Year 5"];
// the line chart point data
var lineData = [-50, -25, -6.04, 24.98, 50];
// colors used as the point background colors as well as the fill colors
var fillColors = [];
lineData.forEach((l)=> {
fillColors.push(l < 0 ? 'rgba(54, 162, 235, 1)' : 'rgba(53, 122, 135, 1)');
});
// get the canvas context and draw the chart
var ctx = document.getElementById("solarPaybackChart").getContext("2d");
var myLine = new Chart(ctx, {
type: 'line',
data: {
labels: labels,
datasets: [{
label: '',
backgroundColor: fillColors, // now we can pass in an array of colors (before it was only 1 color)
pointBackgroundColor: fillColors,
fill: true,
data: lineData,
}]
},
options: {
tooltips: {
callbacks: {
label: function (context) {
let label = '';
if (context.yLabel !== null) {
label += context.yLabel + '%';
}
return label;
}
}
},
scales: {
x: {
display: false,
maxTicks: 15,
grid: {
display: false
},
title: {
display: true,
text: 'Year'
}
},
y: {
display: false,
maxTicksLimit: 5,
grid: {
display: false
},
title: {
display: false,
text: 'Return'
}
}
},
plugins: {
legend: {
display: false
},
tooltips: {
callbacks: {
label: function (context) {
let label = '';
if (context.yLabel !== null) {
label += context.yLabel + '%';
}
return label;
}
}
},
},
interaction: {
intersect: false,
mode: 'index',
},
spanGaps: true,
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.js"></script>
<canvas id="solarPaybackChart"></canvas>
The above code is implemented with Chart.js 2.x
. I wonder how this is implemented in Chart.js 3.x
Source:stackexchange.com