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

// A continuous-axis heatmap: rows stay categorical (one host per row) while the
// x axis is a real datetime scale. Each cell sits at its true timestamp and the
// axis shows sparse proportional date/time ticks instead of one label per cell.
// Because cells are placed by value, a metrics outage (when the collector
// stopped reporting for every host at once) shows up as real empty space, which
// index-based tiling cannot represent.
var HOUR = 60 * 60 * 1000
var start = new Date('2024-03-04T00:00:00.000Z').getTime()
var totalHours = 72

// A deterministic pseudo-random generator so the demo is stable across reloads.
function makeRand(seed) {
  var s = seed
  return function () {
    s = (s * 1103515245 + 12345) & 0x7fffffff
    return s / 0x7fffffff
  }
}

// Hours 30..39 are dropped for every host: a 10-hour window where the metrics
// collector was down and no CPU readings were recorded.
function isOutage(h) {
  return h >= 30 && h < 40
}

// CPU utilization (%) with a daily rhythm: load builds through the working day,
// peaks mid-afternoon (14:00 UTC), and falls off overnight. `base` sets the
// baseline load and `swing` the size of the daily peak, so each host has its
// own profile (steady database, spiky web tier, mostly-idle cache).
function hostSeries(name, seed, base, swing) {
  var rand = makeRand(seed)
  var data = []
  for (var h = 0; h < totalHours; h++) {
    if (isOutage(h)) continue
    var hourOfDay = h % 24
    var daily = (Math.cos(((hourOfDay - 14) / 24) * Math.PI * 2) + 1) / 2
    var cpu = base + swing * daily + (rand() - 0.5) * 12
    data.push({
      x: start + h * HOUR,
      y: Math.max(1, Math.min(99, Math.round(cpu))),
    })
  }
  return { name: name, data: data }
}

var heatData = [
  hostSeries('web-01', 7, 22, 52),
  hostSeries('web-02', 19, 20, 56),
  hostSeries('api-01', 42, 27, 46),
  hostSeries('api-02', 88, 25, 49),
  hostSeries('cache-01', 123, 14, 16),
  // The database is the hot box: steady high load that saturates (red) at the
  // afternoon peak.
  hostSeries('db-01', 256, 66, 18),
]

const ApexChart = () => {
  const [state, setState] = React.useState({
    series: heatData,
    options: {
      chart: {
        height: 220,
        type: 'heatmap',
        toolbar: { show: false },
      },
      dataLabels: {
        enabled: false,
      },
      title: {
        text: 'Server CPU utilization across the fleet (a metrics outage shows as a real gap)',
        align: 'left',
      },
      plotOptions: {
        heatmap: {
          // Flat CPU-health buckets on a green (idle) to red (saturated) scale, so a
          // cell's color reads as a load level straight off the legend.
          enableShades: false,
          colorScale: {
            ranges: [
              { from: 0, to: 30, color: '#00A65A', name: '0-30%' },
              { from: 30, to: 50, color: '#7CB342', name: '30-50%' },
              { from: 50, to: 70, color: '#FBC02D', name: '50-70%' },
              { from: 70, to: 85, color: '#FB8C00', name: '70-85%' },
              { from: 85, to: 100, color: '#E53935', name: '85-100%' },
            ],
          },
        },
      },
      xaxis: {
        type: 'datetime',
        labels: {
          datetimeUTC: true,
          datetimeFormatter: {
            year: 'yyyy',
            month: "MMM 'yy",
            day: 'MMM dd',
            hour: 'HH:mm',
          },
        },
      },
      tooltip: {
        x: { show: true, format: 'MMM dd HH:mm' },
        y: {
          formatter: function (val) {
            return val + '%'
          },
        },
      },
    },
  })

  return (
    <div>
      <div id="chart">
        <ReactApexChart
          options={state.options}
          series={state.series}
          type="heatmap"
          height={220}
        />
      </div>
    </div>
  )
}

export default ApexChart
Continuous Datetime - React Heatmap Charts | ApexCharts.js | ApexCharts.js