Skip to content

Instantly share code, notes, and snippets.

@paitonic
Created March 24, 2019 07:13
Show Gist options
  • Save paitonic/84c2a59424256748212ebffe92ec097b to your computer and use it in GitHub Desktop.
Save paitonic/84c2a59424256748212ebffe92ec097b to your computer and use it in GitHub Desktop.
svg-charts.js
<html>
<head>
<title>SVG Charts</title>
</head>
<body>
<div id="svg-bar"></div>
<div id="svg-area"></div>
<div id="svg-line"></div>
<script src="svg-charts.js"></script>
</body>
</html>
// See Feature Scaling formula at https://en.wikipedia.org/wiki/Normalization_(statistics)
// Also, here is good explanation why it's needed http://chimera.labs.oreilly.com/books/1230000000345/ch07.html#_apples_and_pixels
function rescale(val, minValue, maxValue, fromRange, toRange) {
return fromRange + ((val - minValue) * (toRange - fromRange)) / (maxValue - minValue);
}
function move(x, y) {
return 'M' + x + ',' + y;
}
function line(x, y) {
return 'L' + x + ',' + y;
}
// generates path for a line chart.
var lineChart = function(data, dimensions, options, containerId) {
var totalDataPoints = data.length,
maxValue = Math.max.apply(null, data),
minValue = Math.min.apply(null, data),
path = move(scaleX(0), scaleY(data[0]));
for (var i = 1, max = data.length; i < max; i += 1) {
path += line(scaleX(i), scaleY(data[i]));
}
function scaleX(valueIdx) {
return valueIdx * (dimensions.width / (totalDataPoints-1));
}
function scaleY(val) {
if (minValue === maxValue) {
return 0;
}
console.log(rescale(val, minValue, maxValue, 0, dimensions.height))
return dimensions.height - rescale(val, minValue, maxValue, 0, dimensions.height);
}
// dom
var svgLineChart = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
svgLineChart.setAttribute('height', dimensions.height);
svgLineChart.setAttribute('width', dimensions.width);
line = document.createElementNS('http://www.w3.org/2000/svg', 'path');
line.setAttribute('d', path);
line.setAttribute('fill', 'none');
line.setAttribute('stroke', '#7CB5EC');
svgLineChart.appendChild(line);
var container = document.getElementById(containerId);
container.appendChild(svgLineChart);
}
// lineChart([1, 2, 3, 4, 5], {height: 250, width: 250}, {}, 'svg-line');
// lineChart([5, 4, 3, 2, 1], {height: 250, width: 250}, {}, 'svg-line');
lineChart([2, 4, 1, 5, 3], {height: 250, width: 250}, {}, 'svg-line');
// lineChart([5, 5, 5, 5, 5], {height: 250, width: 250}, {}, 'svg-line');
var areaChart = function(data, dimensions, options, containerId) {
var totalDataPoints = data.length,
maxValue = Math.max.apply(null, data),
minValue = Math.min.apply(null, data),
path = 'M' + '0' + ',' + dimensions.height; // move to the beginning of the chart
// connect left and right bottom edges so that its possible to create
// an area effect on chart by setting fill="#color" attribute on <path>
var pathEnding = 'L' + String(dimensions.width) + ',' + String(dimensions.height) + 'Z';
data.forEach(function(val, idx) {
path += 'L' + scaleX(idx) + ',' + scaleY(val);
})
function scaleX(valueIdx) {
return valueIdx * (dimensions.width / (totalDataPoints-1));
}
function scaleY(val) {
if (minValue === maxValue) {
return 0;
}
console.log(rescale(val, minValue, maxValue, 0, dimensions.height))
return dimensions.height - rescale(val, minValue, maxValue, 0, dimensions.height);
}
// dom
var svgAreaChart = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
svgAreaChart.setAttribute('height', dimensions.height);
svgAreaChart.setAttribute('width', dimensions.width);
area = document.createElementNS('http://www.w3.org/2000/svg', 'path');
area.setAttribute('d', path + pathEnding);
area.setAttribute('fill', '#CCD5DE');
area.setAttribute('stroke', '#7CB5EC');
line = document.createElementNS('http://www.w3.org/2000/svg', 'path');
line.setAttribute('d', path);
line.setAttribute('fill', 'none');
line.setAttribute('stroke', '#7CB5EC');
svgAreaChart.appendChild(area);
svgAreaChart.appendChild(line);
var container = document.getElementById(containerId);
container.appendChild(svgAreaChart);
}
// areaChart([5, 5, 5, 5, 5], {height: 250, width: 250}, {}, 'svg-line-area');
// areaChart([1, 2, 3, 4, 5], {height: 250, width: 250}, {}, 'svg-area');
areaChart([2, 4, 1, 5, 3], {height: 250, width: 250}, {}, 'svg-line');
var barChart = function(data, dimensions, containerId) {
var totalDataPoints = data.length,
maxValue = Math.max.apply(null, data),
barHeight,
barRightMargin = 1,
barWidth = Math.round((dimensions.width / totalDataPoints) - (barRightMargin * (totalDataPoints-1) / totalDataPoints)),
barX = 0,
barY,
rectangles = [];
data.forEach(function(val, idx) {
barHeight = val / maxValue * dimensions.height;
barY = dimensions.height - barHeight;
rectangles.push({x: barX, y: barY, width: barWidth, height: barHeight});
barX = barX + barWidth + barRightMargin;
});
rectangles.forEach(function(rectangle) {
console.log('<rect x="' + rectangle.x + '" y="' + rectangle.y + '" width="' + rectangle.width + '" height="' + rectangle.height + '"/>');
});
// dom
var svgContainer = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
svgContainer.setAttribute('height', dimensions.height);
svgContainer.setAttribute('width', dimensions.width);
var rect;
rectangles.forEach(function(rectangle) {
rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
rect.setAttribute('x', rectangle.x);
rect.setAttribute('y', rectangle.y);
rect.setAttribute('width', rectangle.width);
rect.setAttribute('height', rectangle.height);
svgContainer.appendChild(rect);
});
var container = document.getElementById(containerId);
container.appendChild(svgContainer);
return rectangles;
}
barChart([1, 2, 3, 4, 5], {height: 250, width: 250}, 'svg-bar');
// barChart([1, 1, 1, 1, 1], {height: 250, width: 250}, 'svg-bar');
// barChart([5, 1, 2, 4, 3], {height: 250, width: 250}, 'svg-bar');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment