var ctx = document.getElementById("chart").getContext("2d");
var scatterChart = new Chart(ctx, {
type: "line",
data: {
datasets: [{
label: " Dataset",
data: [{
x: 1,
y: 10
},
{
x: 2,
y: 50
},
{
x: 3,
y: 88
},
{
x: 4,
y: 5
}
]
}]
},
options: {
scales: {
xAxes: [{
type: "linear",
position: "bottom"
}]
}
},
plugins: [{
beforeDatasetDraw: function(chart, options) {
var metasets = chart._getSortedVisibleDatasetMetas();
var ctx = chart.ctx;
var meta, i, el, view, points, mapper, color;
var clipArea = (ctx, area) => {
ctx.save();
ctx.beginPath();
ctx.rect(area.left, area.top, area.right - area.left, area.bottom - area.top);
ctx.clip();
};
var unclipArea = (ctx) => {
ctx.restore();
};
var isDrawable = (point) => {
return point && !point.skip;
}
var lineTo = (ctx, previous, target, flip) => {
var stepped = target.steppedLine;
if (stepped) {
if (stepped === 'middle') {
var midpoint = (previous.x + target.x) / 2.0;
ctx.lineTo(midpoint, flip ? target.y : previous.y);
ctx.lineTo(midpoint, flip ? previous.y : target.y);
} else if ((stepped === 'after' && !flip) || (stepped !== 'after' && flip)) {
ctx.lineTo(previous.x, target.y);
} else {
ctx.lineTo(target.x, previous.y);
}
ctx.lineTo(target.x, target.y);
return;
}
if (!target.tension) {
ctx.lineTo(target.x, target.y);
return;
}
ctx.bezierCurveTo(
flip ? previous.controlPointPreviousX : previous.controlPointNextX,
flip ? previous.controlPointPreviousY : previous.controlPointNextY,
flip ? target.controlPointNextX : target.controlPointPreviousX,
flip ? target.controlPointNextY : target.controlPointPreviousY,
target.x,
target.y);
}
var drawArea = (ctx, curve0, curve1, len0, len1) => {
var i, cx, cy, r;
if (!len0 || !len1) {
return;
}
// building first area curve (normal)
ctx.moveTo(curve0[0].x, curve0[0].y);
for (i = 1; i < len0; ++i) {
lineTo(ctx, curve0[i - 1], curve0[i]);
}
if (curve1[0].angle !== undefined) {
cx = curve1[0].cx;
cy = curve1[0].cy;
r = Math.sqrt(Math.pow(curve1[0].x - cx, 2) + Math.pow(curve1[0].y - cy, 2));
for (i = len1 - 1; i > 0; --i) {
ctx.arc(cx, cy, r, curve1[i].angle, curve1[i - 1].angle, true);
}
return;
}
// joining the two area curves
ctx.lineTo(curve1[len1 - 1].x, curve1[len1 - 1].y);
// building opposite area curve (reverse)
for (i = len1 - 1; i > 0; --i) {
lineTo(ctx, curve1[i], curve1[i - 1], true);
}
}
var doFill = (ctx, points, mapper, view, color, loop) => {
var count = points.length;
var span = view.spanGaps;
var curve0 = [];
var curve1 = [];
var len0 = 0;
var len1 = 0;
var i, ilen, index, p0, p1, d0, d1, loopOffset;
ctx.beginPath();
for (i = 0, ilen = count; i < ilen; ++i) {
index = i % count;
p0 = points[index]._view;
p1 = mapper(p0, index, view);
d0 = isDrawable(p0);
d1 = isDrawable(p1);
if (loop && loopOffset === undefined && d0) {
loopOffset = i + 1;
ilen = count + loopOffset;
}
if (d0 && d1) {
len0 = curve0.push(p0);
len1 = curve1.push(p1);
} else if (len0 && len1) {
if (!span) {
drawArea(ctx, curve0, curve1, len0, len1);
len0 = len1 = 0;
curve0 = [];
curve1 = [];
} else {
if (d0) {
curve0.push(p0);
}
if (d1) {
curve1.push(p1);
}
}
}
}
drawArea(ctx, curve0, curve1, len0, len1);
ctx.closePath();
ctx.fillStyle = color;
ctx.fill();
}
for (i = metasets.length - 1; i >= 0; --i) {
meta = metasets[i].$filler;
if (!meta || !meta.visible) {
continue;
}
el = meta.el;
view = el._view;
points = el._children || [];
mapper = meta.mapper;
// NOTE: HERE IS WHERE THE GRADIENT IS DEFINED. ONE COULD PROBABLY CREATE THE GRADIENT BASED ON INPUT DATA INSIDE THE OPTIONS OBJECT.
color = ctx.createLinearGradient(chart.width / 2, chart.height, chart.width / 2, 0);
color.addColorStop(0, 'red');
color.addColorStop(0.2, 'red');
color.addColorStop(0.4, 'yellow');
color.addColorStop(0.6, 'yellow');
color.addColorStop(0.8, 'green');
color.addColorStop(1, 'green');
if (mapper && color && points.length) {
clipArea(ctx, chart.chartArea);
doFill(ctx, points, mapper, view, color, el._loop);
unclipArea(ctx);
}
}
}
}]
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.bundle.js"></script>
<div class="container">
<canvas id="chart"></canvas>
</div>