Blogger Ever

Draw, animate, redraw and fallbacks for SVG charts

A guide through the new age of SVG charts, which are going quite popular among web devs.
Nothing is more durable in DOM when it comes to vectors. Animation and drawing of simple objects is not an headache right now. Charts and animations are described by Sara Soueidan, Chris Coyer as well as Lea Verou. They are enough in many sense, however my real purpose for this post is to bring some diversity of vision in SVG charts. I'll try to spice it up with some inner stuff needed to display an attractive graph.

DOM is a better choice

Kirupa wrote an article in 2013, pros and cons are attached to every new technology we adopt. He didn't wrote whether to use DOM (<svg>) for charts or not. However, he quoted in post:
Animations are easy to define and modify. [...] This applies to JavaScript-based animations as well. If you are using JavaScript to animate an element's properties, you just have to get your requestAnimationFrame loop setup to update the property values. Everything else is taken care off...such as when to redraw or how to maintain a smooth frame rate.
The DOM let us give the instructions and process it using Graphic API and then visualize what we code, but canvas is just like free space, where we not only provide instructions but draw and provide additional code for fallbacks. Canvas are used for more complex cases, at least complex than charts.

SVGs are part of DOM, depending on the embedding technique, SVG might create a DOM shadow but that won't affect the working of the real code. They are easy to manipulate, draw, animate and accessible via Javascript as well as CSS.

Start with axes and guides

SVGs are all about 2D co-ordinate system. A line segment has two end points, each point have x and y co-ordinate, also known as abscissa and ordinate respectively. A line can simply be defined with line tag and x1,x2,y1 and y2 are co-ordinates of two end points. Use them we will define our axes.
See the Pen SVG chart - axes and grids by Mohammad Hamza Dhamiya (@hamzadhamiya) on CodePen.
Axes are simple to draw, just add simple line strokes with certain stroke-width and color. Make sure they are at the end of SVG document.
<g class='xaxes'>
    <line x1='0' x2='0' y1='0' y2='300' style="stroke:#222;stroke-width:2"></line>
</g>
<g class='yaxes'>
    <line x1='0' x2='600' y1='300' y2='300' style="stroke:#222;stroke-width:2"></line>
</g>
Next step is to use SVG.js, it is a light weight Javascript library to play with SVG. One of the feature of this library is to add group (<g>) in SVG document. Then add items in that group. I used a few lines to add vertical guides and then a few more for horizontal. I coded 50px gap for vertical as well as horizontal guides, this makes a perfect grid.

SVG.JS documents tells that initially SVG is considered as 100% by 100% in size. To get a fixed width and height add size in SVG and create a group for guides.
var chart = SVG('bar-graph'),
    guides = chart.group();
chart.size(602, 302);
Now its time to add a variable for vertical gap and then find the number of guides by dividing the gap with the width of chart. Then a loop to create those guides.
// Vertical Guides
var vGuidesGap = 50,
  firstVGuide = 50,
  numberVGuides = 600 / vGuidesGap;
for (var i = 0; i < numberVGuides; i++) {
  guides.line(firstVGuide, 0, firstVGuide, 300).stroke({
    width: 1,
    color: '#ddd'
  });
  firstVGuide += vGuidesGap;
}
Same procedure would be followed for horizontal lines but they will be added from the bottom of the chart instead of the top. To do this, decrease the y-component of each success line.
firstHGuide -= hGuidesGap;
I left some space on left and bottom of SVG document for labels. Use text tag for labels, put them in a group for easy customization.

Add points

Lets start plotting the points. We'll use circle that is a native element of SVG. Circle is quite simple to use, set cx and cy for positions, fill for inner colour and r for radius. Every circle tag contains a data attribute, to be shown when mouse is near to circle.

In my previous blog post I discussed the way to trigger a function when mouse is around any element. I guess you read that, anyway. Graph or chart is useless until user able to get the values in a visible way. Web devs have figured it out and a very productive solution came around of showing up a tooltip to display the point. Well, my tooltip doesn't work in a automatic way, instead a data attribute is set-up for that tooltip.

Coding is quite simple:

function isAround(element, radius, mouse) {
  var elemTop = element.offset().top - radius,
    elemLeft = element.offset().left - radius,
    elemWidth = elemLeft + element.outerWidth() + (2*radius),
    elemHeight =elemTop +  element.outerHeight() + (2*radius),
    mouseLeft = mouse.pageX,
    mouseTop = mouse.pageY;
  console.log(elemTop + ' ' + elemHeight + ' ' + mouseTop)
  return (mouseLeft > elemLeft && mouseLeft < elemWidth && mouseTop > elemTop && mouseTop < elemHeight)
}
A bunch of conditions using simple maths to make sure that mouse is around the element. A few more lines of codes to show tooltip above the point.

Bar Graph

See the Pen Demo for bar graph by Mohammad Hamza Dhamiya (@hamzadhamiya) on CodePen.
This time I used a simple collection of data in the form of array and looped through it create the graph. Some maths and rest is handled by svg.js. To align the bars in x-axis, there are three major components to do that: width of SVG doc, width of bar and the gap.

Lets break it down, width of SVG is 600 and the gap is set to 50. Then to get the width of each bar, use maths.

  var remainWidth = w - (lengthOfData * gap),
      barWidth = remainWidth / lengthOfData;
w is the width and lengthOfData is the number of item in the array. Next is to set the height and since we know that, to position the elements in SVG we need left and top co-ordinates so we need co-ordinates to stick the bar to the bottom. Otherwise something like this will appear.

To make it stick to the ground just subtract the height of bar from the height of SVG doc and we will get the correct ordinate.

    var barHeight=(data[i]/maxHeight)*h,
        barToGround=h-barHeight;
This one accepts positive values only, share your thoughts with me to display negative values and I will update the article.

Animate and Redraw

SVG.js provides animate method to animate certain attribute of a SVG element, however I used a bit help of jQuery here.
See the Pen BoGpeB by Mohammad Hamza Dhamiya (@hamzadhamiya) on CodePen.
Instead of using the SVG.js animation API, I used jQuery for that. The reason is quite simple: its easy. Well, the things starts by setting up the whole chart but the height of the rect component because that is actually going to animate and change over button click. Secondly, I've left some space under the axes for the text of the players' names.
players.line(0, 0, 0, h - 50).stroke({
    width: 2,
    fill: '#666'
});
players.line(0, h - 50, w, h - 50).stroke({
    width: 2,
    fill: '#666'
});
After axis, I placed the players' names. The thing to note is, that I put the name of the player and its properties in each array on same index, because its really helps to put the things in order. While putting the names, redraw and then animating the stuff, if things in order you can do this with each function of jQuery or simple loop in JS.

To animate the bars correctly, what matters is the bars should grow from bottom, instead from top because it seems pretty. To make this, I just used a simple trick.
$(this).css('y', h - 50).animate({
        height: barHeight,
        y: barToGround
      },1000);
Each time the bars need to change, I put them to ground using .css() method. It doesn't animate the property and then using the animate() method, we let them grow from bottom.

Fallbacks

According to SVG.js docs, library assumes that SVG is supported. To check the browser support, use the following syntax for checking the support.
if (SVG.supported) {
    // If supported
} else {
    // If not supported
}
If you are not using SVG.js then simple add a line of text inside the SVG tag and it will be displayed when browser is not supporting the inline SVG.

There are 6 ways of putting SVG in DOM. There are different ways for each of them. For me, its inline that I use often and above ones are some of the fallbacks for them.

Is there any thoughts coming, throw a comment below.
Blogger

2013-2016 Copyright Blogger E\ver . Coded, managed and founded by Mohammad Hamza (@hamzadhamiya) . Hosted on Blogger and fonts used are Raleway and Open Sans.