DotNetCurry Logo

Creating Charts using HTML5 and SVG

Posted by: Mahesh Sabnis , on 3/9/2014, in Category HTML5 & JavaScript
Views: 16980
Abstract: SVG images have been around since 1999 and now with HTML5 natively adopting it with the 'svg' tag, it is seeing a revival. This article demonstrates how to create a Bar and Line chart in HTML5 using SVG

Web Development has changed a lot. End-users consistently demand rich UI functionality in their web applications (either in browser or on the devices) with some dazzling graphics and animations. Thankfully with some new features provided in HTML5, web developers can achieve these requirements and much more with ease.

One the new features supported in HTML5 is the support for inline Scalable Vector Graphics (SVG). Essentially SVG itself is not a new feature. SVG images have been around since 1999 and now with HTML5 natively adopting it with the <svg> tag, it is seeing a revival. In true sense, SVG’s are awesome. They are vector, they can be compressed, scaled and they are textual in nature composed of some XML tags consisting of strokes, fills and some graphic instructions. Infact if you have observed the HTML5 logo, it originates as an SVG file. Open it in any resolution and it beautifully scales up without losing its clearness and sharpness.

 

 

Some advantages of using SVG graphics are:

  • Images are scalable
  • Images can be printed with at any resolution with great quality
  • Images can be zoomed to any level

..and many more

There are some considerable differences between HTML Canvas object and SVG. One of the major operational difference is the graphics created using Canvas is resolution dependent., whereas SVG is vector in nature. No pixels are involved in creating SVG’s. They are constructed by drawing from point to point.

Charting using SVG

From the very day I started delivering trainings on HTML5, I have been getting queries about creating charts in HTML5. Although there are some charting kits available, my audiences are always curious to know how to build charts from groundup. So I finally decided to write something about it and cook up a solution. To get this done I read a very nice article by one of my colleagues Suprotim Agarwal, for creating charts using HTML 5 canvas. You can find the article Bring Your Charts to Life with HTML5 Canvas and JavaScript. Based on this article, I have presented a charting solution using SVG, instead of HTML 5.

Step 1: Open Visual Studio 2012/2013 (any other HTML5 editors can also be used here, but thanks to Visual Studio 2012/2013 for some great intellisense for HTML5 and JavaScript.) and create a new ASP.NET Empty project. In this project add a HTML page and name it as ‘Chart_SVG.html’.

Step 2: In this page add the following HTML elements in body:

<div  id="dvcontainer">
    <svg id="svgcontainer" height="400" width="600">
    </svg>
</div>
<div id="dvcharttype">
        <input type="radio" id="rdbarchart" name="Chart" />Bar Chart
        <br />
        <input type="radio" id="rdpointchart" name="Chart" />Point Chart
</div>

The above markup defines a <svg> element. This will be used as a container for the elements required for drawing charts.

Step 3: In the example, the population chart is created based upon an array. The data store array is declared as shown below:

var populationArray = new Array();
populationArray[0] = "MH,10000";
populationArray[1] = "KR,12000";
populationArray[2] = "AP,9000";
populationArray[3] = "KL,7000";
populationArray[4] = "CH,5000";
populationArray[5] = "MP,9500";
populationArray[6] = "GJ,9700";
populationArray[7] = "OR,8800";
populationArray[8] = "RJ,8600";
populationArray[9] = "CH,9200";

Step 4: For plotting charts, we need to define an X and Y axis and set the dimensions for them; so declare the following variables:

//Global Declaration Here
var svg; //The declaration for SVG tag

//The Chart dimensional settings
var svgcWidth, svgcHeight, svgcMargin, svgcSpace;
var svgcMarginSpace, svgcMarginHeight;

//The bar Properties Declaration
var bcWidth, bcMargin, totalChartBars, maximumDataValue, bcWidthMargin;

//The Axis Property
var totalLabelOnYAxis;
 
//Ends Here

Step 5: To define the Chart dimensional properties for height and width, the following calculations are specified:

//Function to specify   Chart settings
function barChartSettings() {
svgcMargin = 20;
svgcSpace = 60;

svgcHeight = svg.height.baseVal.value - 2 * svgcMargin - svgcSpace;
svgcWidth = svg.width.baseVal.value - 2 * svgcMargin - svgcSpace;

svgcMarginSpace = svgcMargin + svgcSpace;
svgcMarginHeight = svgcMargin + svgcHeight;

//The Bar Properties
bcMargin = 15;
totalChartBars = populationArray.length;
bcWidth = (svgcWidth / totalChartBars) - bcMargin;

//Maximum value to plot on chart

maximumDataValue = 0;
for (var i = 0; i < totalChartBars; i++) {
    var arrVal = populationArray[i].split(",");
    var barVal = parseInt(arrVal[1]);
    if (parseInt(barVal) > parseInt(maximumDataValue))
        maximumDataValue = barVal;
}

totalLabelOnYAxis = 10;
}
//Ends Here

Step 6: To draw X and Y axis, the Line element must be added in the SVG dynamically. The code is as shown below:

//Function to Draw X and Y Axis
function drawXYAxis(x1, y1, x2, y2) {

    var dataAxis = document.createElementNS("http://www.w3.org/2000/svg", 'line');
    dataAxis.setAttribute("x1", x1);
    dataAxis.setAttribute("y1", y1);
    dataAxis.setAttribute("x2", x2);
    dataAxis.setAttribute("y2", y2);
    dataAxis.style.stroke = "black";
    dataAxis.style.strokeWidth = "5px";
    svg.appendChild(dataAxis);

}
//Ends Here

Step 7: Once the X and Y axis are drawn, we need to define markers on it. As per your Data Store, we need to have StateName on the X axis and Population value on the Y axis. To display the markers, we need to read the Data Store array and accordingly add TextNode in the SVG dynamically as shown here:

//Function to Draw Markers on the Axis
function drawAxisMarkers() {
var numMarkers = parseInt(maximumDataValue/totalLabelOnYAxis);

// On y Axis
for (var i = 0; i < totalLabelOnYAxis +1; i++) {
    markerVal = i * numMarkers;
    markerValHt = i * numMarkers * svgcHeight;
    var xMarkers = svgcMarginSpace - 5;
    var yMarkers = svgcMarginHeight - (markerValHt / maximumDataValue);

    textelement = document.createElementNS("http://www.w3.org/2000/svg", 'text');
    textelement.setAttribute('dx', xMarkers-40);
    textelement.setAttribute('dy',yMarkers);
    txtnode = document.createTextNode(markerVal);
    textelement.appendChild(txtnode);
    svg.appendChild(textelement);
}

//On x Axis
for (var i = 0; i < totalChartBars; i++) {
    arrVal = populationArray[i].split(",");
    name = arrVal[0];
    markerXPosition = svgcMarginSpace + bcMargin + (i * (bcWidth + bcMargin)) + (bcWidth / 2);
    markerYPosition = svgcMarginHeight + 20;

    textelement = document.createElementNS("http://www.w3.org/2000/svg", 'text');
    textelement.setAttribute('dx', markerXPosition);
    textelement.setAttribute('dy', markerYPosition);
    txtnode = document.createTextNode(name);
    textelement.appendChild(txtnode);
    svg.appendChild(textelement);
}
}
//Ends Here

Step 8: Lets now complete the process of drawing axis and the markers by writing the function which will call drawXYAxis() twice for X and Y axis and the drawAxisMarkers() for adding markers on them:

//Method to Draw Axis Label
function drawAxisLableAndMarkers() {
    //Y-Axis
    drawXYAxis(svgcMarginSpace, svgcMarginHeight, svgcMarginSpace, svgcMargin);
    //X-Axis
    drawXYAxis(svgcMarginSpace, svgcMarginHeight, svgcMarginSpace + bcWidth+500, svgcMarginHeight);
    drawAxisMarkers();
}
//Ends Here

Step 9: To generate Bar charts, we need to add rectangles in SVG. Similarly for the Point charts we need to add Ellipses in SVG. The methods for adding both are as shown here:

//Method to Draw rectangle
function drawRectangleForChart(x,y,wd,ht,fill) {
    var rect = document.createElementNS("
http://www.w3.org/2000/svg", 'rect');
    rect.setAttributeNS(null, 'x', x);
    rect.setAttributeNS(null, 'y', y);
    rect.setAttributeNS(null, 'width', wd);
    rect.setAttributeNS(null, 'height', ht);
    rect.setAttributeNS(null, 'fill', "red");
    svg.appendChild(rect);
}
//Ends Here

//Method to Draw Ellipse for the Point Chart
function drawEllipse(x,y,rx) {
    var circle = document.createElementNS("
http://www.w3.org/2000/svg", 'circle');
    circle.setAttributeNS(null, 'cx', x);
    circle.setAttributeNS(null, 'cy', y);
    circle.setAttributeNS(null, 'r', rx);
    circle.setAttributeNS(null, 'fill', "red");
    svg.appendChild(circle);
}
//Ends Here

Step 10: To generate the dimensions for rectangle and ellipse, we have to read the data store for population and read the population for each state. We have to set the coordinates by the height of the rectangle and the dimension of the ellipse, as below:

//Function to draw barchart for all entries in the Population Array
function drawChartWithCalculation(chart) {

for (var i = 0; i < totalChartBars; i++) {
    var arrchartVal = populationArray[i].split(",");
    bcVal = parseInt(arrchartVal[1]);
    bcHt = (bcVal * svgcHeight / maximumDataValue);
    bcX = svgcMarginSpace + (i * (bcWidth + bcMargin)) + bcMargin+10;
    bcY = (svgcMarginHeight - bcHt - 2);
    switch (chart)
    {
        case "Bar":
            drawRectangleForChart(bcX, bcY, bcWidth, bcHt, true);
            break;
        case "Point":
            drawEllipse(bcX, bcY, 5, 5);
            break;
    }
}
}
//Ends Here

Step 11: Add the following code to clear the chart. Since the Chart dimensions with markers and axis are children of SVG, we need to clear them by writing the following code:

//function to clear the SVG contents
function clearGraph() {
    while (svg.lastChild) {
        svg.removeChild(svg.lastChild);
    }
}
//Ends Here

Step 12: Now let’s add a method which will provide the UI interaction for the end-user to select the type of chart (either Bar or Point) they want to draw:

//Function to Draw Barchart
function drawBarChart() {
svg = document.getElementsByTagName('svg')[0];

var rdbarchart = document.getElementById('rdbarchart');
rdbarchart.addEventListener('click', function () {
    clearGraph();
    barChartSettings();
    drawAxisLableAndMarkers();

    drawChartWithCalculation("Bar");
}, false);
var rdpointchart = document.getElementById('rdpointchart');
rdpointchart.addEventListener('click', function () {
    clearGraph();
    barChartSettings();
    drawAxisLableAndMarkers();
    drawChartWithCalculation("Point");
}, false);
}
//Ends Here

The above method reads the svg element from the DOM and it also subscribes to the click event of the radio buttons. So based upon the chart type selections, the code will be executed and the chart will be created.

Finally pass the method to the load event of the window as shown here:

window.onload = drawBarChart;

Load the page in the browser and you should see the following:

blank-svg-chart

 

Select the Bar Chart:

svg-html5-bar-chart

Or select the Point Chart to see the following:

svg-html5-point-chart

Conclusion: As Web Desginers and developers, you should start experimenting with SVG graphics in addition to using the Canvas element. Although not suitable for photographs, they are very useful to create complex graphics and even some cool UI .

See a Live Demo here. To get the source code, open this page, Right Click and view source

Was this article worth reading? Share it with fellow developers too. Thanks!
Share on Google+
Further Reading - Articles You May Like!
Author
Mahesh Sabnis is a DotNetCurry author and Microsoft MVP having over 17 years of experience in IT education and development. He is a Microsoft Certified Trainer (MCT) since 2005 and has conducted various Corporate Training programs for .NET Technologies (all versions). Follow him on twitter @maheshdotnet


Page copy protected against web site content infringement 	by Copyscape




Feedback - Leave us some adulation, criticism and everything in between!
Comment posted by Developer Wun on Thursday, December 4, 2014 10:54 PM
Great Article!  I am using your to build a framework for Charts and Graphs in our ASP.Net MVC App.  Good job, and thanks man!