<template>
  <div>
    <div class="wrap">
      <h1>A parliament, one election apart</h1>

      <div class="controls">
        <button id="btn2019" class="active" type="button">2019</button>
        <button id="btn2023" type="button">2023</button>
      </div>

      <div class="chart-wrap">
        <div id="chart">
          <apexchart
            type="unit"
            height="440"
            :options="chartOptions"
            :series="series"
          ></apexchart>
        </div>
        <p class="lead">
          One dot is one seat. Toggle the year and the same 315 seats recolour
          in place as the chamber recomposes.
        </p>
      </div>
      <div class="readout" id="readout"></div>
    </div>
  </div>
</template>

<script>
import VueApexCharts from 'vue-apexcharts'
import ApexCharts from 'apexcharts'

// 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
}

export default {
components: {
apexchart: VueApexCharts,
},
data: function () {
return {
series: [82, 78, 45, 40, 38, 32],
chartOptions: {
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'
      },
    },
  },
},
},
parliamentTimer: null,
}
},
mounted: function () {
  // Reach the live instance by its chart.id, then wire the buttons.
  // (RESULTS / readoutFor live in the shared head script.)
  var me = this
  me.parliamentTimer = window.setInterval(function () {
    var chart = ApexCharts.getChartByID('parliament')
    if (!chart) return
    window.clearInterval(me.parliamentTimer)

    var readout = document.querySelector('#readout')
    var btn2019 = document.querySelector('#btn2019')
    var btn2023 = document.querySelector('#btn2023')

    var show = function (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', function () { show(2019, btn2019) })
    btn2023.addEventListener('click', function () { show(2023, btn2023) })
    readout.innerHTML = readoutFor(2019)
  }, 50)
},
beforeDestroy: function () {
  window.clearInterval(this.parliamentTimer)
},,
}
</script>

<style>
body {
  font-family:
    -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  background: #fafbfc;
  color: #2c3e50;
  margin: 0;
  padding: 32px 16px;
}
.wrap {
  max-width: 720px;
  margin: 0 auto;
}
h1 {
  font-size: 22px;
  margin: 0 0 8px;
}
.chart-wrap {
  background: #fff;
  border-radius: 8px;
  padding: 16px 16px 8px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.04);
}
.lead {
  color: #5b6b78;
  line-height: 1.5;
  margin: 14px 2px 0;
  font-size: 14px;
}
.controls {
  margin: 8px auto 18px;
  text-align: center;
}
.controls button {
  font: inherit;
  font-size: 14px;
  cursor: pointer;
  border: 1px solid #d4dbe0;
  background: #fff;
  color: #2c3e50;
  padding: 8px 18px;
  border-radius: 999px;
  margin: 0 4px;
}
.controls button.active {
  background: #2c3e50;
  border-color: #2c3e50;
  color: #fff;
}
.readout {
  text-align: center;
  margin-top: 14px;
  font-size: 14px;
  color: #5b6b78;
  min-height: 20px;
}
.readout b {
  color: #2c3e50;
}
</style>
Parliament - Vue Unit Charts | ApexCharts.js | ApexCharts.js