Layout of US House & Senate members in an arc using D3. Based on code from http://en.wikipedia.org/wiki/User_talk:Slashme/parliament.py
A Pen by Liji Jinaraj on CodePen.
<div class="chart"> | |
</div> |
/** | |
* ref http://en.wikipedia.org/wiki/User_talk:Slashme/parliament.py | |
*/ | |
function parliamentCharts(el, parliament) { | |
var margin = {top: 10, right: 0, bottom: 0, left: 10}, | |
width = 500 - margin.left - margin.right, | |
height = 500 - margin.top - margin.bottom; | |
var totalSpots = [3, 15, 33, 61, 95, 138, 189, 247, 313, 388, 469, 559, 657, 762, 876, 997, 1126, 1263, 1408, 1560, 1722, 1889, 2066, 2250, 2442, 2641, 2850, 3064, 3289, 3519, 3759, 4005, 4261, 4522, 4794, 5071, 5358, 5652, 5953, 6263, 6581, 6906, 7239, 7581, 7929, 8287, 8650, 9024, 9404]; | |
var formatNumber = d3.format("n"); | |
var partyColors = { | |
"d":{name:"Democrats", color:"#0A5F90"} | |
, "r":{name:"Republicans", color:"#CC5B2E"} | |
, "i":{name:"Independents", color:"#333"} | |
, "vacant":{name:"Vacant", color:"#fff"} | |
}; | |
var svg = el.append("svg") | |
.attr("class", "parliament usa") | |
.attr("width", width + margin.left + margin.right) | |
.attr("height", height + margin.top + margin.bottom) | |
.append("g") | |
.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); | |
draw(svg, parliament[0].houses[0], 0, 10, {x:5, y:5}); | |
draw(svg, parliament[0].houses[1], 180, 5, {x:5, y:15}); | |
drawLegend(svg); | |
function draw(svgEl, pData, pOffsetAngle, pRows, centerOffset) { | |
var dcols = []; | |
var baseRow = 0; | |
var n = pData.totalMembers; | |
var maxRadius = 0.2/8; | |
var partyIndex = 0; | |
var partyStartIndex = 0; | |
var dataRef = []; | |
var direction = pOffsetAngle === 180 ? 1 : 0; | |
function initDataRef() { | |
pOffsetAngle *= Math.PI/180; | |
function calcCol(drow, dcol, dn, dr) { | |
var da = dcol*(Math.PI-2.0*Math.sin(maxRadius/dr))/(dn-1.0)+Math.sin(maxRadius/dr) + pOffsetAngle; | |
var dx = Math.cos(da) * dr + 1.75; | |
var dy = Math.sin(da) * dr; | |
dataRef.push({ | |
id: dataRef.length, | |
row: drow, | |
col: dcol, | |
a: da, | |
x: dx, | |
y: dy | |
}); | |
} | |
d3.range(1, pRows).forEach(function(drow) { | |
var dr = (3.0*pRows+4.0*drow-2.0)/(4.0*pRows); | |
var dn = Math.floor(n/totalSpots[pRows-1]*Math.PI/(2*Math.asin(2.0/(3.0*pRows+4.0*drow-2.0)))); | |
d3.range(dn).forEach(function(dcol) { | |
calcCol(drow, dcol, dn, dr); | |
}); | |
}); | |
var dn = n - dataRef.length; | |
var dr =(7.0*pRows-2.0)/(4.0*pRows); | |
d3.range(dn).forEach(function(dcol) { | |
calcCol(0, dcol, dn, dr); | |
}) | |
} | |
initDataRef(); | |
dataRef = dataRef.sort(function(a,b) { | |
return a.a - b.a; | |
}).reverse(); | |
var gHouse = svgEl.select(".house " + pData.id); | |
if(gHouse.empty()) { | |
gHouse = svgEl.append("g") | |
.attr("class", "house " + pData.id); | |
} | |
var gTitle = gHouse.append("g") | |
.attr("class", "house-heading"); | |
var center = { | |
x: Math.cos(90 * Math.PI/180 + pOffsetAngle) * 0.2 + 1.75, | |
y: Math.sin(90 * Math.PI/180 + pOffsetAngle) * 0.2 | |
}; | |
gTitle.append("text") | |
.attr("class", "house-members") | |
.attr("text-anchor", "middle") | |
.attr("x", center.x * 100 + centerOffset.x) | |
.attr("y", (1.75 - center.y) * 100 + centerOffset.y + (direction * 28)) | |
.style("fill", "#333") | |
.text(pData.totalMembers); | |
center = { | |
x: Math.cos(90 * Math.PI/180 + pOffsetAngle) * 0.05 + 1.75, | |
y: Math.sin(90 * Math.PI/180 + pOffsetAngle) * 0.05 | |
}; | |
gTitle.append("text") | |
.attr("class", "house-name") | |
.attr("text-anchor", "middle") | |
.attr("x", center.x * 100 + centerOffset.x) | |
.attr("y", (1.75 - center.y) * 100 + centerOffset.y + (direction * 12)) | |
.style("fill", "#333") | |
.text(pData.name); | |
var spot = -1; | |
pData.parties.forEach(function(party) { | |
var gParty = gHouse.select(".party .party-" + party.id); | |
if(gParty.empty()) { | |
gParty = gHouse.append("g") | |
.datum(party) | |
.attr("class", "party party-" + party.id); | |
} | |
var circles = gParty.selectAll(".node." + pData.id) | |
.data(d3.range(spot+1, spot+party.totalMembers+1)); | |
circles.enter().append("circle") | |
.attr("class", function(d) { | |
var dref = dataRef[d]; | |
return "node " + dref.id + " node" + dref.row; | |
}) | |
.attr("r", maxRadius * 100); | |
circles | |
.attr("cx", function(d) { | |
var dref = dataRef[d]; | |
return dref.x * 100 + centerOffset.x; | |
}) | |
.attr("cy", function(d) { | |
var dref = dataRef[d]; | |
return (1.75 - dref.y) * 100 + centerOffset.y; | |
}) | |
.style("fill", partyColors[party.id].color || "#333"); | |
circles.exit().remove(); | |
spot = spot + party.totalMembers; | |
}); | |
} | |
function drawLegend(svg) { | |
var legend = svg.selectAll(".legend") | |
.data(d3.map(partyColors).values()) | |
.enter().append("g") | |
.attr("class", "legend") | |
.attr("transform", function(d, i) { return "translate(0," + (i * 20 + 50) + ")"; }); | |
legend.append("rect") | |
.attr("x", width - 18) | |
.attr("width", 18) | |
.attr("height", 18) | |
.style("fill", function(d) { return d.color; }); | |
legend.append("text") | |
.attr("x", width - 24) | |
.attr("y", 9) | |
.attr("dy", ".35em") | |
.style("text-anchor", "end") | |
.style("fill", "#666") | |
.text(function(d) { return d.name; }); | |
} | |
} | |
var data = [{ | |
"id": "usa", | |
"country": "USA", | |
"code": "US", | |
"houses": [{ | |
"id": "house", | |
"name": "House", | |
"totalMembers": 435, | |
"parties": [ | |
{ | |
"id": "d", | |
"name": "Democrats", | |
"totalMembers": 200 | |
}, | |
{ | |
"id": "r", | |
"name": "Republicans", | |
"totalMembers": 233 | |
}, | |
{ | |
"id": "vacant", | |
"name": "Vacant", | |
"totalMembers": 2 | |
} | |
] | |
}, | |
{ | |
"id": "senate", | |
"name": "Senate", | |
"totalMembers": 100, | |
"parties": [ | |
{ | |
"id": "d", | |
"name": "Democrats", | |
"totalMembers": 53 | |
}, | |
{ | |
"id": "r", | |
"name": "Republicans", | |
"totalMembers": 45 | |
}, | |
{ | |
"id": "i", | |
"name": "Independent", | |
"totalMembers": 2 | |
} | |
] | |
}] | |
}]; | |
parliamentCharts(d3.select(".chart"), data); |
body { | |
background: #C1BBB8; | |
} | |
.chart { | |
border: none; | |
background: none; | |
} | |
.chart h3 { | |
padding: 0 12px; | |
} | |
.house .house-members { | |
font-size: 32px; | |
font-weight: 500; | |
} | |
.house .house-name { | |
font-size: 12px; | |
font-weight: 100; | |
text-transform: uppercase; | |
letter-spacing: 1px; | |
} |
Layout of US House & Senate members in an arc using D3. Based on code from http://en.wikipedia.org/wiki/User_talk:Slashme/parliament.py
A Pen by Liji Jinaraj on CodePen.