// A 2D bubble scatter: each bubble is a city, placed by average income (x) and
// cost of living (y), sized by a third field and coloured by region. This is
// the unit chart's `layout: 'scatter'` in `y: 'value'` mode (each datum's own x
// + y on two numeric axes) with `sizeRange` turning the dots into area-scaled
// bubbles.
//
// The size toggle is the story: by POPULATION the megacities (Tokyo, Delhi,
// Shanghai, Sao Paulo) swell; by GDP the money centres (Tokyo, New York, London,
// Paris) lead instead. Every bubble tweens its size. Figures are approximate
// (public-data style). Shared by the vanilla-js / React / Vue builds.
var REGIONS = [
  { name: 'Americas', color: '#22C55E' },
  { name: 'Europe', color: '#0EA5E9' },
  { name: 'Asia', color: '#F59E0B' },
  { name: 'Oceania', color: '#F43F5E' },
]

// [city, avg income (US$/yr), cost of living (index, NYC = 100),
//  metro population (millions), metro GDP (US$ billions)]
var DATA = {
  Americas: [
    ['New York', 55000, 100, 18.9, 2000],
    ['San Francisco', 62000, 98, 4.7, 650],
    ['Toronto', 40000, 72, 6.4, 400],
    ['Sao Paulo', 12000, 40, 22.6, 480],
    ['Mexico City', 11000, 38, 22.0, 480],
  ],
  Europe: [
    ['Zurich', 72000, 118, 1.4, 340],
    ['London', 45000, 85, 14.3, 1000],
    ['Paris', 38000, 80, 11.1, 850],
    ['Berlin', 36000, 70, 6.1, 180],
    ['Moscow', 18000, 45, 12.6, 550],
  ],
  Asia: [
    ['Tokyo', 40000, 83, 37.4, 1600],
    ['Singapore', 55000, 95, 5.9, 470],
    ['Dubai', 45000, 70, 3.5, 130],
    ['Hong Kong', 42000, 90, 7.5, 380],
    ['Seoul', 34000, 78, 26.0, 780],
    ['Shanghai', 20000, 60, 27.0, 680],
    ['Mumbai', 8000, 35, 20.7, 310],
    ['Delhi', 7000, 32, 32.0, 370],
  ],
  Oceania: [
    ['Sydney', 48000, 88, 5.3, 400],
    ['Melbourne', 44000, 82, 5.0, 250],
  ],
}

// z = the bubble size field: 'population' (people) or 'gdp' (metro output).
function seriesFor(sizeBy) {
  return REGIONS.map(function (r) {
    return {
      name: r.name,
      data: DATA[r.name].map(function (c) {
        return {
          name: c[0],
          x: c[1],
          y: c[2],
          z: sizeBy === 'gdp' ? c[4] : c[3],
        }
      }),
    }
  })
}

var VIEWS = {
  population: {
    caption:
      'Sized by population, the megacities swell: Tokyo, Delhi, Shanghai and Sao Paulo dominate, even where incomes are low and living is cheap.',
  },
  gdp: {
    caption:
      'Sized by economic output, the money centres take over: New York, Tokyo, London and Paris lead, while populous but poorer cities shrink.',
  },
}

var options = {
  series: seriesFor('population'),
  chart: {
    id: 'cityBubbles',
    type: 'unit',
    height: 520,
    animations: {
      enabled: true,
      speed: 700,
    },
  },
  colors: REGIONS.map(function (r) {
    return r.color
  }),
  // Translucent fills so overlapping bubbles read through each other.
  fill: {
    opacity: 0.7,
  },
  legend: {
    position: 'bottom',
  },
  plotOptions: {
    unit: {
      layout: 'scatter',
      scatter: {
        y: 'value',
        xMin: 0,
        yMin: 0,
        xTitle: 'Average income (US$/yr)',
        yTitle: 'Cost of living (NYC = 100)',
        xFormatter: function (v) {
          return '$' + Math.round(v / 1000) + 'k'
        },
        sizeRange: [7, 44],
      },
      tooltip: {
        formatter: function (o) {
          var d = (o && o.datum) || {}
          if (!d.name) return ''
          return (
            d.name +
            ': $' +
            Math.round(d.x / 1000) +
            'k income, cost of living ' +
            d.y
          )
        },
      },
    },
  },
}

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

// Button-driven size-metric switch: each view is a chart.updateSeries payload
// that changes only the bubble size field, so every bubble tweens its radius.
// (REGIONS, DATA, seriesFor, VIEWS live in the shared head script.)
var buttons = document.querySelectorAll('#size-nav button')
var caption = document.getElementById('caption')

function showSize(key) {
  buttons.forEach(function (b) {
    b.classList.toggle('active', b.getAttribute('data-size') === key)
  })
  caption.textContent = VIEWS[key].caption
  chart.updateSeries(seriesFor(key))
}

buttons.forEach(function (btn) {
  btn.addEventListener('click', function () {
    showSize(btn.getAttribute('data-size'))
  })
})

caption.textContent = VIEWS.population.caption
City Bubbles - JavaScript Unit Charts | ApexCharts.js | ApexCharts.js