prototype: slide 02 — clickable missing-pieces center (popups on rects + icons)

- the four 'to build' rects now open popups explaining each missing
  piece (Clinical Intelligence, Datawarehouse, ML-ready data,
  Professional Portal) with 'The gap' highlight box
- system icons keep their own problem popups; pop positioned near the
  clicked element with the red connector line
This commit is contained in:
Codex
2026-09-07 12:03:47 +02:00
parent b4bda2f163
commit f796b14b70
+38 -5
View File
@@ -97,6 +97,7 @@
.missing-title { position: absolute; font: 700 30px/1.2 var(--sans); color: var(--bordeaux-deep); }
.todo-stack { position: absolute; z-index: 2; }
.todo-stack .todo { cursor: pointer; }
.isle .ico { color: var(--bordeaux); }
.isle.ghost .ico { color: #9a938f; }
.isle .nm { font-size: 15px; }
@@ -220,10 +221,10 @@ function ghostIsle(g, size, rot, x, y) {
/* ---- A · Constellation: scattered islands (hand-placed, organic jitter) ---- */
const TODO_STACK = [
['Clinical Intelligence', 'dashboards on the clinical history of the Unit and its patients'],
['Datawarehouse', 'the single source of truth'],
['ML-ready data', 'cohort tables, ready for model training'],
['Professional Portal', 'AritmoLab — the grown-up Omics Portal'],
{ key: 'ci', name: 'Clinical Intelligence', cap: 'dashboards on the clinical history of the Unit and its patients' },
{ key: 'dwh', name: 'Datawarehouse', cap: 'the single source of truth' },
{ key: 'ml', name: 'ML-ready data', cap: 'cohort tables, ready for model training' },
{ key: 'portal', name: 'Professional Portal', cap: 'AritmoLab — the grown-up Omics Portal' },
];
/* three placements of the central "to build" rectangles */
@@ -251,7 +252,7 @@ const ORBIT_CFG = {
function orbitSlide02(v) {
const cfg = ORBIT_CFG[v];
let h = `<div class="todo-stack" style="left:${cfg.stack.left}; top:${cfg.stack.top}; width:${cfg.stack.width}">` +
TODO_STACK.map(([n, c], i) => `<div class="todo" style="margin-left:${cfg.offsets[i]}"><span class="q">?</span><span class="tx"><b>${n}</b><span>${c}</span></span></div>`).join('') + `</div>`;
TODO_STACK.map((td, i) => `<div class="todo" data-missing="${td.key}" style="margin-left:${cfg.offsets[i]}"><span class="q">?</span><span class="tx"><b>${td.name}</b><span>${td.cap}</span></span></div>`).join('') + `</div>`;
for (const s of cfg.isles) {
const sys = SYS.find(vv => vv.key === s.key);
h += `<button class="isle" data-start="${s.key}" style="--rot:${s.rot}deg; --size:${s.size}px; left:${s.x}; top:${s.y}; width:230px">
@@ -332,6 +333,29 @@ pop.className = 'ai-pop';
pop.innerHTML = `<div class="ai-pop-card" role="dialog"><button class="ai-pop-x">✕</button>
<div class="ai-pop-kicker" id="kick"></div><div class="ai-pop-title" id="ttl"></div><div id="bdy"></div></div>`;
document.body.appendChild(pop);
const MISSING_CONTRIBS = {
ci: { kicker: 'The missing piece · 20 years ago', title: 'Clinical Intelligence — the history, made visible',
body: `<p class="lead">Twenty years of clinical history, with no way to show it.</p>
<ul class="pop-list"><li><b>What it is</b> — dashboards on the Unit's activity and its patients: volumes, incidence, outcomes</li>
<li><b>Who needed it</b> — management, audit, clinical research</li>
<li><b>Why it never existed</b> — the data was in prose; building dashboards on text was impractical</li></ul>
<div class="roi"><b class="k">The gap</b>No fast answer to “how are we doing?” — every question meant a manual query.</div>` },
dwh: { kicker: 'The missing piece · 20 years ago', title: 'Datawarehouse — one analysis-ready home',
body: `<p class="lead">One home for every record the Unit produces: text, structured fields, genetics, ECG.</p>
<ul class="pop-list"><li><b>What it is</b> — a single schema joining all the sources, designed for analysis</li>
<li><b>Why it never existed</b> — each system kept its own silo; joining them meant hand-stitching exports</li></ul>
<div class="roi"><b class="k">The gap</b>Every research question started with manual exports — and ended in fragile spreadsheets.</div>` },
ml: { kicker: 'The missing piece · 20 years ago', title: 'ML-ready data — cohorts for research',
body: `<p class="lead">Tables shaped for statistics and model training: clean, wide, reproducible.</p>
<ul class="pop-list"><li><b>What it is</b> — one row per patient, features beside outcomes, rebuildable at will</li>
<li><b>Why it never existed</b> — building it by hand from free text and separate silos took weeks</li></ul>
<div class="roi"><b class="k">The gap</b>Predictive research on the Unit's data stayed out of reach.</div>` },
portal: { kicker: 'The missing piece · 20 years ago', title: 'Professional Portal — the 360° view',
body: `<p class="lead">The 360° view of the patient: Cardioref and genetics finally in one place.</p>
<ul class="pop-list"><li><b>What it is</b> — the grown-up Omics Portal: management, care and research on the same platform</li>
<li><b>Why it never existed</b> — the idea was there; the integrated data to feed it was not</li></ul>
<div class="roi"><b class="k">The gap</b>A single door for patients and clinicians — promised, never delivered.</div>` },
};
document.addEventListener('click', (e) => {
const s = e.target.closest('[data-start]');
if (s) {
@@ -342,6 +366,15 @@ document.addEventListener('click', (e) => {
pop.classList.add('open');
return;
}
const m = e.target.closest('[data-missing]');
if (m) {
const c = MISSING_CONTRIBS[m.dataset.missing];
document.getElementById('kick').textContent = c.kicker;
document.getElementById('ttl').textContent = c.title;
document.getElementById('bdy').innerHTML = c.body;
pop.classList.add('open');
return;
}
if (e.target.closest('.ai-pop-x') || e.target === pop) pop.classList.remove('open');
});
document.addEventListener('keydown', (e) => { if (e.key === 'Escape') pop.classList.remove('open'); });