Skip to content

Instantly share code, notes, and snippets.

@samarpanda
Last active August 29, 2015 14:21
Show Gist options
  • Save samarpanda/d035b919cee62f32d811 to your computer and use it in GitHub Desktop.
Save samarpanda/d035b919cee62f32d811 to your computer and use it in GitHub Desktop.
Line graph using HTML5 Canvas
//http://jsbin.com/bajebo/2/edit?output
var CanvasChart = function() {
var ctx;
var margin = {
top: 40,
left: 75,
right: 0,
bottom: 75
};
var chartHeight, chartWidth, yMax, xMax, data;
var maxYValue = 0;
var ratio = 0;
var renderType = {
lines: 'lines',
points: 'points'
};
var render = function(canvasId, dataObj) {
data = dataObj;
getMaxDataYValue();
var canvas = document.getElementById(canvasId);
chartHeight = 600; //canvas.attr('height');
chartWidth = 800; //canvas.attr('width');
xMax = chartWidth - (margin.left + margin.right);
yMax = chartHeight - (margin.top + margin.bottom);
ratio = yMax / maxYValue;
ctx = canvas.getContext("2d");
renderChart();
}
function getMaxDataYValue() {
maxYValue = 308.7;
}
var renderChart = function() {
renderBackground();
renderText();
renderLinesAndLabels();
//render data based upon type of renderType(s) that client supplies
if (data.renderTypes == undefined || data.renderTypes == null) data.renderTypes = [renderType.lines];
for (var i = 0; i < data.renderTypes.length; i++) {
renderData(data.renderTypes[i]);
}
}
var renderBackground = function() {
var lingrad = ctx.createLinearGradient(margin.left, margin.top, xMax - margin.right, yMax);
lingrad.addColorStop(0.0, '#D4D4D4');
lingrad.addColorStop(0.2, '#fff');
lingrad.addColorStop(0.8, '#fff');
lingrad.addColorStop(1, '#D4D4D4');
ctx.fillStyle = lingrad;
ctx.fillRect(margin.left, margin.top, xMax - margin.left, yMax - margin.top);
ctx.fillStyle = 'black';
}
var renderText = function renderText() {
var labelFont = (data.labelFont != null) ? data.labelFont : '20pt Arial';
ctx.font = labelFont;
ctx.textAlign = "center";
//Title
var txtSize = ctx.measureText(data.title);
ctx.fillText(data.title, (chartWidth / 2), (margin.top / 2));
//X-axis text
txtSize = ctx.measureText(data.xLabel);
ctx.fillText(data.xLabel, margin.left + (xMax / 2) - (txtSize.width / 2), yMax + (margin.bottom / 1.2));
//Y-axis text
ctx.save();
ctx.rotate(-Math.PI / 2);
ctx.font = labelFont;
ctx.fillText(data.yLabel, (yMax / 2) * -1, margin.left / 4);
ctx.restore();
}
var renderLinesAndLabels = function renderLinesAndLabels() {
//Vertical guide lines
var yInc = yMax / data.dataPoints.length;
var yPos = 0;
var yLabelInc = (maxYValue * ratio) / data.dataPoints.length;
var xInc = xMax / data.dataPoints.length;
var xPos = margin.left;
for (var i = 0; i < data.dataPoints.length; i++) {
yPos += (i == 0) ? margin.top : yInc;
//Draw horizontal lines
drawLine(margin.left, yPos, xMax, yPos, '#E8E8E8');
//y axis labels
ctx.font = (data.dataPointFont != null) ? data.dataPointFont : '10pt Calibri';
var txt = Math.round(maxYValue - ((i == 0) ? 0 : yPos / ratio));
var txtSize = ctx.measureText(txt);
ctx.fillText(txt, margin.left - ((txtSize.width >= 14) ? txtSize.width : 10) - 7, yPos + 4);
//x axis labels
txt = data.dataPoints[i].x;
txtSize = ctx.measureText(txt);
ctx.fillText(txt, xPos, yMax + (margin.bottom / 3));
xPos += xInc;
}
//Vertical line
drawLine(margin.left, margin.top, margin.left, yMax, 'black');
//Horizontal Line
drawLine(margin.left, yMax, xMax, yMax, 'black');
}
var drawLine = function drawLine(startX, startY, endX, endY, strokeStyle, lineWidth) {
if (strokeStyle != null) ctx.strokeStyle = strokeStyle;
if (lineWidth != null) ctx.lineWidth = lineWidth;
ctx.beginPath();
ctx.moveTo(startX, startY);
ctx.lineTo(endX, endY);
ctx.stroke();
ctx.closePath();
}
var renderData = function renderData(type) {
var xInc = xMax / data.dataPoints.length;;
var prevX, prevY = 0;
for (var i = 0; i < data.dataPoints.length; i++) {
var pt = data.dataPoints[i];
var ptY = (maxYValue - pt.y) * ratio;
if (ptY < margin.top) ptY = margin.top;
var ptX = (i * xInc) + margin.left;
if (i > 0 && type == renderType.lines) {
//Draw connecting lines
drawLine(ptX, ptY, prevX, prevY, 'black', 2);
}
if (type == renderType.points) {
var radgrad = ctx.createRadialGradient(ptX, ptY, 8, ptX - 5, ptY - 5, 0);
radgrad.addColorStop(0, 'Green');
radgrad.addColorStop(0.9, 'White');
ctx.beginPath();
ctx.fillStyle = radgrad;
//Render circle
ctx.arc(ptX, ptY, 8, 0, 2 * Math.PI, false)
ctx.fill();
ctx.lineWidth = 1;
ctx.strokeStyle = '#000';
ctx.stroke();
ctx.closePath();
}
prevX = ptX;
prevY = ptY;
}
}
return {
renderType: renderType,
render: render
};
}();
var dataDef = {
title: "US Population Chart",
xLabel: 'Year',
yLabel: 'Population (millions)',
labelFont: '19pt Arial',
dataPointFont: '10pt Arial',
renderTypes: [CanvasChart.renderType.lines, CanvasChart.renderType.points],
dataPoints: [{
x: '1790',
y: 3.9
}, {
x: '1810',
y: 7.2
}, {
x: '1830',
y: 12.8
}, {
x: '1850',
y: 23.1
}, {
x: '1870',
y: 36.5
}, {
x: '1890',
y: 62.9
}, {
x: '1910',
y: 92.2
}, {
x: '1930',
y: 123.2
}, {
x: '1950',
y: 151.3
}, {
x: '1970',
y: 203.2
}, {
x: '1990',
y: 248.7
}, {
x: '2010',
y: 308.7
}]
};
CanvasChart.render('canvas', dataDef);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment