<template>
  <div>
    <div class="wrap">
      <h1>Patient vitals, one reference range</h1>
      <p class="lead">
        The normal band is declared once and drawn in all twelve panels, so the
        question "who is outside the range" is answered by looking, and P-07's
        tachycardia is unmissable. Hover anywhere: one card reads every patient
        at the same hour.
      </p>

      <div class="chart-wrap">
        <div id="chart">
          <apexchart
            type="line"
            :options="chartOptions"
            :series="series"
          ></apexchart>
        </div>
      </div>

      <div class="note">
        A trellis-scoped annotation is declared once on the host and projected
        into every panel through each panel's own scale, so twelve
        hand-annotated charts collapse into one
        <code>annotations.yaxis</code> entry. An annotation with
        <code>scope: 'P-07'</code> draws only in that patient's panel (the
        medication event). <code>trellis.tooltip: 'grid'</code>
        composes ONE tooltip card with one row per panel at the hovered hour,
        honoring the y formatter, and works even on panels a virtualized grid
        has not mounted. Trellis is a premium feature; without a license it
        renders with a trial watermark.
      </div>
    </div>
  </div>
</template>

<script>
import VueApexCharts from 'vue-apexcharts'

import 'apexcharts/features/trellis'

// 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),
  })
}

export default {
  components: {
    apexchart: VueApexCharts,
  },
  data: function () {
    return {
      series: patientSeries,
      chartOptions: {
        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',
          },
        },
      },
    }
  },
}
</script>

<style>
body {
  font-family:
    -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  background: #fafbfc;
  color: #2c3e50;
  margin: 0;
  padding: 32px 16px;
}
.wrap {
  max-width: 1040px;
  margin: 0 auto;
}
h1 {
  font-size: 22px;
  margin: 0 0 8px;
}
.lead {
  color: #5b6b78;
  line-height: 1.5;
  margin: 0 0 20px;
}
.chart-wrap {
  background: #fff;
  border-radius: 8px;
  padding: 16px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.04);
}
.note {
  background: #f0fdf4;
  border-left: 3px solid #16a34a;
  padding: 12px 16px;
  font-size: 13px;
  color: #333;
  border-radius: 2px;
  line-height: 1.6;
  margin: 26px auto 0;
}
.note code {
  background: #dcfce7;
  padding: 1px 5px;
  border-radius: 3px;
}
</style>