code everywhere

drawing line charts with SVG

posted on April 25, 2015, 12:13 am in js

An web page line chart based on SVG.

The Code

/*
 * LineChart (April 25 2015)
 * Copyright 2015, http://codeeverywhere.ca
 * Licensed under the MIT license.
 */
(function() {
    var 
lineChart = function(obj) {
        var 
w = obj.width || document.getElementById('test').offsetWidth;
        var 
h = obj.height || 250;
        var 
background = obj.background || "#fff";
        var 
showPoints = (obj.showPoints === undefined) ? false : obj.showPoints;

        
//if "auto", use offsetWidth
        
if (w == "auto") w = document.getElementById('test').offsetWidth;

        
//create svg elem
        
var svgns = "http://www.w3.org/2000/svg";
        var 
chart = document.createElementNS(svgns, "svg:svg");
        
chart.setAttribute("width", w);
        
chart.setAttribute("height", h);

        
//calculate max, min values
        
var maxX = 0,
            
maxY = 0,
            
minX = obj.lines[0].data[0][0],
            
minY = obj.lines[0].data[0][1];
        for (var 
y = 0; y < obj.lines.length; y++) {
            var 
values = obj.lines[y].data;
            for (var 
x = 0; x < values.length; x++) {
                
maxX = (values[x][0] > maxX) ? values[x][0] : maxX;
                
maxY = (values[x][1] > maxY) ? values[x][1] : maxY;
                
minX = (values[x][0] <= minX) ? values[x][0] : minX;
                
minY = (values[x][1] <= minY) ? values[x][1] : minY;
            }
        }

        
//for each line
        
for (var y = 0; y < obj.lines.length; y++) {
            
//get values
            
var values = obj.lines[y].data;

            
//if independent, find relative max, min values
            
if (obj.lines[y].independent) {
                var 
maxX = 0,
                    
maxY = 0,
                    
minX = obj.lines[0].data[0][0],
                    
minY = obj.lines[0].data[0][1];
                for (var 
x = 0; x < values.length; x++) {
                    
maxX = (values[x][0] > maxX) ? values[x][0] : maxX;
                    
maxY = (values[x][1] > maxY) ? values[x][1] : maxY;
                    
minX = (values[x][0] <= minX) ? values[x][0] : minX;
                    
minY = (values[x][1] <= minY) ? values[x][1] : minY;
                }
            }

            var 
circles = [];

            
//get start positions
            
var posX = 10 + ((values[0][0] - minX) / (maxX - minX)) * (w - 20);
            var 
posY = 10 + (1 - (values[0][1] / maxY)) * (h - 20);

            var 
linePrefix = "M " + posX + " " + posY;
            var 
fillPrefix = "M " + posX + " " + (h - 10);

            var 
coords = "";

            
//calculate points
            
for (var x = 0; x < values.length; x++) {
                
posX = 10 + ((values[x][0] - minX) / (maxX - minX)) * (w - 20);
                
posY = 10 + (1 - (values[x][1] / maxY)) * (h - 20);
                
coords += " L " + posX + " " + posY;
                
circles.push([posX, posY]);
            }

            
//draw path
            
var path = document.createElementNS(svgns, "path");
            
path.setAttribute("d", linePrefix + coords);
            
path.setAttribute("stroke", obj.lines[y].color);
            
path.setAttribute("stroke-width", obj.lines[y].strokeWidth);
            
path.setAttribute("fill", "none");
            
chart.appendChild(path);

            var 
fillTail = " L " + (posX) + " " + (h - 10);

            var 
path = document.createElementNS(svgns, "path");
            
path.setAttribute("d", fillPrefix + coords + fillTail);
            
path.setAttribute("fill", obj.lines[y].fill);
            
chart.appendChild(path);

            
//draw points on line
            
if (showPoints) {
                for (var 
x = 0; x < values.length; x++) {
                    var 
circle = document.createElementNS(svgns, "circle");
                    
circle.setAttribute("cx", circles[x][0]);
                    
circle.setAttribute("cy", circles[x][1]);
                    
circle.setAttribute("r", "4");
                    
circle.setAttribute("stroke-width", Math.floor(obj.lines[y].strokeWidth / 3));
                    
circle.setAttribute("stroke", obj.lines[y].color);
                    
circle.setAttribute("fill", background);
                    
circle.setAttribute("onmouseout", "evt.target.setAttribute('r', '4');");
                    
circle.setAttribute("onmouseover", "evt.target.setAttribute('r', '6');");

                    var 
title = document.createElementNS(svgns, "title");
                    var 
titleText;
                    if (
obj.lines[y].title === undefined)
                        
titleText = "(" + values[x][0] + ", " + values[x][1] + ")";
                    else
                        
titleText = obj.lines[y].title(values[x][0], values[x][1]);

                    var 
text = document.createTextNode(titleText);
                    
title.appendChild(text);
                    
circle.appendChild(title);

                    
chart.appendChild(circle);
                }
            }

            
//append to doc
            
var c = document.getElementById(obj.targetId);
            
c.style.width = w + "px";
            
c.style.height = h + "px";
            
c.appendChild(chart);
        }
    };
    
//add to window var
    
window.lineChart = lineChart;
})();

example usage

Add the script to your page, then call lineChart(obj), ex:

var obj = {
    
targetId : "test", // target <div>
    
width : "auto",
    
height : 350,
    
background : "#fff",
    
showPoints : true,
    
lines : [{
        
color : "#d22fff",
        
title : function(x, y){ return "x=" + x + ", y=" + y; },
        
independent: false, //draw line indepened of others
        
fill : "#e896ff",
        
strokeWidth : "6",
        
data : [ [3, 65], [4, 59], [5, 80] ]
    },
    {
        
color : "#baff39",
        
independent: false,
        
fill : "#ddff9e",
        
strokeWidth : "6",
        
data : [ [0, 35], [1, 43], [2, 33], [3, 13], [4, 22], [5, 35], [6, 20] ]
    },
    {
        
color : "#445546",
        
independent: false,
        
fill : "none",
        
strokeWidth : "6",
        
data : [ [1, 22], [2, 21], [3, 20], [4, 22], [5, 28], [6,2] ]
    }]
};
lineChart(obj);

Online Demo

Try it out jsfiddle.net/h3j0sn05/

recent posts

< back
find something helpful? send us some coin BTC 19u6CWTxH4cH9V2yTfAemA7gmmh7rANgiv

(ad) Need Hosting? Try Linode, VPS Starting from $5

privacy policy