Skip to content

Instantly share code, notes, and snippets.

@leakyMirror
Forked from kforeman/index.html
Created July 9, 2013 17:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save leakyMirror/5959379 to your computer and use it in GitHub Desktop.
Save leakyMirror/5959379 to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<title>Treemap</title>
<script type="text/javascript" src="http://mbostock.github.com/d3/d3.js"></script>
<script type="text/javascript" src="http://mbostock.github.com/d3/d3.layout.js"></script>
<script type="text/javascript" src="http://simiantics.net/d3/lib/jquery/jquery.min.js"></script>
<script type="text/javascript" src="http://simiantics.net/d3/lib/jquery-ui/jquery-ui.min.js"></script>
<style type="text/css"> @import url("http://simiantics.net/d3/lib/jquery-ui/jquery-ui.css"); text { font-family: sans-serif; } </style>
<script type="text/javascript" src="http://simiantics.net/treemap_USA.js"></script>
</head>
<body>
<script type="text/javascript">
// setup initial params
var w = 800,
h = 500,
min_labeled_cf = .01,
max_color_cf = .3,
ysa = '00F30',
change_duration = 500;
// age sliders
age_title = d3.select('body')
.append('div')
.style ('position', 'absolute')
.style ('left', '10px')
.style ('top', '5px')
.style ('width', '100px')
.append('span')
.text ('Age')
.style ('font-family', 'sans-serif')
.style ('font-weight', 'bold');
// play button for age slider
age_play = d3.select('body')
.append('div')
.style ('position', 'absolute')
.style ('left', '50px')
.style ('top', '5px')
.style ('width', '20px')
.append('img')
.attr ('src', 'http://simiantics.net/play.png')
.attr ('alt', 'Play')
.attr ('onclick', 'play_age()');
// a div to contain the slider
age_slider_div = d3.select('body')
.append('div')
.attr ('id', 'age_slider')
.style ('position', 'absolute')
.style ('left', '85px')
.style ('top', '7px')
.style ('width', '500px');
// the age slider itself
var age = 'E', display_age = '30 to 34', slider_age = 30;
$('#age_slider').slider({
min: -15,
max: 80,
value: slider_age,
width: '100px',
animate: true,
step: 5,
slide: function(event, ui) { refresh_age(ui.value); }
});
// text to indicate the currently selected age
age_label = d3.select('body')
.append('div')
.attr ('id', 'age_label')
.style ('position', 'absolute')
.style ('left', '605px')
.style ('top', '5px')
.style ('width', '125px')
.append('span')
.text (display_age)
.style ('font-family', 'sans-serif')
.style ('font-weight', 'bold');
// function to update the plot when a new age is selected
function refresh_age(a) {
// change the slider age to reflect whatever was just picked
slider_age = a;
// update the display ages to match what the slider is set to (again accounting for weirdness in the age cutpoints)
switch(slider_age) {
case -15: age = 'E'; display_age = 'Early Neonatal'; break;
case -10: age = 'L'; display_age = 'Late Neonatal'; break;
case -5: age = 'P'; display_age = 'Post Neonatal'; break;
case 0: age = '1'; display_age = '1 to 4'; break;
case 80: age = slider_age; display_age = '80 plus'; break;
default: age = slider_age; display_age = slider_age + ' to ' + (slider_age + 4); break;
}
// update the text specifying the current age
age_label.text (display_age);
// refresh the tree
ysa = ysa.substr(0,3) + age
change_ysa(ysa);
}
// function to step through age groups if the play button is clicked
var age_timer = undefined;
function play_age() {
// if the map is already playing, then stop it
if (age_timer) stop_age();
else {
// if we're at the last age group, start again at the beginning
if (slider_age == 80) {
slider_age = -15;
refresh_age(slider_age)
$('#age_slider').slider('value', slider_age);
}
// change the play button into a stop button
age_play.transition().attr ('src', 'http://simiantics.net/stop.png');
// increment the age groups
age_timer = setInterval(function() {
// stop if we've reached the last age group
if (slider_age >= 80) stop_age();
else {
// deal with awkward age groups again
switch(age) {
case 0: age = .01; slider_age = -10; break;
case .01: age = .1; slider_age = -5; break;
case .1: age = 1; slider_age = 0; break;
case 1: age = 5; slider_age = 5; break;
default: age = age+5; slider_age = slider_age+5; break;
}
}
// update the slider
$('#age_slider').slider('value', slider_age);
// update the map as though the slider were moved
refresh_age(slider_age);
// increment every 1 second
}, 1000);
}
}
// function to stop looping through ages
function stop_age() {
// clear the timer
clearInterval(age_timer);
age_timer = undefined;
// change the stop button back into a play button
age_play.transition().attr ('src', 'http://simiantics.net/play.png');
}
// year sliders
year_title = d3.select('body')
.append('div')
.style ('position', 'absolute')
.style ('left', '10px')
.style ('top', '30px')
.style ('width', '100px')
.append('span')
.text ('Year')
.style ('font-family', 'sans-serif')
.style ('font-weight', 'bold');
// play button for year slider
year_play = d3.select('body')
.append('div')
.style ('position', 'absolute')
.style ('left', '50px')
.style ('top', '30px')
.style ('width', '20px')
.append('img')
.attr ('src', 'http://simiantics.net/play.png')
.attr ('alt', 'Play')
.attr ('onclick', 'play_year()');
// a div to contain the slider
year_slider_div = d3.select('body')
.append('div')
.attr ('id', 'year_slider')
.style ('position', 'absolute')
.style ('left', '85px')
.style ('top', '32px')
.style ('width', '500px');
// the year slider itself
var year = '90', slider_year = 2000;
$('#year_slider').slider({
min: 1980,
max: 2010,
value: slider_year,
width: '100px',
animate: true,
step: 1,
slide: function(event, ui) { refresh_year(ui.value); }
});
// text to indicate the currently selected year
year_label = d3.select('body')
.append('div')
.attr ('id', 'year_label')
.style ('position', 'absolute')
.style ('left', '605px')
.style ('top', '30px')
.style ('width', '125px')
.append('span')
.text (slider_year)
.style ('font-family', 'sans-serif')
.style ('font-weight', 'bold');
// function to update the plot when a new year is selected
function refresh_year(y) {
// change the slider year to reflect whatever was just picked
slider_year = y;
// update the display years to match what the slider is set to (again accounting for weirdness in the year cutpoints)
year = (slider_year+'').substr(2,2)
// update the text specifying the current age
year_label.text (slider_year);
// refresh the tree
ysa = year + ysa.substr(2,3)
change_ysa(ysa);
}
// function to step through year groups if the play button is clicked
var year_timer = undefined;
function play_year() {
// if the map is already playing, then stop it
if (year_timer) stop_year();
else {
// if we're at the last year group, start again at the beginning
if (slider_year == 2010) {
slider_year = 1980;
refresh_year(slider_year)
$('#year_slider').slider('value', slider_year);
}
// change the play button into a stop button
year_play.transition().attr ('src', 'http://simiantics.net/stop.png');
// increment the year groups
year_timer = setInterval(function() {
// stop if we've reached the last year group
if (slider_year >= 2010) stop_year();
else slider_year++;
// update the slider
$('#year_slider').slider('value', slider_year);
// update the map as though the slider were moved
refresh_year(slider_year);
// increment every 1 second
}, 1000);
}
}
// function to stop looping through years
function stop_year() {
// clear the timer
clearInterval(year_timer);
year_timer = undefined;
// change the stop button back into a play button
year_play.transition().attr ('src', 'http://simiantics.net/play.png');
}
// color interpolators for red/blue/green
reds = d3.interpolate(d3.rgb(252,174,145), d3.rgb(165,15,21));
blues = d3.interpolate(d3.rgb(189,215,231), d3.rgb(8,81,156));
greens = d3.interpolate(d3.rgb(186,228,179), d3.rgb(0,109,44));
// scale CF for coloring
color_scale = d3.scale.sqrt().domain([0,max_color_cf]).clamp(true);
// function to color based on category
function color(d) {
switch(d.name.substr(0,1)) {
case 'A':
return reds(color_scale(d[ysa]));
break;
case 'B':
return blues(color_scale(d[ysa]));
break;
case 'C':
return greens(color_scale(d[ysa]));
break;
default:
return 'white';
break;
}
}
// make the treemap layout
var treemap = d3.layout.treemap()
.size([w+1, h+1])
.value(function(d) { return d[ysa]; })
.padding(1)
.sticky(true);
// create the visualization area
var vis = d3.select('body')
.append('div')
.attr ('id', 'vis')
.style ('position', 'absolute')
.style ('top', '50px')
.append('svg:svg')
.style('width', w)
.style('height', h)
.append('svg:g')
.attr('transform', 'translate(-.5, -.5)');
// make cells for each cause
var cell = vis.selectAll('g')
.data(treemap.nodes(USA))
.enter().append('svg:g')
.attr('class', 'cell')
.attr('transform', function(d) { return 'translate(' + d.x + ',' + d.y + ')'; });
// add a rectangle to each cell
var rect = cell.append('svg:rect')
.attr('width', function(d) { return d.dx; })
.attr('height', function(d) { return d.dy; })
.attr('stroke', 'white')
.attr('stroke-width', function(d) { return d.depth == 0 ? 0 : 1; })
.style('fill', function(d) { return d.children ? 'white' : color(d); });
// label the cells
label_sizes = d3.interpolate(8,30);
label_sizer = d3.scale.sqrt().domain([min_labeled_cf, max_color_cf]).clamp(true);
labels = cell.append('svg:text')
.attr('x', function(d) { return d.dx/2; })
.attr('y', function(d) { return d.dy/2; })
.attr('font-size', function(d) { return label_sizes(label_sizer(d[ysa])); })
.attr('text-anchor', 'middle')
.attr('alignment-baseline', 'middle')
.text(function(d) { return d.children ? null : (d[ysa] > min_labeled_cf ? d.short : null); });
cell.append('svg:title')
.text(function(d) { return d.children ? null : d.desc; });
// function to change the year-sex-age (ysa)
function change_ysa(new_ysa) {
ysa = new_ysa;
cell.data(treemap.value(function(d) { return d[ysa]; }));
refreshTree();
}
// function to change the country
var iso3 = 'USA',
loaded = {};
loaded['USA'] = 1;
function change_country(new_iso3) {
iso3 = new_iso3;
if (!loaded[iso3]) {
var newdata = document.createElement('script');
newdata.setAttribute('type', 'text/javascript');
newdata.setAttribute('src', 'data/treemap_' + iso3 + '.js');
document.getElementsByTagName('head')[0].appendChild(newdata);
}
cell.data(treemap.nodes(iso3));
change_ysa(ysa);
}
// function to resize the treemap
function refreshTree() {
cell.transition().ease('linear').duration(change_duration).attr('transform', function(d) { return 'translate(' + d.x + ',' + d.y + ')'; });
rect.transition().ease('linear').duration(change_duration).attr('width', function(d) { return d.dx; }).attr('height', function(d) { return d.dy; }).style('fill', function(d) { return d.children ? 'white' : color(d); });
labels.transition().ease('linear').duration(change_duration).attr('x', function(d) { return d.dx/2; }).attr('y', function(d) { return d.dy/2; }).attr('font-size', function(d) { return label_sizes(label_sizer(d[ysa])); }).text(function(d) { return d.children ? null : (d[ysa] > min_labeled_cf ? d.short : null); });;
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment