A new example of a filled Line chart with alternating colors
Written by Richard Heyes, RGraph author, on 23rd July 2023Introduction
Here's a novel, if not terribly useful, example of a filledLine chart where the fill color is different above the first line (the pink line) to the fill color below the line. The demo that the code produces is also adjustable so you can drag the lines up and down and the fill color changes appropriately. There's two demos available: one is angular (like the chart that you can see at the CodePen link) and the other is a spline (smooth and curvy). This chart was requested on another Open Source charting library's support forum.
The code is not at all insubstantial and, at this time, does require a few new functions that are currently only available in unreleased versions of the RGraph libraries. These libraries are, however, available via GitHub so here's some links to them (and also the demo files) so that you can get hold of them:
The HTML markup
This is the html code that's used to show the chart. Note that the html includes label and input tags that you don't need if you don't want to allow people to switch between adjustable and static modes.
<!-- Include the relevant RGraph libraries --> <script src="RGraph.common.core.js"></script> <script src="RGraph.common.dynamic.js"></script> <script src="RGraph.line.js"></script> <!-- The canvas tag --> <canvas id="cvs" width="750" height="350" style="background-color: black">[No canvas support]</canvas><br /> <!-- The HTML tags for the checkbox underneath the chart. If you don't want the chart to be adjustable then these are not required --> <label for="checkboxAdjustable"> <span style="font-size: 30pt">Adjustable</span> </label> <input type="checkbox" value="1" id="checkboxAdjustable" onchange="line.set('adjustable', this.checked); RGraph.redraw()" style="width: 35px; height: 35px" checked />
The JavaScript code
This is the options section) is quite straight-forward - all the magic happens in the draw event.
<script>
line = new RGraph.Line({
id: 'cvs',
data: [
[200,300,200,300,350,250,200,225],
[200,110,280,290,250,350,310,110]
],
options: {
shadow: false,
yaxisScaleMax: 400,
colors: ['pink', 'cyan'],
textColor: '#ccc',
xaxis: false,
yaxis: false,
linewidth: 3,
tickmarkSize: 7,
backgroundGridColor: '#666',
backgroundGridDashed: true,
marginLeft: 75,
marginBottom: 50,
yaxisScaleUnitsPost: 'k',
xaxisLabels: ['Rich','Holly','Kevin','Bea','Gary','Pob','Luis','Jim'],
xaxisLabelsOffsety: 5,
textSize: 20,
// Set this to false if you don't want the chart to be adjustable
adjustable: true,
events: {
draw: function (obj)
{
// First, fill the bits which appear ABOVE the cyan
// (the first) line
obj.path('sa');
// Clip to the top bit of the canvas - above then first
// line
obj.path('b m % % l % %',
obj.canvas.width - obj.properties.marginRight,
obj.properties.marginTop,
obj.properties.marginLeft,
obj.properties.marginTop
);
// Path the line - the RGraph.pathLine() function
// is a shortcut function for creating a
// path from an array of X/Y coordinate pairs
RGraph.pathLine({
context: obj.context,
coords: obj.coords2[0],
moveto: false
});
// Now clip the canvas to the path that has just
// been created.
obj.path('cl');
// Begin drawing the lines
obj.path('b');
// Create a path from the first line
RGraph.pathLine({
context: obj.context,
coords: obj.coords2[0]
});
// Add the second line to the path in reverse
// order
RGraph.pathLine({
context: obj.context,
coords: obj.coords2[1],
moveto: false,
reverse: true
});
// Set the globalAlpha and then fill the shape
// that has just been drawn
obj.path('ga 0.5 f purple');
// Reset the canvas
obj.path('rs');
// Second, fill the bits which appear BELOW the cyan
// (the first) line.
obj.path('sa');
// Clip to the bottom bit of the canvas - below the
// first line.
obj.path('b m % % l % %',
obj.canvas.width - obj.properties.marginRight,
obj.canvas.height - obj.properties.marginBottom,
obj.properties.marginLeft,
obj.canvas.height - obj.properties.marginBottom
);
RGraph.pathLine({
context: obj.context,
coords: obj.coords2[0],
moveto: false
});
// Clip the canvas
obj.path('cl');
// Draw both of the lines
obj.path('b');
RGraph.pathLine({
context: obj.context,
coords: obj.coords2[0]
});
RGraph.pathLine({
context: obj.context,
coords: obj.coords2[1],
moveto: false,
reverse: true
});
// Set the globalAlpha and fill the shape in a green
// color
obj.path('ga 0.5 f green');
// Reset the canvas
obj.path('rs');
//
// Now, because the fills that were done above appear
// a little bit over the lines, draw the lines again
// along with the tickmarks.
//
// Add a custom tickmark - just a regular circle
// with the center colored black
for (var i=0; i<2; ++i) {
var coords = obj.coords2[i];
// Redraw the lines
RGraph.drawLine({
context: obj.context,
coords: coords,
linewidth: typeof obj.properties.linewidth === 'object' ? obj.properties.linewidth[i] : obj.properties.linewidth,
stroke: obj.properties.colors[i]
});
// Draw the tickmarks for the line
for (var j=0; j<coords.length; ++j) {
var x = coords[j][0];
var y = coords[j][1];
// Draw a big circle in the line color
obj.path(
"b a % % % % % false f %",
x, y, obj.properties.tickmarkSize, 0, 6.29,
obj.properties.colors[i]
);
// Draw a smaller circle over the above circle
// with a smaller radius so that it appears
// like a donut shaped tickmark
obj.path(
"b a % % % % % false f %",
x, y, obj.properties.tickmarkSize - 3, 0, 6.29,
'black'
);
}
}
}
}
}
}).draw();
</script>
A spline (smoothed) version
It's possible to get a spline version of the above by changing the obj.coords2 variable to obj.coordsSpline and adding spline: true to the chart configuration. Also change the for loop that redraws the tickmarks to only draw every tenth iteration - otherwise you'll see a lot of tickmarks! As simple as that!
Working demos
From version 6.14 a working demo is available in the demos/ folder of the download archive called line-alternate-fills.html