Fork Me on GitHub
stuquery.barchart.js (13.1kB) minified (8.6kB) css (2.1kB)

stuQuery barchart

This is a simple HTML barchart library that makes use of stuQuery. Being created from simple HTML elements, it is easy to style the barcharts with CSS.

Basic example

In the head of your page include the Javascript and CSS

<link rel="stylesheet" href="stuquery.barchart.css">
<script type="text/javascript" src="stuquery.js"></script>
<script type="text/javascript" src="stuquery.barchart.js"></script>

Create your Javascript

S(document).ready(function(){
	// Create your data array where each item is in the form [bin,value]
	var data = [[-1.2,2],[-0.4,3],[-0.2,1],[0.2,4],[0.8,2.5],[1.2,2],[1.8,1],[2.2,1]]

	// Build the barchart object attached to <div id="barchart">
	var chart = new S.barchart('#barchart');
	
	// Set the data
	// Set the bins - if no values are provided here, they will be automatically generated
	// Draw the chart
	chart.setData(data).setBins({'mintick':5}).draw();
});

A chart can be created with any of the following options:

// Build the barchart object with options set
var chart = new S.barchart('#barchart', {
	'units': string,       // Display a unit before the bin values
	'formatKey': function, // A function that is called to format the key value
	'formatBar': function, // A function that is called to add a class to a bar
	'parent': node,        // A value passed through to events as e.data.parent
	'min': number,         // The minimum bin value
	'max': number,         // The maximum bin value
	'inc': number,         // The numerical size of the bin
	'mintick': number,     // A minimum number of bins
	'bin': function        // A function that returns the bin number given an input value
});

The setBins function can take the following options:

chart.setBins({
	'min': number,         // The minimum bin value
	'max': number,         // The maximum bin value
	'inc': number,         // The numerical size of the bin
	'mintick': number,     // A minimum number of bins
	'update': true         // Force a recalculation of the bins
});

Example 1

This chart shows year-based data binned by year and with labels only every decade.

// Create the barchart object attached to the element with id="barchart"
var chart = new S.barchart('#barchart', {
	// Only display an x-axis label every decade
	'formatKey': function(key){
		return (key%10==0 ? key.substr(0,4) : '');
	}
});

// Add events
chart.on('barclick',function(e){
	// Get the bin
	this.toggleBin(e.bin);
}).on('barover',function(e){
	// Remove any existing information balloon
	S('.balloon').remove();
	// Get the key for this bin
	var key = parseInt(this.bins[e.bin].key);
	// Add a new information balloon - if the bin size is >1 we show the bin range in the label
	S(e.event.currentTarget).find('.bar').append(
		'<div class="balloon">'
		+ (this.inc > 1 ? key+'&rarr;'+(key+this.inc) : key)
		+ ': '+(this.bins[e.bin].value).toFixed(2).replace(/\.?0+$/,"")
		+ '</div>');
});

// Remove the information balloon when we leave the chart
S('#barchart').on('mouseleave',function(e){
	S('.balloon').remove();
});

// Define data
var data = [[1950,1],[1951,0],[1952,0],[1953,0],[1954,0],[1955,0]...

// Force the bins to be 1 year wide, set the data, and draw the chart
chart.setData(data).setBins({'inc':1}).draw();

// Attach event to button
S('#year5').on('click',function(){

	// Set the bin size to 5 years
	chart.setBins({'inc':5});

	// Re-draw the chart
	chart.draw();
});

Example 2

This chart displays random data with an auto scaling to test negative values. Negative values are given a different bar style.

We'll add some CSS to change the colours of the bars to purple with a pink hover.

#barchart .bar { background-color: #722EA5; }
#barchart td:hover .bar { background-color: #E6007C; }
#barchart td:hover .antibar { background-color: rgba(230,0,124,0.1); }
#barchart td.negative .bar {
	background-color: #722EA5;
	background-image: repeating-linear-gradient(45deg, transparent, transparent 35px, rgba(255,255,255,.5) 35px, rgba(255,255,255,.5) 70px);
}
#barchart td.negative:hover .bar { background-color: #E6007C; }

Here is the Javascript.

// Define some data
var data = [[-1.2,2],[-0.4,3],[-0.2,1],[0.2,4],[0.8,2.5],[1.2,2],[1.8,1],[2.2,1]];

// Create the barchart object. We'll add a function to
// customise the class of the bar depending on the key.
var chart = new S.barchart('#barchart',{
	formatBar: function(key){
		return (key < 0 ? "negative":"");
	}
});

// Send the data array and bin size then draw the chart
chart.setData(data).setBins({ 'mintick': 5 }).draw();

// Add an event
chart.on('barover',function(e){
	S('.balloon').remove();
	S(e.event.currentTarget).find('.bar').append(
		"<div class=\"balloon\">"
		+(this.bins[e.bin].key
		+" &rarr; "
		+(parseFloat(this.bins[e.bin].key)+this.inc))
		+" = "
		+(this.bins[e.bin].value).toFixed(2).replace(/\.?0+$/,"")
		+"</div>"
	);
});

// Remove the information balloon when we leave the chart
S('#barchart').on('mouseleave',function(e){
	S('.balloon').remove();
});

// Add a button press event (id=random) which creates 
// some new random data and updates the graph
S('#random').on('click',function(){
	var mydata = [];
	var maxy = 50;
	var maxx = Math.pow(10,Math.random()*5);
	var cen = Math.random()*maxx;
	var n = 100;
	for(var i = 0; i < n; i++) mydata[i] = [(Math.random()*maxx)-cen,1];

	// We've created data with different bins so we will force a 
	// recalculation of the bins before redrawing
	chart.setData(mydata).setBins({'update':true}).draw();
})

Example 3

This chart shows category bins.

// Define the data
var data = [["Bradford Beck",0.2],["Lower Beck",0.4],["River Aire",0.5],["Flood alleviation",0.15]];

// Create the barchart object
var chart = new S.barchart('#barchart');

// Add the data and draw the chart
chart.setData(data).setBins().draw();

// Display information on hover events
chart.on('barover',function(e){
	S('.balloon').remove();
	S(e.event.currentTarget).find('.bar').append(
		'<div class="balloon">'
		+ (this.bins[e.bin].key)+': '
		+ (this.bins[e.bin].value).toFixed(2).replace(/\.?0+$/,"")
		+ '</div>'
	);
}).on('mouseleave',function(e){
	S('.balloon').remove();
});
#barchart .bar {
	background: radial-gradient(circle closest-side, #f9f9fa 13px, rgba(255,255,255,0) 0) 0 -28px,
	radial-gradient(circle closest-side, #f9f9fa 13px, rgba(255,255,255,0) 0) 25px -28px #178CFF;
	background-size: 50px 50px;
	background-repeat:repeat-x;
}
#barchart td:hover .bar {
	background: radial-gradient(circle closest-side, #dfdfdf 13px, rgba(255,255,255,0) 0) 0 -28px,
	radial-gradient(circle closest-side, #dfdfdf 13px, rgba(255,255,255,0) 0) 25px -28px #178CFF;
	background-size: 50px 50px;
	background-repeat:repeat-x;
}

Example 4

This chart shows monthly bins using categories.

// Define the data
var data = [["2014-04",1],["2014-05",9],["2014-06",4],["2014-07",10],["2014-08",1],["2014-09",6],["2014-10",9],["2014-11",7],["2014-12",12],["2015-01",13],["2015-02",14],["2015-03",17],["2015-04",20],["2015-05",16],["2015-06",23],["2015-07",14],["2015-08",4],["2015-09",20],["2015-10",15],["2015-11",24],["2015-12",9],["2016-01",16],["2016-02",20],["2016-03",11],["2016-04",16],["2016-05",19],["2016-06",19],["2016-07",21],["2016-08",3],["2016-09",15],["2016-10",17],["2016-11",14],["2016-12",7],["2017-01",8],["2017-02",12],["2017-03",1]];

// Make the chart
var chart = new S.barchart('#barchart',{
	// Only show x-axis labels when they are of the form YYYY-01
	'formatKey': function(key){
		return (key.indexOf('-01') > 0 ? key.substr(0,4) : '');
	}
});

// Set the data and draw the chart
chart.setData(data).setBins().draw();

// Add events
chart.on('barover',function(e){
	S('.balloon').remove();
	var months = ['January','February','March','April','May','June','July','August','September','October','November','December'];
	S(e.event.currentTarget).find('.bar').append(
		'<div class="balloon">'
		+months[parseInt(this.bins[e.bin].key.substring(5))-1]
		+' '
		+this.bins[e.bin].key.substr(0,4)
		+': '
		+this.bins[e.bin].value
		+'</div>'
	)
});

// Remove the information balloon
S('#barchart').on('mouseleave',function(e){
	S('.balloon').remove();
});

Example 5

This chart shows time bins with negative values.

// Define the data
var data = [["00:00",0],["00:30",0],["01:00",0],["01:30",0],["02:00",0],["02:30",0],["03:00",0],["03:30",0],["04:00",0],["04:30",1.8],["05:00",0.8],["05:30",0.7],["06:00",8.1],["06:30",5.3],["07:00",0.3],["07:30",1.9],["08:00",0.5],["08:30",0.7],["09:00",4.1],["09:30",3.2],["10:00",0],["10:30",0],["11:00",0],["11:30",-2],["12:00",0.3],["12:30",0.9],["13:00",3.3],["13:30",5.7],["14:00",0.6],["14:30",0.6],["15:00",0.6],["15:30",0.9],["16:00",3],["16:30",3.5],["17:00",3.4],["17:30",2.6],["18:00",3.6],["18:30",2],["19:00",0.7],["19:30",0],["20:00",0],["20:30",0.6],["21:00",5.5],["21:30",16],["22:00",13.6],["22:30",2.8],["23:00",0.6],["23:30",0.2],["00:00",0]];

// Create the barchart object
var chart = new S.barchart('#barchart', {
	// Only display an x-axis label every decade
	'formatKey': function (key) {
		keyHours = Number(key.split(":")[0]);
		keyMinutes = Number(key.split(":")[1]);
		return (keyHours % 4 == 0 && keyMinutes == 0 ? key : '');
	},
	'formatBar':function(key,val){ return (val < 0 ? "negative":""); }
});

// Add events
chart.on('barover', function (e) {
	// Get the bin
	var b = S(e.event.currentTarget).attr('data-index');

	// Remove any existing information balloon
	S('.balloon').remove();

	// Add a new information balloon
	S(e.event.currentTarget).find('.bar').append('
' + this.bins[b].key + ': ' + (this.bins[b].value) + ' mins
') }); // draw the chart chart.setData(data).setBins().draw();
#barchart td.negative .bar { background-color: #F9BC26; }