Above is a graph I made using ChartJS. I have two datasets. I also have the space between the two datasets filled just like I want it. But I need to get two different colors for the fill. When the Hours dataset is bigger than the Goal dataset, I want the fill to be green, and when the Hours dataset is smaller than Goal, I want it to be red. I'm really hoping there is a way to do this using ChartJS, so that I don't have to recreate this in Canvas.
If it matters, this is in Vue.Js.
Here is the code for the two datasets:
const dataSets = [{
label: this.dataSetLabel,
data: this.dataArray,
backgroundColor: new Array(this.dataArray.length).fill('rgba(255, 0, 0, 0.8)'), // red
borderColor: new Array(this.dataArray.length).fill('rgba(255, 0, 0, 0.8)'),
borderWidth: 1,
fill: '+1'
}]
if (this.fi !== 3) {
dataSets.push({
label: 'Goal',
data: new Array(this.dataArray.length).fill(this.user.braceHours),
type: 'line',
backgroundColor: new Array(this.dataArray.length).fill('rgba(84, 232, 198, 0.8)'), // green
borderColor: new Array(this.dataArray.length).fill('rgba(84, 232, 198, 0.8)'),
borderWidth: 1,
fill: '-1'
})
}
Any help with this would be much appreciated.
You can extend an existing line chart as shown by the runnable code snippted below.
This solution is based on the answer https://stackoverflow.com/a/36941860/2358409 that had to be slightly adapted to work with the latest stable version of Chart.js (2.9.3).
const goal = 2;
Chart.defaults.areaConditionalColors = Chart.defaults.line;
Chart.controllers.areaConditionalColors = Chart.controllers.line.extend({
update: function(reset) {
var yAxis = this.chart.scales['y-axis-0'];
var max = Math.max.apply(null, this.chart.data.datasets[0].data);
var yTop = yAxis.getPixelForValue(max);
var yGoal = yAxis.getPixelForValue(goal);
var min = Math.min.apply(null, this.chart.data.datasets[0].data);
var yBottom = yAxis.getPixelForValue(min);
// build a gradient that changes the color at the goal
var ctx = this.chart.chart.ctx;
var gradient = ctx.createLinearGradient(0, yTop, 0, yBottom);
var ratio = Math.min((yGoal - yTop) / (yBottom - yTop), 1);
gradient.addColorStop(0, 'green');
gradient.addColorStop(ratio, 'green');
gradient.addColorStop(ratio, 'red');
gradient.addColorStop(1, 'red');
this.chart.data.datasets[0].backgroundColor = gradient;
return Chart.controllers.line.prototype.update.apply(this, arguments);
}
});
new Chart('myChart', {
type: 'areaConditionalColors',
data: {
labels: ['FRI', 'SAT', 'SUN', 'MON', 'TUE', 'WED', 'THU'],
datasets: [{
label: 'Hours',
backgroundColor: 'green',
data: [0, 3, 0, 9, 4, 0, 0],
fill: '+1'
},
{
label: 'Goal',
backgroundColor: 'rgba(84, 232, 198, 0.8)',
data: [goal, goal, goal, goal, goal, goal, goal],
fill: '-1'
}]
},
options: {
legend: {
onClick: e => e.stopPropagation()
},
tooltips: {
mode: 'x'
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="myChart" height="80"></canvas>