Created
March 2, 2012 06:44
-
-
Save scameron/1956297 to your computer and use it in GitHub Desktop.
Sparkline in table.
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>Animated Sparkline</title> | |
<script src="http://bost.ocks.org/mike/d3.v2.min.js"></script> | |
<style type="text/css"> | |
svg { | |
display: block; | |
position: relative; | |
} | |
path { | |
stroke: steelblue; | |
stroke-width: 1; | |
fill: none; | |
} | |
circle { | |
fill: red; | |
stroke: white; | |
stroke-width: .75; | |
} | |
#settings { | |
border: 1px solid; | |
margin: 30px 0px 0px 30px; | |
padding: 10px; | |
width: 270px; | |
float:left | |
} | |
#refreshbutton { | |
margin: 30px 0px 20px; | |
width: 50%; | |
height: 188px; | |
float:left; | |
} | |
#main { | |
margin: 10px 30px; | |
float: left; | |
} | |
input { | |
margin: 3px 10px; | |
width: 60px; | |
} | |
label { | |
width: 180px; | |
display: inline-block; | |
} | |
button { | |
margin: 10px 0px 5px 0px; | |
} | |
button#refresh { | |
margin: 0px 0px 0px 30px; | |
} | |
hr { | |
width: 75%; | |
height: 1px; | |
border-width: 0; | |
background-color: gray; | |
margin-left: 30px; | |
} | |
table { | |
border: 1px solid #BBB; | |
border-collapse: collapse; | |
} | |
#vizCol { | |
width: 500px; | |
} | |
table th { | |
padding: 5px; | |
border: 1px solid #BBB; | |
background: #EEE; | |
} | |
table td { | |
padding: 5px; | |
border: 1px solid #BBB; | |
height: 50px; | |
} | |
</style> | |
<script type="text/javascript"> | |
var duration = 5000; | |
var ballRadius = 2; | |
var rowCount = 10, values = 60; | |
var data = new Array(); | |
var graphs; // Holds the sparklines themselves | |
var line; | |
function generateData() { | |
data.length = 0; | |
for (var i = 0; i < rowCount; i++ ) { | |
data.push(new Array()); | |
for (var j = 0; j < values; j++) { | |
data[i].push(Math.round(Math.random() * 10)); | |
} | |
} | |
} | |
function refreshLines() { | |
d3.select("table tbody").selectAll("tr") | |
.data(data) | |
.selectAll("path") | |
.data(function(d) { return [d]; }) | |
.transition() | |
.duration(duration / 2) | |
.ease("linear") | |
.attr("d", line); | |
} | |
function refresh() { | |
generateData(); | |
refreshLines(); | |
} | |
function draw() { | |
generateData(); | |
var rows = d3.select("table tbody").selectAll("tr") | |
.data(data) | |
.enter().append("tr"); | |
rows.selectAll("td.column1") | |
.data(function(d, i) { return [i]; }) | |
.enter().append("td") | |
.attr("class", "column1") | |
.text(function(d) { return d+1; }); | |
var cellHeight = 0, cellWidth = 0; | |
graphs = rows.selectAll("td.column2") | |
.data(function(d) { return [d]; }) | |
.enter().append("td") | |
.attr("class", "column2") | |
.each(function() { | |
cellHeight = this.clientHeight; | |
cellWidth = this.clientWidth; | |
}) | |
.append("svg") | |
.attr("height", cellHeight) | |
.attr("width", cellWidth); | |
var x = d3.scale.linear().domain([0, 1]).range([0, cellWidth / (data[0].length-1)]); | |
// take ball radius into account so it doesn't dip below or above the visible area | |
var y = d3.scale.linear().domain([0, 10]).range([ballRadius, cellHeight - ballRadius]); | |
line = d3.svg.line() | |
.interpolate("linear") | |
.x(function(d,i) { return x(i); }) | |
.y(function(d) { return cellHeight - y(d); }); | |
graphs.append("clipPath") | |
.attr("id", function(d, i, j) { return "clippy" + j; }) | |
.append("rect"); | |
var path = graphs.append("g") | |
.attr("clip-path", function(d, i, j) { return "url(#clippy" + j + ")"; }) | |
.selectAll("path") | |
.data(function(d) { return [d]; }) | |
.enter().append("path") | |
.attr("class", "path") | |
.attr("d", line); | |
var y_start = y(data[0][0]); | |
var circle = graphs.append("circle") | |
.attr("class", "circle") | |
.attr("cy", y_start) | |
.attr("r", ballRadius); | |
graphs.selectAll("rect").attr("height", cellHeight); | |
var currentX = new Array(rows); | |
var transition = d3.transition() | |
.duration(duration) | |
.ease("linear"); | |
transition.selectAll("rect") | |
.attrTween("width", function(d, i) { | |
return function(t) { | |
return currentX[i]; | |
}; | |
}); | |
transition.selectAll("circle") | |
.attrTween("transform", function(d, i) { | |
return function(t) { | |
return followPath(path[i][0], t, i); | |
}; | |
}) | |
.each("end", function() { this.style.visibility = "hidden"; }); | |
function followPath(pathElement, t, i) { | |
var l = pathElement.getTotalLength(); | |
var p = pathElement.getPointAtLength(t * l); | |
currentX[i] = p.x; | |
return "translate(" + p.x + ", " + (p.y - y_start) + ")"; | |
} | |
} | |
function redraw() { | |
rowCount = inputRowCount.value; | |
values = inputNumValues.value; | |
duration = inputDuration.value * 1000; | |
updateStyles(inputWidth.value, inputHeight.value); | |
d3.select("table tbody").selectAll("tr").remove(); | |
draw(); | |
} | |
function redrawOnEnter(e) { | |
// look for window.event in case event isn't passed in | |
if (typeof e == 'undefined' && window.event) { e = window.event; } | |
if (e.keyCode == 13) | |
{ | |
document.getElementById("redraw").click(); | |
} | |
} | |
function updateStyles(w, h) { | |
var theRules = new Array(); | |
if (document.styleSheets[0].cssRules) { | |
theRules = document.styleSheets[0].cssRules | |
} | |
else if (document.styleSheets[0].rules) { // IE uses rules not cssRules | |
theRules = document.styleSheets[0].rules | |
} | |
for (var i = 0; i < theRules.length; i++) { | |
if ( theRules[i].selectorText.toLowerCase()=="#vizcol" ) { | |
theRules[i].style.width = w + "px"; | |
} | |
else if ( theRules[i].selectorText.toLowerCase()=="table td" ) { | |
theRules[i].style.height = h + "px"; | |
} | |
} | |
} | |
</script> | |
</head> | |
<body> | |
<div id="settings"> | |
<label for="inputRowCount">Number of Rows: </label><input id="inputRowCount" type="text" value="10" onkeypress="redrawOnEnter(event)"></br> | |
<label for="inputNumValues">Number of Values: </label><input id="inputNumValues" type="text" value="60" onkeypress="redrawOnEnter(event)"></br> | |
<label for="inputWidth">Cell Width (px): </label><input id="inputWidth" type="text" value="500" onkeypress="redrawOnEnter(event)"></br> | |
<label for="inputHeight">Cell Height (px): </label><input id="inputHeight" type="text" value="50" onkeypress="redrawOnEnter(event)"></br> | |
<label for="inputDuration">Time to Draw (sec): </label><input id="inputDuration" type="text" value="5" onkeypress="redrawOnEnter(event)"></br> | |
<button id="redraw" onclick="redraw();">Redraw Table</button><br/> | |
</div> | |
<div id="refreshbutton"> | |
<button id="refresh" onclick="refresh();">Refresh Data</button> | |
</div> | |
<hr> | |
<div id="main"> | |
<table> | |
<colgroup> | |
<col/> | |
<col id="vizCol"/> | |
</colgroup> | |
<thead> | |
<tr> | |
<th>Description</th> | |
<th>Visualization</th> | |
</tr> | |
</thead> | |
<tbody> | |
</tbody> | |
</table> | |
</div> | |
<script> | |
draw(); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment