Use the code below to try out everything that I talk about in this post, and check out the live demo over on code.bocoup.com.
//based on the source of http://g.raphaeljs.com/linechart.html
var options = {
axis: "0 0 1 1", // Where to put the labels (trbl)
axisxstep: 16 // How many x interval labels to render (axisystep does the same for the y axis)
};
document.addEventListener('DOMContentLoaded', function () {
// Make the raphael object
var r = Raphael("myDomElem");
var lines = r.g.linechart(
20, // X start in pixels
10, // Y start in pixels
300, // Width of chart in pixels
200, // Height of chart in pixels
[.5,1.5,2,2.5,3,3.5,4,4.5,5], // Array of x coordinates equal in length to ycoords
[7,11,9,16,3,19,12,12,15], // Array of y coordinates equal in length to xcoords
options // opts object
);
// Modify the x axis labels
var xText = lines.axis[0].text.items;
for(var i in xText){ // Iterate through the array of dom elems, the current dom elem will be i
var _oldLabel = (xText[i].attr('text') + "").split('.'), // Get the current dom elem in the loop, and split it on the decimal
_newLabel = _oldLabel[0] + ":" + (_oldLabel[1] == undefined ? '00' : '30'); // Format the result into time strings
xText[i].attr({'text': _newLabel}); // Set the text of the current elem with the result
};
}, false); // End DOMContentLoaded callback
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script type="text/javascript" src="https://raw.github.com/DmitryBaranovskiy/raphael/03538da207cb41e2ebc303fe8fc247dd0b5e655f/raphael-min.js"></script>
<script type="text/javascript" src="https://raw.github.com/DmitryBaranovskiy/g.raphael/177d888cbc8824d2a513c975ed5be8a3291b72ea/g.raphael.js"></script>
<script type="text/javascript" src="https://raw.github.com/DmitryBaranovskiy/g.raphael/177d888cbc8824d2a513c975ed5be8a3291b72ea/g.line.js"></script>
<script type="text/javascript" src="modified-x-axis-intervals-and-labels.js"></script>
</head>
<body>
<div id="myDomElem"></div>
</body>
</html>
Raphaël’s charting tools, gRaphaël, come with great out of the box functionality. The core charting library, and the individual chart scripts allow you to easily pass in arrays of x,y coordinates, and they just get charted. Since there are no docs, however, figuring out how to modify the default behavior can be tricky.
I recently worked on a gRaphaël linchart that required fixed 1/2 hour intervals of time on the x-axis, and various quantities on the y-axis. gRaphaël’s linechart()
default behavior presented two problems, which I found solutions for in the g.line.js source and the gRaphaël issues page on github and will demonstrate bellow:
- The default x-axis label intervals are auto built by `linechart()` based on the number of data points, and the width in pixels of your chart.
- `linechart()` assumes you are charting base 10 numbers and the x axis label text are created implicitly from the data. Therefore, the labels must be real base 10 numbers, and not wacky base 60 time with sexagesimal colons instead of decimal periods.
1) Modifying the default x-axis interval
The x-axis label interval is set on line 72 of g.raphael.js where width
is the width argument passed into linechart()
, and gutter is 10 (unless you override it):
Math.floor((width - 2 * gutter) / 20), 2)
You’ll notice, if you read earlier in line 72, that this default condition only occurs if opts.axisxstep
is not set. opts
is an option object that you can pass in to linechart()
as an optional last argument, and linechart()
will try to use it all over the place.
All you have to do is pass in a object literal with an axisxstep property set to what ever value you want:
2)Modifying the the x-axis labels
I needed to represent time in the line chart that I was working on. Instead of modifying gRaphaël to operate on base 60 numbers, my solution was to send base 10 representations of time intervals, and convert the labels into time interval strings.
When you run linechart() on a raphael object, an object representation of your linechart is stored on the object you created. If your named linechart object lines you could grab a reference to the DOM element of each text node by iterating through this array:
lines.axis[0].text.items; //[array, of, DOM elements]
You can get the text for each text node like this:
var myTextElem = lines.axis[0].text.items[0];
myTextElem.attr('text');
You can set the text for each text node like this:
myTextElem.attr({'text' : 'new string of text'});
Thanks to Lindsay Holmwood for pointing this out.
In this way, you can traverse your instance of the linechart object, get the text nodes for each x axis label, manipulate them and set them again.