For a while I have been toying with the idea of creating a javascript tool/library to display simple histograms in the browser window. The idea was inspired by a concept called sparklines. Sparklines are considered to be “intense, simple, wordlike graphics” to represent simple data sets. This genre of graph can be used for a number of different things, though primarily it is used to display data that has little or no explanation needed. It’s helpful for displaying the history of a number, or for quickly displaying trends in data sets. One of my favourite websites has been using sparklines for a while now to display their daily page views.
Although not technically sparklines, the graphs created using this library are of a similar type. They could be used to display any sort of data that would normally be displayed using a histogram. The implementation that I demonstrate below is still a work in progress (it could even be considered a beta version - :P) and I will be working on it over the course of the next few days, so look out for edits to this post.
The invocation format is fairly simple, although it would be a lot nicer if I was able to use prototype and use invocation syntax like moo.ajax used to, but I want to keep the filesize as low as possible, plus not require any external libraries. I’ve thrown the types in for added clarity:
drawHistogram(‘graphDiv’,new Array() dataset,int width,int height,boolean axis,boolean autoRange)
The different parameters are fairly straight forward, axis enables and disables the x- and y-axis, while autoRange causes the graph to start at the lowest number. Here is an example:
drawHistogram(‘graphEl’,new Array(88,84,82,92,82,86,66,82,44,64,66,88,96,80,24,26,14,0,0,26,8,6,6,24,52,66,36,6,10,14,30),180,40,false,false);
Results in:
With some small changes made to the code, these graphs can also be used to quickly represent just about anything. Take this example of a weather forecast, which gives an overview of the weather for the previous 4 weeks in a very elegant way:
So finally - here is the code for displaying the graphs. Simply add this code within a <script> tag in your documents <head>, or save the file at the bottom of this page and import it using a <script> tag.
var divOffset = 0;
function drawHistogram(id,array,width,height,axis,autoRange)
{
var el = document.getElementById(id);
el.style.width = Math.round(width/array.length)*array.length + “px”;
el.style.height = height + “px”;
if(axis)
{
el.style.borderLeft = “1px solid #3D3D3D”;
el.style.borderBottom = “1px solid #3D3D3D”;
el.style.zIndex = 3;
}
var tempArray = new Array();
if(autoRange)
{
var smallest = getSmallestElement(array);
for(i = 0; i < array.length; i++)
{
tempArray[i] = array[i];
array[i] = array[i]-smallest+(smallest*0.05);
}
}
var xPos = 2;
//work out the multiplier for height
var multiplier = parseInt(el.style.height)*0.95 / getLargestElement(array);
// draw the actual graph
for(i = 0; i < array.length; i++)
{
var newItem = document.createElement(“div”);
var divIdName = “graphItem” + (++divOffset);
newItem.setAttribute(“y”,array[i]);
newItem.setAttribute(“id”, divIdName);
newItem.style.backgroundColor = “#B3CC99″;
newItem.style.width = Math.round((parseInt(el.style.width) - array.length*2)/array.length) + “px”;
newItem.style.height = Math.round(array[i]*multiplier) + “px”;
newItem.style.position = “absolute”;
//set the y position
var offset = (parseInt(el.style.height) - parseInt(newItem.style.height));
newItem.style.top = (findPosY(el) + offset) + “px”;
//set the x position
newItem.style.left = (findPosX(el) + xPos) + “px”;
xPos = xPos + (parseInt(el.style.width)/array.length);
el.appendChild(newItem);
if (newItem.addEventListener){
newItem.addEventListener(‘mouseover’, function () {this.style.backgroundColor = ‘#3366FF’}, false);
newItem.addEventListener(‘mouseout’, function () {this.style.backgroundColor = ‘#B3CC99′}, false);
}
else if (el.attachEvent){
//Internet Explorer
document.getElementById(divIdName).onmouseover = highlight;
document.getElementById(divIdName).onmouseout = normal;
}
}
}
function highlight(event) {
this.style.backgroundColor=‘#3366FF’;
}
function normal(event) {
this.style.backgroundColor=‘#B3CC99′;
}
function getLargestElement(array)
{
var largest = 0;
for(i = 0; i < array.length; i++)
if(array[i] > largest)
largest = array[i];
return largest;
}
function getSmallestElement(array)
{
var smallest = array[0];
for(i = 0; i < array.length; i++)
if(array[i] < smallest)
smallest = array[i];
return smallest;
}
/* Original code below created by by Peter-Paul Koch & modified by Alex Tingle. */
function findPosX(obj)
{
var curleft = 0;
if(obj.offsetParent)
while(1)
{
curleft += obj.offsetLeft;
if(!obj.offsetParent)
break;
obj = obj.offsetParent;
}
else if(obj.x)
curleft += obj.x;
return curleft;
}
function findPosY(obj)
{
var curtop = 0;
if(obj.offsetParent)
while(1)
{
curtop += obj.offsetTop;
if(!obj.offsetParent)
break;
obj = obj.offsetParent;
}
else if(obj.y)
curtop += obj.y;
return curtop;
}
Browser Support:
Tested in: Opera 9, Firefox 2, IE6+
Should work (but not fully tested): Safari, Opera 7+, Firefox 1+, IE 5+ (possibly with no mouse over effect)
Let me know if you find the demo’s buggy in any particular browser. I’ll be doing further testing of my own over the weekend and will update this post at some when I know more.
TODO/Ideas:
Make the mouse over effect work in IE.
Display x-value on mouseover (possibly tooltip)
Be able to zoom the graph.
Make it easier to set colour of bars.
Download:
The script can be downloaded from here. Right click and select to save the file.
Licence:
Although I am happy for this code to be used in any way you wish, a small note in the comments of this page would be appreciated if you use this code in your projects.
Parts of the code are sourced from Peter-Paul Koch & Alex Tingle, this code is believed to be public domain.