import React from 'react'
import ReactApexChart from 'react-apexcharts'
import './styles.css'

// A VERTICAL beeswarm: value runs up the Y axis, each species is a column, and
// dots are anti-overlap "swarm" packed so the column's WIDTH reads as density.
// One dot per penguin. Figures are an illustrative sample around the real
// Palmer Archipelago body-mass distributions (Gentoo run visibly heavier).
// Shared by the vanilla-js / React / Vue builds.
var SPECIES = [
  { name: 'Adelie', mean: 3700, sd: 460, n: 44 },
  { name: 'Chinstrap', mean: 3733, sd: 385, n: 34 },
  { name: 'Gentoo', mean: 5076, sd: 505, n: 40 },
]

// Deterministic normal-ish sample (Irwin-Hall of 6 uniforms via an LCG): stable
// across re-renders and SSR, no Math.random. Rounded to the nearest 25 g.
function swarm(mean, sd, n, seed) {
  var out = []
  var s = seed >>> 0
  function u() {
    s = (s * 1664525 + 1013904223) >>> 0
    return s / 4294967296
  }
  for (var i = 0; i < n; i++) {
    var g = 0
    for (var k = 0; k < 6; k++) g += u()
    var z = (g - 3) / Math.sqrt(0.5)
    out.push(Math.round((mean + z * sd) / 25) * 25)
  }
  return out
}

var swarmSeries = SPECIES.map(function (sp, i) {
  return {
    name: sp.name,
    data: swarm(sp.mean, sp.sd, sp.n, 97 + i * 613).map(function (v, j) {
      return { name: sp.name + ' ' + (j + 1), value: v }
    }),
  }
})

const ApexChart = () => {
  const [state, setState] = React.useState({
    series: swarmSeries,
    options: {
      chart: {
        id: 'bodyMassSwarm',
        type: 'unit',
        height: 460,
        fontFamily: 'inherit',
        animations: {
          enabled: true,
          speed: 700,
        },
      },
      colors: ['#eb6834', '#4a3aa7', '#1baf7a'],
      legend: {
        position: 'bottom',
        markers: { radius: 12 },
      },
      plotOptions: {
        unit: {
          layout: 'scatter',
          size: 4.4,
          scatter: {
            orientation: 'vertical',
            spread: 'swarm',
            xMin: 2000,
            xMax: 6000,
            tickAmount: 5,
            xTitle: 'Body mass',
            xFormatter: function (v) {
              return (v / 1000).toFixed(1) + ' kg'
            },
          },
        },
      },
      tooltip: {
        enabled: true,
      },
    },
  })

  return (
    <div>
      <div className="wrap">
        <h1>How much does a penguin weigh?</h1>
        <p className="lead">
          One dot per penguin, stacked into a column per species. The swarm
          packs dots side by side with no overlap, so each column's width is its
          density, you read the spread and the clusters, not just an average.
        </p>

        <div className="card">
          <div id="chart">
            <ReactApexChart
              options={state.options}
              series={state.series}
              type="unit"
              height={460}
            />
          </div>
        </div>

        <div className="note">
          A vertical beeswarm is <code>plotOptions.unit.scatter</code> with
          <code>orientation: 'vertical'</code>: the value sits on the Y axis and
          each category becomes a column across X. <code>spread: 'swarm'</code>{' '}
          packs equal and near-equal values off the centre line so nothing
          overlaps, turning each column into a density silhouette. The unit
          chart is a premium type, without a license it renders with a trial
          watermark.
        </div>
      </div>
    </div>
  )
}

export default ApexChart
Vertical Beeswarm - React Unit Charts | ApexCharts.js | ApexCharts.js