You may have heard of libraries such as D3 or chart js, which enable you to create many different charts of all shapes and sizes using JavaScript.
But most of the time you have to spend a fair bit of time learning the libraries themselves which is not always ideal, especially if you only need a simple bar chart for example.
Now with standard html elements alone, it is not ideal either because you will have to add in many styles to even begin seeing results how you want to see them.
But when you combine JavaScript and svg elements together you can create fast, efficient and cool looking svg bar charts that are scalable and manageable.
With the added bonus of no libraries to learn or to add size to your code base.
This works because svg elements have size and position attributes which makes moving them around and changing the shapes and sizes very easy to do.
For the svg bar chart we will only need to use two svg elements so there isn’t loads to learn to get started either.
Svg
Firstly is the svg element itself, there are three key attributes we need to look into before we can create our svg bar chart.
viewBox
In an svg the attribute viewBox
does quite a lot and can cause frustrating issues if you are not sure what is really does.
The viewBox takes 4 numerical values that are usually separated by white space.
The first two values are min-x
, and min-y
, when in use, you can use these first to numbers to almost pan/position the inside content of the svg, for example if you have an svg that is of size 10 wide and 10 tall, and you set the initial two values of viewbox to 5 0
this will move the contents of the svg half to the left, and 0 5
would push it up by half.
You can think of this effect to be similar to that of a transform in css.
The last two values in viewBox define the width
and height
of the contents in the svg. Which means, when you combine this with a fixed height and width, these values will effectively work as a zoom for all the elements within the svg.
Height and width
The next two attributes are fairly self explanatory, they simply set the height and width of the svg using any unit you wish just like many other html elements would accept. For example <svg height=”100” width=”100”>
.
Rect
The svg element rect, literally stands for rectangle, because this is the shape it will allow you to create when using this element (perfect for an svg bar chart!).
On the rect we only need to worry about 4 attributes which are very easy to understand, the first two I probably don’t need to explain and they are height
and width
, which control the size and shape of the rect element.
And the last two that we need to look at are the x
, and y
attributes which allow you to position the rect element within the svg.
With the basics now covered for our svg bar chart, we can now start taking a look at how this fits in with JavaScript.
First little tip to remember is that when creating any svg elements using JavaScript, the normal conventional way of using document.createElement
will not work.
If you try to use it, you won’t get an error message, it will simply just not create the element leaving you confused.
To get around this you need to use the following function instead: document.createElementNS
, this allows you to specify a namespace URI as well as the element, and in our situation we will need to use the svg namespace to create our svg bar chart elements with JavaScript.
The namespace URI for the svg elements will be: http://www.w3.org/2000/svg
.
This means whenever we create an svg element using JavaScript it will look something like this:
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
Let’s take a look at the code behind our svg bar chart now.
Firstly, create an empty root html element like this:
<div id="root"></div>
This is so we have somewhere to add our svg bar chart to once we have generated it.
Also add in a few basic css styles that we will make use of to style our svg bar chart so we can see it in a nice visual manner:
body {
background: #333;
}
svg {
background: #fff;
}
rect {
fill: lightblue;
stroke-width: 1px;
stroke:#fff;
}
Now for the JavaScript, let’s initiate our svg bar chart with js by creating the svg container by using the following code:
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
svg.setAttribute('height', `${500}px`);
svg.setAttribute('width', `${500}px`);
svg.setAttribute('viewBox', `0 0 500 500`);
Here we are creating a new svg element and giving it the height and width of 500px and setting the viewBox to match the 500px exactly so the contents should fit to the svg container exactly.
Next create some dummy data in the form of an array like this:
const chartData = new Array(10)
.fill(0)
.map(
() =>
parseInt(
100 * (Math.random() + 1),
10
),
);
This will create an array with 10 entries that will each have a random numerical value between 100 - 200.
Now we have our base svg and our dummy data, next is to generate the bar chart, create a new function that will contain the processes we need to create our svg bar chart as well as having the ability to store all our chart data.
function generateChart(data) {
const barChartElems = [];
}
Now we are going to create a create method and an update method within this function, the reason why we will need both a create and update is mainly so we can add data to our bar chart in the future but it also enables us to make a nice onload animation when the bar chart first loads in.
Let’s start with the creation function.
const create = (d) => {
d.forEach((entry, index) => {
const bar = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
bar.setAttribute('x', index * (500 / data.length));
bar.setAttribute('y', 500 - 0);
bar.setAttribute('height', `${0}px`);
bar.setAttribute('width', `${500 / data.length}px`);
bar.setAttribute('style', 'transition: 0.5s all;');
svg.appendChild(bar);
barChartElems.push(bar);
});
};
In this create function we are iterating over the dummy data we created using the Array.forEach higher order function.
Then for each bit of data, we are creating a new bar, in our svg bar chart, with the initial values of 0, except from the x
position, which is setting the position in the bar chart where the bar will be so we can limit our animation to grow in height, and not move to its position as well. Doing this should help to create a smooth and clean animation.
Next is the update method.
const update = (newData) => {
if (newData.length > barChartElems.length) {
create(newData.filter(((e, i) => i > barChartElems.length - 1)));
}
newData.forEach((newEntry, index) => {
if (index > barChartElems.length - 1) return;
const bar = barChartElems[index];
bar.setAttribute('x', index * (500 / newData.length));
bar.setAttribute('width', `${500 / newData.length}px`);
setTimeout(() => {
bar.setAttribute('y', 500 - newEntry);
bar.setAttribute('height', `${newEntry}px`);
}, 100 * index);
});
};
In this method, we are first checking to see if any additional data has been added to our data array, and if it has it will then re-create the initial set of bars for our bar chart with the correct amount of data.
We then loop over the new data, accessing the bars in our array, and updating each of the attributes to represent the actual data with the height and y values being changed after a delay of 0.1 seconds, created by the setTimeout
, to create a smooth animation effect.
Finally to finish off our svg bar chart generation function, at the end we want to call, and return the functions we just made.
We first want to call the create function, and then the update, finally returning the update method to be used again and again, whilst storing all the current data by making use of a closure.
function generateChart(data) {
…
create(data);
update(data);
return update;
}
Finally, to finish off our svg bar chart we need to append it as a child to our root html element which can be done like this: document.getElementById('root').appendChild(svg);
and then call the generate function like this: const updateChart = generateChart(chartData);
Which will give us a working svg bar chart, with a nice smooth animation when loading in.
Now to add on one last final touch, let’s add in an input and a button so we can add more data to our chart and make use of the update closure we created.
Add in the following code to the bottom of the JavaScript which will just create an input and a button and add an event listener that when activated will add the data from the input to our dummy data array.
const updateChart = generateChart(chartData);
const input = document.createElement('input');
const button = document.createElement('button');
button.innerText = 'Add to data';
button.addEventListener('click', (e) => {
const nextEntry = parseInt(input.value, 10);
chartData.push(nextEntry);
if(updateChart === null) {
updateChart = generateChart(chartData);
} else {
updateChart(chartData);
}
});
document.getElementById('root').appendChild(input);
document.getElementById('root').appendChild(button);
Here is the code pen for your to see the full code and see how the chart looks and works:
Will