Continuous Datetime in JavaScript

Using ApexCharts with JavaScript

This Continuous Datetime example uses ApexCharts.js directly in JavaScript, with no wrapper component.

Install it with npm install apexcharts, then mount the chart with new ApexCharts(element, options).render().

JavaScript installation guide
// 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),
]

var options = {
  series: heatData,
  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 + '%'
      },
    },
  },
}

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