Created
April 10, 2015 20:55
-
-
Save cstrelioff/b7a3bb7c2a2a56c23d49 to your computer and use it in GitHub Desktop.
responsive svg bar chart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>responsive svg bar chart</title> | |
<meta charset="utf-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<!-- styles: should have reset.css first --> | |
<link rel="stylesheet" href= "reset.css"> | |
<link rel="stylesheet" href= "main.css"> | |
</head> | |
<body> | |
<div id="fullpage"> | |
<header role="banner"> | |
<h1>header</h1> | |
<nav role="navigation"> | |
</nav> | |
</header> | |
<article id="mainviz"> | |
</article> | |
<aside role="complementary"> | |
<h1>data</h1> | |
<div class="radio-toolbar"> | |
<input type="radio" id="radio1" name="data" value="a" checked/> | |
<label for="radio1">set a</label> <br> | |
<input type="radio" id="radio2" name="data" value="b"/> | |
<label for="radio2">set b</label> | |
</div> | |
</aside > | |
<footer role="contentinfo"> | |
<h1>footer</h1> | |
</footer> | |
</div> <!-- end fullpage --> | |
<!-- javascript links --> | |
<script src="main.js"></script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
header, article, aside, footer, ul, li, p { | |
-webkit-box-sizing: border-box; | |
-moz-box-sizing: border-box; | |
box-sizing: border-box; | |
} | |
#fullpage { | |
max-width: 62em; | |
margin: auto; | |
} | |
body { | |
font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; | |
} | |
header, article, aside, footer { | |
padding: 10px 1em; | |
margin: 0 5% 10px; | |
} | |
header { | |
margin-top: 10px; | |
} | |
article { | |
min-height: 10em; | |
border-left: 5px solid black; | |
} | |
aside { | |
min-height: 5em; | |
border-left: 5px solid black; | |
} | |
h1 { | |
font-size: 2em; | |
} | |
h2 { | |
font-size: 1.5em; | |
} | |
h1, h2 { | |
font-weight: bold; | |
margin: 5px 0; | |
} | |
p { | |
font-size: 1em; | |
margin: 5px 0; | |
} | |
strong { | |
font-weight: bold; | |
} | |
/* spacing for radio buttons | |
* | |
* credit: http://stackoverflow.com/questions/4641752/css-how-to-style-a-selected-radio-buttons-label | |
* | |
*/ | |
.radio-toolbar input[type="radio"] { | |
display: none; | |
} | |
.radio-toolbar label { | |
display: inline-block; | |
padding: 4px 11px; | |
margin: 10px 0px; | |
border: 1px solid #bbb; | |
border-radius: 5px; | |
font-size: 1.2em; | |
} | |
.radio-toolbar input[type="radio"]:checked + label { | |
background-color: #bbb; | |
border: 2px solid black; | |
} | |
/* Chart */ | |
.chart { | |
width: 98%; | |
padding: 10px 2% 10px 0; | |
} | |
.chart rect:hover { | |
fill: red; | |
} | |
.chart text { | |
fill: black; | |
text-anchor: start; | |
font-size: 1em; | |
} | |
.chart rect { | |
fill: steelblue; | |
} | |
.type2 rect { | |
fill: burlywood; | |
} | |
/* large screens */ | |
@media only screen and (min-width: 38em) { | |
article { | |
width: 67%; | |
float: left; | |
margin-right: 0; | |
} | |
aside { | |
width: 21%; | |
float: right; | |
margin-left: 0; | |
} | |
footer { | |
clear: both; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* main.js | |
* Copyright (C) 2015 Christopher C. Strelioff <[email protected]> | |
* | |
* Distributed under terms of the MIT license. | |
*/ | |
// --- | |
var ds = { | |
current: "a", | |
a: [40, 50, 10, 140, 300, 25], | |
b: [200, 40, 80, 15, 400, 88, 45], | |
getValues: function () { | |
return this[this.current].slice(); | |
}, | |
getLength: function () { | |
return this[this.current].length; | |
}, | |
getMax: function() { | |
return Math.max.apply(Math, this[this.current]); | |
}, | |
getAvg: function() { | |
var sum = 0, | |
length = this.getLength() | |
data = this.getValues(); | |
for (var n=0; n < length; n++) { | |
sum += data[n]; | |
} | |
return Math.round(sum/length * 100)/100; | |
} | |
}; | |
var barHeight = 30, | |
barLengthFactor = 0.7; | |
// --- | |
window.onload = function init() { | |
ds.current = get_radio_val(); | |
draw_svg_chart(); | |
} | |
// --- | |
function draw_svg_chart () { | |
var data = ds.getValues(), | |
dataLength = ds.getLength(), | |
maxData = ds.getMax(), | |
vizDiv = document.getElementById('mainviz'), | |
svg = document.createElementNS("http://www.w3.org/2000/svg", 'svg'), | |
infoDiv = document.createElement('div'); | |
// setup svg and append to vizDiv | |
svg.setAttributeNS(null, "id", 'mainviz_svg'); | |
svg.setAttributeNS(null, "height", dataLength*(barHeight+1)); | |
vizDiv.appendChild(svg); | |
// set scales, widths, etc | |
var svgWidth = svg.parentElement.clientWidth, | |
maxBarLength = barLengthFactor*svgWidth, | |
scale_factor = maxBarLength/maxData; | |
// setup infoDiv and append to vizDiv | |
infoDiv.setAttribute("id", "dataInfo"); | |
infoDiv.innerHTML = "<p><strong>set " + ds.current + | |
"</strong> -- click bars for more information.</p>"; | |
vizDiv.appendChild(infoDiv); | |
if (ds.current === "a") { | |
svg.setAttributeNS(null, "class", 'chart'); | |
} | |
else { | |
svg.setAttributeNS(null, "class", 'chart type2'); | |
} | |
var newG, | |
newRect, | |
newText, | |
textNode; | |
// loop through data | |
for (n=0; n < dataLength; n++) { | |
//create new group for this bar | |
newG = document.createElementNS("http://www.w3.org/2000/svg", 'g'); | |
newG.setAttributeNS(null, "id", "group-" + n); | |
newG.setAttributeNS(null, "data-value", data[n]); | |
newG.setAttributeNS(null, "transform", "translate(0," + ((barHeight+1)*n) +")"); | |
newG.addEventListener("click", bar_mouse_click(data[n])); | |
// create rectangle/bar | |
newRect = document.createElementNS("http://www.w3.org/2000/svg", 'rect'); | |
newRect.setAttributeNS(null, "id", "bar-val-" + n); | |
newRect.setAttributeNS(null, "width", data[n]*scale_factor); | |
newRect.setAttributeNS(null, "height", barHeight); | |
// create text/label | |
newText = document.createElementNS("http://www.w3.org/2000/svg", 'text'); | |
newText.setAttributeNS(null, "id", "text-val-" + n); | |
newText.setAttributeNS(null, "x", data[n]*scale_factor + 2); | |
newText.setAttributeNS(null, "y", barHeight/2); | |
newText.setAttributeNS(null, "dy", "0.35em"); | |
// text node | |
textNode = document.createTextNode(data[n]); | |
newText.appendChild(textNode); | |
// add rectangle to g | |
newG.appendChild(newRect); | |
// add text to g | |
newG.appendChild(newText); | |
// add g to svg | |
svg.appendChild(newG); | |
} | |
} | |
// --- | |
function update_svg() { | |
var data = ds.getValues(), | |
dataLength = ds.getLength(), | |
maxData = ds.getMax(), | |
svg = document.getElementById('mainviz_svg'), | |
svgWidth = svg.parentElement.clientWidth, | |
maxBarLength = barLengthFactor*svgWidth, | |
scaleFactor = maxBarLength/maxData, | |
rCurr, | |
tCurr; | |
for (n=0; n < dataLength; n++) { | |
// get current bar and update width | |
rCurr = document.getElementById("bar-val-" + n); | |
rCurr.setAttributeNS(null, "width", data[n]*scaleFactor); | |
// get current text and update x-position | |
var tCurr = document.getElementById("text-val-" + n); | |
tCurr.setAttributeNS(null, "x", data[n]*scaleFactor + 2); | |
} | |
} | |
// --- | |
function clear_svg_chart() { | |
var v = document.getElementById("mainviz"), | |
s = document.getElementById("mainviz_svg"), | |
d = document.getElementById("dataInfo"); | |
v.removeChild(s); | |
v.removeChild(d); | |
} | |
// --- | |
function get_radio_val() { | |
var radio1 = document.getElementById("radio1"), | |
radio2 = document.getElementById("radio2"); | |
if (radio1.checked) { | |
return radio1.value; | |
} | |
else if (radio2.checked) { | |
return radio2.value; | |
} | |
} | |
// --- | |
function check_data_buttons() { | |
var newSelectedData = get_radio_val(); | |
if (newSelectedData !== ds.current){ | |
ds.current = newSelectedData; | |
clear_svg_chart(); | |
draw_svg_chart(); | |
} | |
} | |
// --- | |
function bar_mouse_click(value) { | |
var outDiv = document.getElementById("dataInfo"), | |
dataAvg = ds.getAvg(); | |
function data_info() { | |
outDiv.innerHTML = "<p><strong>set:</strong> " + ds.current + | |
"<br><strong>value:</strong> " + value; | |
if(value > dataAvg) { | |
outDiv.innerHTML += "<br>This value is <strong>greater than</strong> the average of " + | |
dataAvg + "</p>" | |
} | |
else { | |
outDiv.innerHTML += "<br>This value is <strong>less than</strong> the average of " + | |
dataAvg + "</p>" | |
} | |
} | |
return data_info; | |
} | |
// events | |
window.addEventListener('resize', function() { | |
update_svg(); | |
}); | |
document.getElementById("radio1") | |
.addEventListener("click", check_data_buttons); | |
document.getElementById("radio2") | |
.addEventListener("click", check_data_buttons); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* http://meyerweb.com/eric/tools/css/reset/ | |
v2.0 | 20110126 | |
License: none (public domain) | |
*/ | |
html, body, div, span, applet, object, iframe, | |
h1, h2, h3, h4, h5, h6, p, blockquote, pre, | |
a, abbr, acronym, address, big, cite, code, | |
del, dfn, em, img, ins, kbd, q, s, samp, | |
small, strike, strong, sub, sup, tt, var, | |
b, u, i, center, | |
dl, dt, dd, ol, ul, li, | |
fieldset, form, label, legend, | |
table, caption, tbody, tfoot, thead, tr, th, td, | |
article, aside, canvas, details, embed, | |
figure, figcaption, footer, header, hgroup, | |
menu, nav, output, ruby, section, summary, | |
time, mark, audio, video { | |
margin: 0; | |
padding: 0; | |
border: 0; | |
font-size: 100%; | |
font: inherit; | |
vertical-align: baseline; | |
} | |
/* HTML5 display-role reset for older browsers */ | |
article, aside, details, figcaption, figure, | |
footer, header, hgroup, menu, nav, section { | |
display: block; | |
} | |
body { | |
line-height: 1; | |
} | |
ol, ul { | |
list-style: none; | |
} | |
blockquote, q { | |
quotes: none; | |
} | |
blockquote:before, blockquote:after, | |
q:before, q:after { | |
content: ''; | |
content: none; | |
} | |
table { | |
border-collapse: collapse; | |
border-spacing: 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment