|
<!DOCTYPE html> |
|
<meta charset='utf-8'> |
|
<style> |
|
svg { |
|
font: 11px sans-serif; |
|
} |
|
.header { |
|
text-anchor: start; |
|
font: bold 16px sans-serif; |
|
} |
|
.legend { |
|
text-anchor: start; |
|
font: 13px sans-serif; |
|
} |
|
.legend-r { |
|
text-anchor: end; |
|
font: 13px sans-serif; |
|
} |
|
rect.seat { |
|
stroke-width: .5; |
|
} |
|
line { |
|
shape-rendering: crispEdges; |
|
} |
|
|
|
</style> |
|
<body> |
|
<script src="//d3js.org/d3.v3.min.js" charset="utf-8"></script> |
|
<script src="util.js"></script> |
|
<script> |
|
|
|
|
|
function toSeats ( lineup ) { |
|
var _lineup = []; |
|
lineup.forEach(d => { |
|
for (var i=0; i<parties[d].seats; i++) { |
|
_lineup.push({ id: d, index: _lineup.length }); |
|
} |
|
}); |
|
while (_lineup.length < total_mps) { |
|
_lineup.push({ id: '?', index: _lineup.length }); |
|
} |
|
return _lineup; |
|
} |
|
|
|
|
|
var margin = { top: 20, right: 10, bottom: 25, left: 3 }, |
|
width = 960 - margin.left - margin.right, |
|
height = 1500 - margin.top - margin.bottom, |
|
cx = width / 2; |
|
|
|
var total_mps = 63; |
|
var half_mps = total_mps / 2; |
|
var parties = { |
|
'?': { |
|
id: '?', |
|
party: 'Aðrir', |
|
// color: '#bbb', |
|
percent: 0, |
|
} |
|
}; |
|
|
|
var common_coalitions = [ |
|
['B','D'], // núverandi stjórn |
|
['S','V','A'], // vinstri stjórn |
|
['D','C','B'], // hægri stórn |
|
['A','S','V','P'], // stjórnarandstaðan |
|
['A','C','S','P'], // |
|
]; |
|
|
|
var svg = d3.select( 'body' ).append( 'svg' ) |
|
.attr( 'width', width + margin.left + margin.right ) |
|
.attr( 'height', height + margin.top + margin.bottom ) |
|
.append( 'g' ) |
|
.attr( 'transform', `translate(${margin.left},${margin.top})` ); |
|
|
|
svg.append('defs') |
|
.append('pattern') |
|
.attr('id', 'stripes') |
|
.attr('patternUnits', 'userSpaceOnUse') |
|
.attr('width', 4) |
|
.attr('height', 4) |
|
.append('path') |
|
.attr('d', "M0,4 l4,-4 M-1,1 l2,-2 M3,5 l2,-2") |
|
.attr('stroke-width', 1) |
|
.attr('shape-rendering', 'auto') |
|
.attr('stroke', '#aaa') |
|
.attr('stroke-linecap', 'square'); |
|
|
|
d3.csv('data.csv', function ( err, data ) { |
|
|
|
data.forEach(d => { |
|
d.count = +d.count; |
|
d.percent = +d.percent; |
|
d.prection_percent = +d.prection_percent; |
|
d.seats = +d.seats; |
|
parties[d.id] = d; |
|
}); |
|
// dhont( data, total_mps ); |
|
|
|
var sections = []; |
|
|
|
var pool = d3.comb(Object.keys(parties)) |
|
.map(lineup => { |
|
var comb = obj(lineup); |
|
// These have declared they won't work together |
|
// http://stundin.is/frett/piratar-utiloka-framsoknarflokkinn-og-sjalfstaedis/ |
|
if (('P' in comb && ('D' in comb || 'B' in comb)) || |
|
('D' in comb && ('V' in comb || 'S' in comb))) { |
|
return null; |
|
} |
|
var id = lineup.sort(d3.ascending).join(''), |
|
counts = lineup.map(d => parties[d].seats).sort(d3.descending), |
|
mps = d3.sum(counts), |
|
but_last = d3.sum(counts.slice(0,-1)); |
|
|
|
if (but_last > half_mps) { return null; } |
|
|
|
if (mps && mps > half_mps) { |
|
lineup = lineup.sort((a,b) => d3.descending(parties[a].percent, parties[b].percent)); |
|
return { |
|
'id': id, |
|
'mps': mps, |
|
'seats': toSeats(lineup), |
|
'lineup': lineup, |
|
}; |
|
} |
|
}) |
|
.filter(Boolean) |
|
.sort((a,b) => b.mps - a.mps); |
|
|
|
sections.push({ |
|
'offset': 0, |
|
'title': "Mögulegar meirihlutastjórnir", |
|
'combinations': pool, |
|
}); |
|
|
|
|
|
var runners_up = common_coalitions |
|
.map(lineup => { |
|
var id = lineup.sort(d3.ascending).join(''); |
|
if (pool.filter( d=> d.id === id).length) { |
|
// already exists in pool |
|
return null; |
|
} |
|
lineup = lineup.sort((a,b) => d3.descending(parties[a].percent, parties[b].percent)); |
|
return { |
|
'id': id, |
|
'mps': d3.sum(lineup, d => parties[d].seats), |
|
'seats': toSeats(lineup), |
|
'lineup': lineup, |
|
}; |
|
}); |
|
|
|
sections.push({ |
|
'offset': d3.sum(sections, d => d.combinations.length + 1), |
|
'title': 'Pólitískur ómöguleiki', |
|
'combinations': runners_up.filter(Boolean), |
|
}); |
|
|
|
// reconfigure chart height: |
|
height = d3.sum(sections, d => 1 + d.combinations.length) * 45; |
|
svg.attr('height', height + margin.top + margin.bottom); |
|
console.log( height ); |
|
svg.append('rect') |
|
.attr('width', width) |
|
.attr('height', height) |
|
.attr('fill', 'white'); |
|
|
|
var x = d3.scale.linear() |
|
.domain([ 0, total_mps ]) |
|
.range([ 0, Math.floor(width/total_mps) * total_mps ]); |
|
|
|
var y = d3.scale.ordinal() |
|
.domain(pool.map(d => d.id)) |
|
.rangeBands([ 0, pool.length * 45 ]); |
|
|
|
var sects = svg.selectAll('.section') |
|
.data(sections).enter() |
|
.append('g') |
|
.attr('class', 'section') |
|
.attr('transform', d => `translate(0,${(1+d.offset) * 45})`); |
|
|
|
sects.append('text') |
|
.attr('class', 'header') |
|
.attr('y', -30) |
|
.text(d => d.title); |
|
|
|
var stacks = sects.selectAll('.stack') |
|
.data(d => d.combinations).enter() |
|
.append('g') |
|
.attr('class', 'stack') |
|
.attr('transform', (d, i) => `translate(0,${i * 45})`); |
|
|
|
stacks.append('text') |
|
.attr('class', 'legend') |
|
.attr('dy', -5) |
|
.text(d => { |
|
var t = d.lineup.map(d => parties[d].party).join(', '); |
|
return d.mps + ' þingsæti: ' + t + '.'; |
|
}); |
|
|
|
stacks.append('text') |
|
.attr('class', 'legend-r') |
|
.attr('x', x(total_mps)) |
|
.attr('dy', -5) |
|
.text(d => { |
|
return (d.mps < half_mps) |
|
? `Vantar ${-Math.floor(d.mps - half_mps)} þingsæti.` |
|
: `${(d.mps - half_mps)*2} sæta meirihluti.`; |
|
}); |
|
|
|
var bars = stacks.selectAll('.seat') |
|
.data(d => d.seats).enter(); |
|
|
|
bars.append('rect') |
|
.attr('class', 'seat') |
|
.attr('x', d => x(d.index)) |
|
.attr('height', x(1)) |
|
.attr('width', x(1)) |
|
.attr('fill', d => parties[d.id].color || 'url(#stripes)') |
|
.attr('stroke', 'white'); |
|
|
|
bars.append('circle') |
|
.attr('class', 'empty-seat') |
|
.attr('cy', x(1) / 2) |
|
.attr('cx', d => x(d.index) + x(1) / 2) |
|
.attr('r', x(1) / 5) |
|
.attr('fill', d => { |
|
if ( d.index < half_mps && d.id === '?' ) { |
|
return 'gray'; |
|
} |
|
if ( d.index > half_mps - 1 && d.id !== '?' ) { |
|
return 'white'; |
|
} |
|
return 'none'; |
|
}) |
|
.attr('stroke', d => { |
|
if ( d.index < half_mps && d.id === '?' ) { |
|
return 'white'; |
|
} |
|
if ( d.index > half_mps - 1 && d.id !== '?' ) { |
|
return 'gray'; |
|
} |
|
return 'none'; |
|
}); |
|
|
|
|
|
}); |
|
</script> |