Clinical Reference Bands in JavaScript

Using ApexCharts with JavaScript

This Clinical Reference Bands 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
// Twelve patients, one reference range: the 60-100 bpm normal band is
// declared ONCE on the host and drawn in every panel, projected through the
// shared scale, so no panel's band can ever be wrong. A second annotation
// carries `scope: 'P-07'`: the medication event line appears only in that
// patient's panel. Hover anywhere: `tooltip: 'grid'` shows ONE card with
// every patient's reading at the hovered hour.
//
// Deterministic vitals so the e2e snapshot is stable.
function mulberry32(seed) {
  return function () {
    seed |= 0
    seed = (seed + 0x6d2b79f5) | 0
    var t = Math.imul(seed ^ (seed >>> 15), 1 | seed)
    t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t
    return ((t ^ (t >>> 14)) >>> 0) / 4294967296
  }
}

var T0 = new Date('01 Jan 2025').getTime()

function heartRate(seed, base, tachyFrom) {
  var rand = mulberry32(seed)
  var out = []
  var ts = T0
  var val = base
  for (var i = 0; i < 48; i++) {
    val += (rand() - 0.5) * 6
    var v = val
    // P-07 trends tachycardic until the 30h medication event pulls it back.
    if (tachyFrom && i >= tachyFrom && i < 30) v = val + 28
    if (tachyFrom && i >= 30) v = val + Math.max(0, 28 - (i - 30) * 3)
    out.push([ts, Math.round(v)])
    ts += 3600000 // hourly
  }
  return out
}

var patientSeries = []
for (var p = 1; p <= 12; p++) {
  var id = 'P-' + (p < 10 ? '0' + p : p)
  patientSeries.push({
    name: 'Heart rate',
    patient: id,
    data: heartRate(p * 7, 68 + (p % 5) * 4, p === 7 ? 12 : 0),
  })
}

var options = {
  series: patientSeries,
  chart: {
    id: 'vitalsTrellis',
    type: 'line',
    animations: {
      enabled: false,
    },
  },
  trellis: {
    by: 'patient',
    minPanelWidth: 240,
    panelHeight: 130,
    gap: 12,
    tooltip: 'grid',
  },
  colors: ['#0F766E'],
  stroke: {
    width: 2,
    curve: 'straight',
  },
  annotations: {
    yaxis: [
      {
        y: 60,
        y2: 100,
        fillColor: '#22C55E',
        opacity: 0.1,
      },
    ],
    xaxis: [
      {
        x: new Date('01 Jan 2025').getTime() + 30 * 3600000,
        scope: 'P-07',
        borderColor: '#D97706',
        strokeDashArray: 4,
        label: {
          text: 'medication',
          orientation: 'horizontal',
          style: {
            color: '#92400E',
            background: '#FEF3C7',
            fontSize: '10px',
          },
        },
      },
    ],
  },
  xaxis: {
    type: 'datetime',
  },
  yaxis: {
    labels: {
      formatter: function (val) {
        return Math.round(val) + ' bpm'
      },
    },
  },
  dataLabels: {
    enabled: false,
  },
  tooltip: {
    x: {
      format: 'dd MMM HH:mm',
    },
  },
}

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