import React from 'react'
import ReactApexChart from 'react-apexcharts'
import ApexCharts from 'apexcharts'
import './styles.css'
// Each dot is one seat. Parties sit left to right as contiguous wedges of the
// hemicycle; the same 315 seats recolour in place as the result changes, so you
// watch the majority form. Shared by the vanilla-js, React and Vue builds.
var PARTIES = [
'Progressives',
'Conservatives',
'Greens',
'Liberals',
'Centre',
'Independents',
]
var MAJORITY = 158 // of 315 seats
var RESULTS = {
2019: [82, 78, 45, 40, 38, 32], // fragmented: no single majority
2023: [60, 162, 30, 28, 20, 15], // the Conservatives sweep to a majority
}
// Leading party + whether anyone cleared the majority line, for the readout.
function readoutFor(year) {
var seats = RESULTS[year]
var topIdx = 0
for (var i = 1; i < seats.length; i++) {
if (seats[i] > seats[topIdx]) topIdx = i
}
var top = seats[topIdx]
var verdict =
top >= MAJORITY
? '<b>' +
PARTIES[topIdx] +
'</b> hold an outright majority (' +
top +
' of 315).'
: 'No majority: <b>' +
PARTIES[topIdx] +
'</b> lead with ' +
top +
' of 315, short of ' +
MAJORITY +
'.'
return year + ': ' + verdict
}
const ApexChart = () => {
const [state, setState] = React.useState({
series: [82, 78, 45, 40, 38, 32],
options: {
chart: {
id: 'parliament',
type: 'unit',
height: 440,
animations: {
enabled: true,
speed: 800,
},
},
labels: [
'Progressives',
'Conservatives',
'Greens',
'Liberals',
'Centre',
'Independents',
],
colors: [
'#E3000F',
'#1E6FD9',
'#3DA35D',
'#F0A202',
'#17A2B8',
'#6C757D',
],
legend: {
position: 'bottom',
},
plotOptions: {
unit: {
layout: 'arc',
arc: {
innerRadiusRatio: 0.35,
},
tooltip: {
// Party name + its seat total for the hovered seat.
formatter: function (o) {
return '<b>' + o.seriesName + '</b><br/>' + o.count + ' seats'
},
},
},
},
},
})
React.useEffect(() => {
// Reach the live instance by its chart.id, then wire the buttons.
// (RESULTS / readoutFor live in the shared head script.)
let chart
const timer = window.setInterval(() => {
chart = ApexCharts.getChartByID('parliament')
if (!chart) return
window.clearInterval(timer)
const readout = document.querySelector('#readout')
const btn2019 = document.querySelector('#btn2019')
const btn2023 = document.querySelector('#btn2023')
const show = (year, btn) => {
btn2019.classList.toggle('active', btn === btn2019)
btn2023.classList.toggle('active', btn === btn2023)
readout.innerHTML = readoutFor(year)
chart.updateSeries(RESULTS[year])
}
btn2019.addEventListener('click', () => show(2019, btn2019))
btn2023.addEventListener('click', () => show(2023, btn2023))
readout.innerHTML = readoutFor(2019)
}, 50)
return () => window.clearInterval(timer)
}, [])
return (
<div>
<div className="wrap">
<h1>A parliament, one election apart</h1>
<div className="controls">
<button id="btn2019" className="active" type="button">
2019
</button>
<button id="btn2023" type="button">
2023
</button>
</div>
<div className="chart-wrap">
<div id="chart">
<ReactApexChart
options={state.options}
series={state.series}
type="unit"
height={440}
/>
</div>
<p className="lead">
One dot is one seat. Toggle the year and the same 315 seats recolour
in place as the chamber recomposes.
</p>
</div>
<div className="readout" id="readout"></div>
</div>
</div>
)
}
export default ApexChart