// Shared by the vanilla-js, React and Vue builds. A synthetic population model:
// as the minimum age rises, the crowd shrinks and the female share dips. Each
// dot is one person; colour is gender; the female minority nests in the centre
// of the packed blob. Dragging the slider re-buckets the data and the dots
// redistribute in place, they do not rebuild from scratch.
function countsForAge(minAge) {
  var frac = (90 - minAge) / 45 // 1 at age 45, 0 at age 90
  var total = Math.round(180 + 760 * frac)
  var femaleShare = 0.2 + 0.16 * frac
  var female = Math.round(total * femaleShare)
  return { female: female, male: total - female, total: total }
}

function readoutText(minAge) {
  var c = countsForAge(minAge)
  var pct = ((c.female / c.total) * 100).toFixed(1)
  return (
    c.total.toLocaleString() +
    ' people aged ' +
    minAge +
    '+, ' +
    c.female.toLocaleString() +
    ' female (' +
    pct +
    '%)'
  )
}

var options = {
  series: [338, 602],
  chart: {
    id: 'popChart',
    type: 'unit',
    height: 460,
    animations: {
      enabled: true,
      speed: 700,
    },
  },
  labels: ['Female', 'Male'],
  colors: ['#EE5A8F', '#1AA5A0'],
  legend: {
    position: 'bottom',
  },
  plotOptions: {
    unit: {
      layout: 'packed',
      sortByGroup: true,
      spacing: 1.1,
    },
  },
}

var chart = new ApexCharts(document.querySelector('#chart'), options)
chart.render()

// countsForAge and readoutText live in the shared head script.
var ageInput = document.querySelector('#age')
var readout = document.querySelector('#readout')

ageInput.addEventListener('input', function () {
  var minAge = parseInt(ageInput.value, 10)
  readout.textContent = readoutText(minAge)
  var c = countsForAge(minAge)
  chart.updateSeries([c.female, c.male])
})
Population Explorer - JavaScript Unit Charts | ApexCharts.js | ApexCharts.js