Last active
June 7, 2016 21:09
-
-
Save eagereyes/1a3ac476c7d21e0f7b00 to your computer and use it in GitHub Desktop.
Multiples chart in D3 to show how much more CEOs make than average workers.
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>Large Multiples</title> | |
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script> | |
<style> | |
rect { | |
fill: #ddd; | |
stroke: none; | |
} | |
rect.active, circle.unit, circle.worker { | |
fill: steelblue; | |
} | |
text { | |
font-family: Helvetica, Arial, sans-serif; | |
fill: lightgray; | |
} | |
text.barlabel { | |
fill: white; | |
pointer-events: none; | |
} | |
text.label, #sentence, .activestep { | |
fill: darkgray; | |
} | |
.step:hover { | |
fill: #ccc; | |
} | |
h1 { | |
font-family: Helvetica, Arial, sans-serif; | |
margin-bottom: 0px; | |
margin-left: 5px; | |
} | |
</style> | |
</head> | |
<body> | |
<h1>It pays to be a CEO in the U.S.</h1> | |
<div id="chart"> | |
</div> | |
<script> | |
var data = [ | |
{country: "Poland", multiple: 28, article: ""}, | |
{country: "Austria", multiple: 36, article: ""}, | |
{country: "Denmark", multiple: 48, article: ""}, | |
{country: "Portugal", multiple: 53, article: ""}, | |
{country: "Norway", multiple: 58, article: ""}, | |
{country: "Japan", multiple: 67, article: ""}, | |
{country: "Israel", multiple: 76, article: ""}, | |
{country: "United Kingdom", multiple: 84, article: "the "}, | |
{country: "Sweden", multiple: 89, article: ""}, | |
{country: "Australia", multiple: 93, article: ""}, | |
{country: "France", multiple: 104, article: ""}, | |
{country: "Czech Republic", multiple: 110, article: "the "}, | |
{country: "Spain", multiple: 127, article: ""}, | |
{country: "Germany", multiple: 147, article: ""}, | |
{country: "Switzerland", multiple: 148, article: ""}, | |
{country: "United States", multiple: 354, article: "the "} | |
]; | |
var intervalID = -1; | |
var TIMEOUT = 20; | |
function makeSquares(numUnits) { | |
svg.selectAll('.unit').remove(); | |
var a = Math.floor(Math.sqrt(numUnits)) // numUnits/.75 for 4:3 ratio of units | |
var b = Math.floor(numUnits/a); | |
var rest = numUnits-a*b; | |
if (rest > a) { | |
a += 1; | |
rest = numUnits-a*b; | |
} | |
if (b > a) { | |
var temp = a; | |
a = b; | |
b = temp; | |
} | |
var circles = []; | |
for (var y = 0; y < b; y += 1) { | |
for (var x = 0; x < a; x += 1) { | |
var c = svg.append('circle') | |
.attr('cx', unitsOffset+x*(unitsize+unitpadding)) | |
.attr('cy', unitsHeight-y*(unitsize+unitpadding)) | |
.attr('r', unitsize/2) | |
.style('visibility', 'hidden') | |
.attr('class', 'unit'); | |
circles.push(c); | |
} | |
} | |
for (var x = 0; x < rest; x += 1) { | |
var c = svg.append('circle') | |
.attr('cx', unitsOffset+x*(unitsize+unitpadding)) | |
.attr('cy', unitsHeight-b*(unitsize+unitpadding)) | |
.attr('r', unitsize/2) | |
.style('visibility', 'hidden') | |
.attr('class', 'unit'); | |
circles.push(c); | |
} | |
svg.select('#ceolabel').transition().attr('y', unitsHeight-b*(unitsize+unitpadding)-16); | |
if (intervalID != -1) { | |
window.clearInterval(intervalID); | |
} | |
var circleIndex = 0; | |
intervalID = window.setInterval(function() { | |
circles[circleIndex].style('visibility', 'visible'); | |
circleIndex += 1; | |
if (circleIndex == circles.length) { | |
window.clearInterval(intervalID); | |
intervalID = -1; | |
} | |
}, TIMEOUT); | |
} | |
var svg = d3.select('#chart').append('svg').attr('width', 694).attr('height', 470); | |
var barheight = 24; | |
var barpad = 3; | |
var unitsize = 17; | |
var unitpadding = 3; | |
var topOffset = 30; | |
var unitsOffset = 320; | |
var unitsHeight = topOffset+16*barheight+15*barpad-unitsize/2; | |
var selected = data[0]; | |
function select(d) { | |
svg.selectAll('.'+selected.country.replace(' ', '-')).classed('active', false); | |
svg.select('.barlabel.'+selected.country.replace(' ', '-')).text(selected.country); | |
svg.selectAll('.'+d.country.replace(' ', '-')).classed('active', true); | |
makeSquares(d.multiple); | |
svg.select('.barlabel.'+d.country.replace(' ', '-')).text(d.country+': '+d.multiple+'x'); | |
svg.select('#sentence').text('In '+d.article+d.country+', the average CEO makes '+d.multiple+' times the salary of the average worker.') | |
selected = d; | |
svg.select('.activestep').classed('activestep', false); | |
activeStep = -1; | |
for (var i = 0; i < steps.length; i++) { | |
if (data[steps[i]] == d) { | |
svg.select('.step-'+i).classed('activestep', true); | |
activeStep = i; | |
} | |
} | |
} | |
svg.selectAll('.bar').data(data).enter() | |
.append('rect') | |
.attr('width', 170) | |
.attr('height', barheight) | |
.attr('x', 5) | |
.attr('y', function(d, i) { return topOffset+i*(barheight+barpad); }) | |
.attr('class', function(d) { return 'bar '+d.country.replace(' ', '-'); }) | |
.on('mouseenter', function(d) { | |
select(d); | |
}); | |
svg.selectAll('.barlabel').data(data).enter() | |
.append('text') | |
.attr('x', barpad*2) | |
.attr('y', function(d, i) { return topOffset+i*(barheight+barpad)+barheight-barpad-4; }) | |
.attr('class', function(d) { return 'barlabel '+d.country.replace(' ', '-'); }) | |
.text(function(d) { return d.country; }); | |
svg.append('circle') | |
.attr('class', 'worker') | |
.attr('cx', unitsOffset-4*(unitsize+unitpadding)) | |
.attr('cy', unitsHeight) | |
.attr('r', unitsize/2); | |
svg.append('text') | |
.attr('class', 'label') | |
.attr('x', unitsOffset-4*(unitsize+unitpadding)-unitsize/2) | |
.attr('y', unitsHeight-16) | |
.text('Worker'); | |
svg.append('text') | |
.attr('class', 'label') | |
.attr('x', unitsOffset-unitsize/2) | |
.attr('y', unitsHeight-16) | |
.attr('id', 'ceolabel') | |
.text('CEO'); | |
svg.append('text') | |
.attr('id', 'sentence') | |
.attr('x', 5) | |
.attr('y', 18); | |
var steps = [0, 3, 7, 13, 15]; | |
var activeStep = 0; | |
var stepsLeft = 493; | |
svg.selectAll('.step').data(steps).enter() | |
.append('rect') | |
.attr('class', function(d, i) { return 'step step-'+i+(i==0?' activestep':''); }) | |
.attr('x', function(d, i) { return stepsLeft+i*(barheight+barpad); }) | |
.attr('y', topOffset) | |
.attr('width', barheight) | |
.attr('height', barheight) | |
.on('click', function(d, i) { | |
svg.select('.activestep').classed('activestep', false); | |
svg.select('.step-'+i).classed('activestep', true); | |
activeStep = i; | |
select(data[d]); | |
}); | |
svg.selectAll('.steplabel').data(steps).enter() | |
.append('text') | |
.attr('class', 'barlabel') | |
.attr('x', function(d, i) { return stepsLeft+7+i*(barheight+barpad); }) | |
.attr('y', topOffset+17) | |
.text(function(d, i) { return ''+(i+1); }); | |
svg.append('rect') | |
.attr('class', 'step') | |
.attr('x', stepsLeft+steps.length*(barheight+barpad)) | |
.attr('y', topOffset) | |
.attr('width', barheight*2.5) | |
.attr('height', barheight) | |
.on('click', function() { | |
if (activeStep < steps.length-1) { | |
svg.select('.activestep').classed('activestep', false); | |
activeStep += 1; | |
svg.select('.step-'+activeStep).classed('activestep', true); | |
select(data[steps[activeStep]]); | |
} | |
}); | |
svg.append('text') | |
.attr('class', 'barlabel') | |
.attr('x', stepsLeft+7+steps.length*(barheight+barpad)) | |
.attr('y', topOffset+17) | |
.text('Next >'); | |
select(data[0]); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment