@codesys/mcp-toolkit 2.2.0 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +85 -0
- package/README.md +109 -9
- package/README.zh-CN.md +72 -9
- package/dist/actions.d.ts +9 -4
- package/dist/actions.js +1 -1
- package/dist/actions.js.map +1 -1
- package/dist/codesys/debug.d.ts +5 -0
- package/dist/codesys/debug.js +89 -0
- package/dist/codesys/debug.js.map +1 -0
- package/dist/codesys/device-tools.d.ts +3 -0
- package/dist/codesys/device-tools.js +38 -0
- package/dist/codesys/device-tools.js.map +1 -0
- package/dist/codesys/graphical.d.ts +76 -0
- package/dist/codesys/graphical.js +226 -0
- package/dist/codesys/graphical.js.map +1 -0
- package/dist/codesys/lang.d.ts +39 -0
- package/dist/codesys/lang.js +177 -0
- package/dist/codesys/lang.js.map +1 -0
- package/dist/codesys/simtest.d.ts +48 -0
- package/dist/codesys/simtest.js +103 -0
- package/dist/codesys/simtest.js.map +1 -0
- package/dist/codesys/st.d.ts +1 -1
- package/dist/codesys/st.js.map +1 -1
- package/dist/codesys/trace.d.ts +19 -0
- package/dist/codesys/trace.js +139 -0
- package/dist/codesys/trace.js.map +1 -0
- package/dist/hmi/native.d.ts +89 -0
- package/dist/hmi/native.js +447 -0
- package/dist/hmi/native.js.map +1 -0
- package/dist/hmi/render.d.ts +90 -0
- package/dist/hmi/render.js +307 -0
- package/dist/hmi/render.js.map +1 -0
- package/dist/hmi/route.d.ts +32 -0
- package/dist/hmi/route.js +184 -0
- package/dist/hmi/route.js.map +1 -0
- package/dist/hmi/service.d.ts +45 -0
- package/dist/hmi/service.js +182 -0
- package/dist/hmi/service.js.map +1 -0
- package/dist/hmi/spec.d.ts +821 -0
- package/dist/hmi/spec.js +191 -0
- package/dist/hmi/spec.js.map +1 -0
- package/dist/hmi/templates.d.ts +11 -0
- package/dist/hmi/templates.js +92 -0
- package/dist/hmi/templates.js.map +1 -0
- package/dist/hmi/tools.d.ts +4 -0
- package/dist/hmi/tools.js +222 -0
- package/dist/hmi/tools.js.map +1 -0
- package/dist/hmi/value.d.ts +3 -0
- package/dist/hmi/value.js +26 -0
- package/dist/hmi/value.js.map +1 -0
- package/dist/panel/hmi.js +138 -0
- package/dist/panel.d.ts +3 -0
- package/dist/panel.js +17 -0
- package/dist/panel.js.map +1 -1
- package/dist/server.d.ts +1 -1
- package/dist/server.js +7 -2
- package/dist/server.js.map +1 -1
- package/dist/tools.d.ts +5 -1
- package/dist/tools.js +18 -2
- package/dist/tools.js.map +1 -1
- package/dist/viewer.d.ts +1 -1
- package/dist/viewer.js +13 -2
- package/dist/viewer.js.map +1 -1
- package/package.json +1 -1
- package/watcher/mcp_alarms.py +134 -0
- package/watcher/mcp_debug.py +161 -0
- package/watcher/mcp_devices.py +83 -0
- package/watcher/mcp_lang.py +179 -0
- package/watcher/mcp_ops.py +3 -1
- package/watcher/mcp_trace.py +90 -0
- package/watcher/mcp_ui.py +54 -0
- package/watcher/mcp_visu.py +422 -0
- package/watcher/watcher.py +35 -1
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Renders an HMI screen to HTML + SVG on a fixed 1280x720 canvas (scaled to the
|
|
3
|
+
* window by the page). Pure: no DOM, so the server can build screenshot pages
|
|
4
|
+
* and the browser can mount live ones. Values are not rendered here: elements
|
|
5
|
+
* carry `data-b` (an index into `bindings`), and the live client (live.ts)
|
|
6
|
+
* applies values through CSS variables and classes, so animations keep running.
|
|
7
|
+
*/
|
|
8
|
+
import { routed } from "./route.js";
|
|
9
|
+
export const CANVAS = { w: 1280, h: 720, header: 76, pad: 20, gap: 14 };
|
|
10
|
+
/** The canvas of a screen's panel size. */
|
|
11
|
+
export function canvasOf(screen) {
|
|
12
|
+
const [w, h] = (screen.size ?? "1280x720").split("x").map(Number);
|
|
13
|
+
if (h <= 480)
|
|
14
|
+
return { w, h, header: 54, pad: 12, gap: 9 };
|
|
15
|
+
if (h >= 1080)
|
|
16
|
+
return { w, h, header: 96, pad: 28, gap: 18 };
|
|
17
|
+
return { w, h, header: 76, pad: 20, gap: 14 };
|
|
18
|
+
}
|
|
19
|
+
const esc = (s) => s.replace(/[&<>"']/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[c]);
|
|
20
|
+
const r1 = (n) => Math.round(n * 10) / 10;
|
|
21
|
+
export const SERIES_COLORS = ["#38bdf8", "#a78bfa", "#fbbf24", "#34d399", "#f472b6", "#60a5fa"];
|
|
22
|
+
/** The pixel box of a tile on the canvas. */
|
|
23
|
+
export function tileBox(screen, at) {
|
|
24
|
+
const [cols, rows] = screen.grid;
|
|
25
|
+
const { w, h, header, pad, gap } = canvasOf(screen);
|
|
26
|
+
const cw = (w - 2 * pad - (cols - 1) * gap) / cols;
|
|
27
|
+
const ch = (h - header - pad - (rows - 1) * gap) / rows;
|
|
28
|
+
const [c, r, wd, ht] = at;
|
|
29
|
+
return { x: pad + (c - 1) * (cw + gap), y: header + (r - 1) * (ch + gap), w: wd * cw + (wd - 1) * gap, h: ht * ch + (ht - 1) * gap };
|
|
30
|
+
}
|
|
31
|
+
export function renderScreen(screen, page = {}) {
|
|
32
|
+
const bindings = [];
|
|
33
|
+
const bind = (b) => `data-b="${bindings.push(b) - 1}"`;
|
|
34
|
+
let uid = 0;
|
|
35
|
+
const id = (p) => `${p}${++uid}`;
|
|
36
|
+
const faces = [];
|
|
37
|
+
const face = (title, f, extra) => {
|
|
38
|
+
const k = `fp-${faces.length + 1}`;
|
|
39
|
+
faces.push(faceplateHtml(k, title, f, extra, bind));
|
|
40
|
+
return `data-open="${k}"`;
|
|
41
|
+
};
|
|
42
|
+
const cv = canvasOf(screen);
|
|
43
|
+
const tiles = screen.widgets.map((wg) => {
|
|
44
|
+
const box = tileBox(screen, wg.at);
|
|
45
|
+
const inner = widget(wg, box, bind, id, face);
|
|
46
|
+
const title = wg.title ? `<div class="t-title">${esc(wg.title)}</div>` : "";
|
|
47
|
+
return `<section class="tile t-${wg.type}${wg.title ? "" : " untitled"}${box.h < 110 ? " compact" : ""}" style="left:${r1(box.x)}px;top:${r1(box.y)}px;width:${r1(box.w)}px;height:${r1(box.h)}px">${title}<div class="t-body">${inner}</div></section>`;
|
|
48
|
+
});
|
|
49
|
+
const nav = (page.pages?.length ?? 0) > 1 ? `<nav class="h-nav">${page.pages.map((p) => `<button class="h-page${p.name === screen.name ? " cur" : ""}" data-nav="${esc(p.name)}">${esc(p.title)}</button>`).join("")}</nav>` : "";
|
|
50
|
+
const alarmVars = (page.alarms ?? []).map((a) => a.active);
|
|
51
|
+
const badge = alarmVars.length ? `<div class="h-alarm" ${bind({ kind: "count", vars: alarmVars })}><span class="dot"></span><span class="n">0</span><span class="lbl">alarms</span></div>` : "";
|
|
52
|
+
const html = `<div class="hmi theme-${screen.theme}${cv.h <= 480 ? " small" : cv.h >= 1080 ? " large" : ""}" style="width:${cv.w}px;height:${cv.h}px;--hdr:${cv.header}px">
|
|
53
|
+
<div class="glow"></div>
|
|
54
|
+
<svg width="0" height="0" style="position:absolute" aria-hidden="true">${DEFS}</svg>
|
|
55
|
+
<header class="h-bar"><div class="h-titles"><div class="h-title">${esc(screen.title)}</div>${screen.subtitle ? `<div class="h-sub">${esc(screen.subtitle)}</div>` : ""}</div>
|
|
56
|
+
${nav}<div class="h-right">${badge}<div class="h-sim" data-sim><span class="dot"></span><span class="lbl">Offline</span></div><div class="h-clock" data-clock>--:--:--</div></div></header>
|
|
57
|
+
${tiles.join("\n")}
|
|
58
|
+
${faces.join("\n")}
|
|
59
|
+
</div>`;
|
|
60
|
+
return { html, bindings, css: HMI_CSS };
|
|
61
|
+
}
|
|
62
|
+
function faceplateHtml(k, title, f, extra, bind) {
|
|
63
|
+
const status = [
|
|
64
|
+
extra.running ? `<span class="led tone-ok" ${bind({ kind: "on", v: extra.running })}><span class="led-dot"></span>Running</span>` : "",
|
|
65
|
+
extra.open ? `<span class="led tone-ok" ${bind({ kind: "on", v: extra.open })}><span class="led-dot"></span>Open</span>` : "",
|
|
66
|
+
extra.fault ? `<span class="led tone-alarm" ${bind({ kind: "on", v: extra.fault })}><span class="led-dot"></span>Fault</span>` : "",
|
|
67
|
+
].join("");
|
|
68
|
+
const mode = f.auto ? `<label class="sw" data-act="toggle" data-var="${esc(f.auto)}" ${bind({ kind: "on", v: f.auto })}><span class="sw-track"><span class="sw-knob"></span></span><span class="sw-lbl">Automatic</span><span class="sw-state"><span class="s-on">AUTO</span><span class="s-off">MANUAL</span></span></label>` : "";
|
|
69
|
+
const btn = (label, v, tone) => (v ? `<button class="btn tone-${tone}" data-act="tap" data-var="${esc(v)}" ${bind({ kind: "on", v })}>${label}</button>` : "");
|
|
70
|
+
const buttons = [btn("Start", f.start, "ok"), btn("Stop", f.stop, "alarm"), btn("Open", f.open, "ok"), btn("Close", f.close, "alarm"), btn("Reset", f.reset, "warn")].join("");
|
|
71
|
+
const values = (f.values ?? []).map((x) => `<div class="fp-row"><span>${esc(x.label)}</span><b ${bind({ kind: "text", v: x.value, decimals: x.decimals, unit: x.unit })}>–</b></div>`).join("");
|
|
72
|
+
const sp = f.setpoint;
|
|
73
|
+
const setpoint = sp
|
|
74
|
+
? `<div class="fp-sp"><div class="fp-row"><span>${esc(sp.label ?? "Setpoint")}</span></div><div class="sp" data-var="${esc(sp.variable)}" data-min="${sp.min}" data-max="${sp.max}" data-step="${sp.step ?? 1}" ${bind({ kind: "setpoint", v: sp.variable, decimals: 1 })}><div class="sp-row"><button class="sp-btn" data-step="-1">−</button><div class="sp-val"><span class="sp-num" ${bind({ kind: "text", v: sp.variable, decimals: 1 })}>–</span><span class="sp-unit">${esc(sp.unit ?? "")}</span></div><button class="sp-btn" data-step="1">+</button></div><input class="sp-range" type="range" min="${sp.min}" max="${sp.max}" step="${sp.step ?? 1}"></div></div>`
|
|
75
|
+
: "";
|
|
76
|
+
return `<div class="fp" id="${k}" hidden><div class="fp-card"><div class="fp-head"><div class="fp-title">${esc(f.title ?? title)}</div><button class="fp-x" data-close>×</button></div>${status ? `<div class="fp-status">${status}</div>` : ""}${mode}${buttons ? `<div class="btns fp-btns">${buttons}</div>` : ""}${values}${setpoint}</div></div>`;
|
|
77
|
+
}
|
|
78
|
+
function toneOf(t) {
|
|
79
|
+
return t ?? "accent";
|
|
80
|
+
}
|
|
81
|
+
function widget(w, box, bind, id, face) {
|
|
82
|
+
const bodyH = box.h - (w.title ? 44 : 20);
|
|
83
|
+
switch (w.type) {
|
|
84
|
+
case "value": {
|
|
85
|
+
const size = Math.max(22, Math.min(64, bodyH * (w.trend ? 0.36 : 0.55), box.w / 6));
|
|
86
|
+
const spark = w.trend ? `<svg class="spark" viewBox="0 0 200 40" preserveAspectRatio="none" ${bind({ kind: "spark", v: w.value })}><path class="spark-fill"/><path class="spark-line"/></svg>` : "";
|
|
87
|
+
return `<div class="v-wrap"><div class="v-num" style="font-size:${r1(size)}px" ${bind({ kind: "text", v: w.value, decimals: w.decimals, bands: w.bands })}>–</div>${w.unit ? `<div class="v-unit">${esc(w.unit)}</div>` : ""}</div>${spark}`;
|
|
88
|
+
}
|
|
89
|
+
case "gauge": {
|
|
90
|
+
const s = Math.min(box.w - 24, bodyH * 1.25);
|
|
91
|
+
const R = 80;
|
|
92
|
+
const arc = describeArc(100, 100, R, -120, 120);
|
|
93
|
+
const len = r1((240 / 360) * 2 * Math.PI * R);
|
|
94
|
+
const ticks = Array.from({ length: 11 }, (_, i) => {
|
|
95
|
+
const a = ((-120 + i * 24) * Math.PI) / 180;
|
|
96
|
+
const r0 = i % 5 === 0 ? 62 : 66;
|
|
97
|
+
return `<line x1="${r1(100 + r0 * Math.sin(a))}" y1="${r1(100 - r0 * Math.cos(a))}" x2="${r1(100 + 70 * Math.sin(a))}" y2="${r1(100 - 70 * Math.cos(a))}"/>`;
|
|
98
|
+
}).join("");
|
|
99
|
+
return `<svg class="gauge" style="width:${r1(s)}px;height:${r1(s * 0.86)}px;--len:${len}" viewBox="0 0 200 172" ${bind({ kind: "level", v: w.value, min: w.min, max: w.max, bands: w.bands })}>
|
|
100
|
+
<path class="g-track" d="${arc}"/><path class="g-val" d="${arc}" style="stroke-dasharray:${len};"/><g class="g-ticks">${ticks}</g>
|
|
101
|
+
<text x="100" y="104" class="g-num" ${bind({ kind: "text", v: w.value, decimals: w.decimals, bands: w.bands })}>–</text>
|
|
102
|
+
<text x="100" y="128" class="g-unit">${esc(w.unit ?? "")}</text>
|
|
103
|
+
<text x="${r1(100 - R * Math.sin((120 * Math.PI) / 180))}" y="166" class="g-lim">${w.min}</text><text x="${r1(100 + R * Math.sin((120 * Math.PI) / 180))}" y="166" class="g-lim">${w.max}</text></svg>`;
|
|
104
|
+
}
|
|
105
|
+
case "bar": {
|
|
106
|
+
const lvl = bind({ kind: "level", v: w.value, min: w.min, max: w.max, bands: w.bands });
|
|
107
|
+
return `<div class="bar-wrap${w.vertical ? " vert" : ""}"><div class="bar" ${lvl}><div class="bar-fill"></div></div><div class="bar-read"><span class="bar-num" ${bind({ kind: "text", v: w.value, decimals: 1, bands: w.bands })}>–</span> <span class="bar-unit">${esc(w.unit ?? "")}</span><span class="bar-lim">${w.min} – ${w.max}</span></div></div>`;
|
|
108
|
+
}
|
|
109
|
+
case "status":
|
|
110
|
+
return `<ul class="status">${w.items.map((i) => `<li class="led tone-${toneOf(i.tone ?? "ok")}" ${bind({ kind: "on", v: i.on, invert: i.invert })}><span class="led-dot"></span><span>${esc(i.label)}</span></li>`).join("")}</ul>`;
|
|
111
|
+
case "buttons":
|
|
112
|
+
return `<div class="btns${w.items.length > 2 && box.w < 360 ? " col" : ""}">${w.items
|
|
113
|
+
.map((i) => `<button class="btn tone-${toneOf(i.tone ?? (/stop|reset|off/i.test(i.label) ? "alarm" : "accent"))}" data-act="${i.action}" data-var="${esc(i.variable)}" ${i.action === "tap" || i.action === "toggle" ? bind({ kind: "on", v: i.variable }) : ""}>${esc(i.label)}</button>`)
|
|
114
|
+
.join("")}</div>`;
|
|
115
|
+
case "switch":
|
|
116
|
+
return `<label class="sw" data-act="toggle" data-var="${esc(w.variable)}" ${bind({ kind: "on", v: w.variable })}><span class="sw-track"><span class="sw-knob"></span></span><span class="sw-lbl">${esc(w.label ?? "")}</span><span class="sw-state"><span class="s-on">ON</span><span class="s-off">OFF</span></span></label>`;
|
|
117
|
+
case "setpoint": {
|
|
118
|
+
const dec = w.step !== undefined && !Number.isInteger(w.step) ? String(w.step).split(".")[1].length : 0;
|
|
119
|
+
return `<div class="sp" data-var="${esc(w.variable)}" data-min="${w.min}" data-max="${w.max}" data-step="${w.step ?? 1}" ${bind({ kind: "setpoint", v: w.variable, decimals: dec })}>
|
|
120
|
+
<div class="sp-row"><button class="sp-btn" data-step="-1">−</button><div class="sp-val"><span class="sp-num" ${bind({ kind: "text", v: w.variable, decimals: dec })}>–</span><span class="sp-unit">${esc(w.unit ?? "")}</span></div><button class="sp-btn" data-step="1">+</button></div>
|
|
121
|
+
<input class="sp-range" type="range" min="${w.min}" max="${w.max}" step="${w.step ?? 1}"><div class="sp-lim"><span>${w.min}</span><span>${w.max}</span></div></div>`;
|
|
122
|
+
}
|
|
123
|
+
case "trend": {
|
|
124
|
+
const lines = w.series.map((s, i) => `<path class="tr-line" style="stroke:${SERIES_COLORS[i % SERIES_COLORS.length]}"/>`).join("");
|
|
125
|
+
const legend = w.series.map((s, i) => `<span><i style="background:${SERIES_COLORS[i % SERIES_COLORS.length]}"></i>${esc(s.label ?? s.value.split(".").pop())}</span>`).join("");
|
|
126
|
+
const grid = [0.25, 0.5, 0.75].map((f) => `<line x1="0" x2="600" y1="${200 * f}" y2="${200 * f}"/>`).join("");
|
|
127
|
+
return `<div class="tr-legend">${legend}</div><svg class="trend" viewBox="0 0 600 200" preserveAspectRatio="none" ${bind({ kind: "trend", series: w.series.map((s) => s.value), min: w.min, max: w.max, seconds: w.seconds })}><g class="tr-grid">${grid}</g>${lines}</svg><div class="tr-axis"><span>−${w.seconds} s</span><span class="tr-range"><span class="tr-min"></span> – <span class="tr-max"></span></span><span>now</span></div>`;
|
|
128
|
+
}
|
|
129
|
+
case "alarms":
|
|
130
|
+
return `<ul class="alarms">${w.items.map((i) => `<li class="al sev-${i.severity}" ${bind({ kind: "alarm", v: i.active })}><span class="al-badge">${i.severity === "info" ? "INFO" : i.severity === "warning" ? "WARN" : "ALARM"}</span><span class="al-text">${esc(i.text)}</span></li>`).join("")}<li class="al-none">No active alarms</li></ul>`;
|
|
131
|
+
case "text":
|
|
132
|
+
return `<div class="txt">${esc(w.text).replace(/\n/g, "<br>")}</div>`;
|
|
133
|
+
case "process": {
|
|
134
|
+
const vw = 100;
|
|
135
|
+
const vh = r1((100 * Math.max(60, bodyH)) / Math.max(60, box.w - 24));
|
|
136
|
+
const sy = vh / 100;
|
|
137
|
+
const items = routed(w.items, sy).sort((a, b) => (a.type === "pipe" ? -1 : 0) - (b.type === "pipe" ? -1 : 0));
|
|
138
|
+
return `<svg class="proc" viewBox="0 0 ${vw} ${vh}" preserveAspectRatio="xMidYMid meet">${items.map((p) => processSvg(p, sy, bind, id, face)).join("")}</svg>`;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
function describeArc(cx, cy, r, a0, a1) {
|
|
143
|
+
const p = (a) => [cx + r * Math.sin((a * Math.PI) / 180), cy - r * Math.cos((a * Math.PI) / 180)].map(r1);
|
|
144
|
+
const [x0, y0] = p(a0);
|
|
145
|
+
const [x1, y1] = p(a1);
|
|
146
|
+
return `M${x0} ${y0} A${r} ${r} 0 ${a1 - a0 > 180 ? 1 : 0} 1 ${x1} ${y1}`;
|
|
147
|
+
}
|
|
148
|
+
const DEFS = `<defs>
|
|
149
|
+
<linearGradient id="gShell" x1="0" x2="1"><stop offset="0" stop-color="var(--shell-a)"/><stop offset=".5" stop-color="var(--shell-b)"/><stop offset="1" stop-color="var(--shell-a)"/></linearGradient>
|
|
150
|
+
<linearGradient id="gLiquid" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stop-color="var(--liq-a)"/><stop offset="1" stop-color="var(--liq-b)"/></linearGradient>
|
|
151
|
+
<radialGradient id="gHub" cx=".35" cy=".35" r=".8"><stop offset="0" stop-color="var(--hub-a)"/><stop offset="1" stop-color="var(--hub-b)"/></radialGradient>
|
|
152
|
+
<filter id="fGlow" x="-50%" y="-50%" width="200%" height="200%"><feGaussianBlur stdDeviation="1.2" result="b"/><feMerge><feMergeNode in="b"/><feMergeNode in="SourceGraphic"/></feMerge></filter>
|
|
153
|
+
</defs>`;
|
|
154
|
+
function processSvg(p, sy, bind, id, face) {
|
|
155
|
+
const Y = (y) => r1(y * sy);
|
|
156
|
+
const label = (x, y, t) => (t ? `<text class="p-label" x="${r1(x)}" y="${Y(y)}">${esc(t)}</text>` : "");
|
|
157
|
+
switch (p.type) {
|
|
158
|
+
case "pipe": {
|
|
159
|
+
const d = (p.points ?? []).map(([x, y], i) => `${i ? "L" : "M"}${r1(x)} ${Y(y)}`).join(" ");
|
|
160
|
+
return `<g class="pipe" ${p.flow ? bind({ kind: "on", v: p.flow }) : ""}><path class="pipe-outer" d="${d}"/><path class="pipe-inner" d="${d}"/><path class="pipe-flow" d="${d}"/></g>`;
|
|
161
|
+
}
|
|
162
|
+
case "tank": {
|
|
163
|
+
const x = r1(p.x), y = Y(p.y), w = r1(p.w), h = Y(p.h);
|
|
164
|
+
const clip = id("tk");
|
|
165
|
+
const ticks = [0.25, 0.5, 0.75].map((f) => `<line x1="${r1(x + w - 2.2)}" x2="${r1(x + w - 0.8)}" y1="${r1(y + h * (1 - f))}" y2="${r1(y + h * (1 - f))}"/>`).join("");
|
|
166
|
+
return `<g class="tank" ${bind({ kind: "level", v: p.level, min: 0, max: p.max, bands: p.bands })}>
|
|
167
|
+
<clipPath id="${clip}"><rect x="${x}" y="${y}" width="${w}" height="${h}" rx="${r1(Math.min(w, h) * 0.12)}"/></clipPath>
|
|
168
|
+
<rect class="tank-shell" x="${x}" y="${y}" width="${w}" height="${h}" rx="${r1(Math.min(w, h) * 0.12)}"/>
|
|
169
|
+
<g clip-path="url(#${clip})"><g class="tank-liq" style="transform-origin:${x}px ${r1(y + h)}px"><rect x="${x}" y="${y}" width="${w}" height="${h}" fill="url(#gLiquid)"/><path class="tank-wave" d="M${x} ${r1(y + 1)} q ${r1(w / 8)} -1.2 ${r1(w / 4)} 0 t ${r1(w / 4)} 0 t ${r1(w / 4)} 0 t ${r1(w / 4)} 0 t ${r1(w / 4)} 0 V ${r1(y + 3)} H ${x} Z"/></g></g>
|
|
170
|
+
<rect class="tank-gloss" x="${r1(x + w * 0.1)}" y="${r1(y + h * 0.05)}" width="${r1(w * 0.12)}" height="${r1(h * 0.9)}" rx="${r1(w * 0.06)}"/>
|
|
171
|
+
<g class="tank-ticks">${ticks}</g>
|
|
172
|
+
<text class="tank-num" x="${r1(x + w / 2)}" y="${r1(y + h / 2 + 1.5)}" ${bind({ kind: "text", v: p.level, decimals: 0, unit: p.unit })}>–</text>
|
|
173
|
+
${label(x + w / 2, p.y + p.h + 2.8 / sy, p.label)}</g>`;
|
|
174
|
+
}
|
|
175
|
+
case "pump": {
|
|
176
|
+
const s = p.size, cx = r1(p.x), cy = Y(p.y), r = r1(s / 2);
|
|
177
|
+
const blades = [0, 60, 120, 180, 240, 300].map((a) => `<path d="M0 0 Q ${r1(r * 0.3)} ${r1(-r * 0.25)} ${r1(r * 0.12)} ${r1(-r * 0.62)}" transform="rotate(${a})"/>`).join("");
|
|
178
|
+
return `<g ${p.fault ? bind({ kind: "fault", v: p.fault }) : ""} ${p.faceplate ? `class="clickable" ${face(p.label ?? "Pump", p.faceplate, { running: p.running, fault: p.fault })}` : ""}><g class="pump" ${bind({ kind: "on", v: p.running })}>
|
|
179
|
+
<circle class="pump-ring" cx="${cx}" cy="${cy}" r="${r}"/><circle class="pump-body" cx="${cx}" cy="${cy}" r="${r1(r * 0.86)}" fill="url(#gHub)"/>
|
|
180
|
+
<g transform="translate(${cx} ${cy})"><g class="pump-imp">${blades}<circle r="${r1(r * 0.14)}" class="pump-hub"/></g></g>
|
|
181
|
+
${label(p.x, p.y + (s / 2 + 2.6) / sy, p.label)}</g></g>`;
|
|
182
|
+
}
|
|
183
|
+
case "fan": {
|
|
184
|
+
const s = p.size, cx = r1(p.x), cy = Y(p.y), r = r1(s / 2);
|
|
185
|
+
const blades = [0, 120, 240].map((a) => `<path d="M0 0 C ${r1(r * 0.5)} ${r1(-r * 0.2)} ${r1(r * 0.55)} ${r1(-r * 0.8)} 0 ${r1(-r * 0.86)} C ${r1(-r * 0.2)} ${r1(-r * 0.6)} ${r1(-r * 0.1)} ${r1(-r * 0.2)} 0 0Z" transform="rotate(${a})"/>`).join("");
|
|
186
|
+
return `<g class="pump fan${p.faceplate ? " clickable" : ""}" ${bind({ kind: "on", v: p.running })} ${p.faceplate ? face(p.label ?? "Fan", p.faceplate, { running: p.running }) : ""}><circle class="pump-ring" cx="${cx}" cy="${cy}" r="${r}"/><circle class="pump-body" cx="${cx}" cy="${cy}" r="${r1(r * 0.9)}" fill="url(#gHub)"/><g transform="translate(${cx} ${cy})"><g class="pump-imp">${blades}<circle r="${r1(r * 0.12)}" class="pump-hub"/></g></g>${label(p.x, p.y + (s / 2 + 2.6) / sy, p.label)}</g>`;
|
|
187
|
+
}
|
|
188
|
+
case "valve": {
|
|
189
|
+
const s = p.size, cx = r1(p.x), cy = Y(p.y), h = r1(s / 2);
|
|
190
|
+
const body = `<path class="valve-body" d="M${r1(-h)} ${r1(-h * 0.7)} L${h} ${r1(h * 0.7)} L${h} ${r1(-h * 0.7)} L${r1(-h)} ${r1(h * 0.7)} Z"/><line class="valve-stem" x1="0" y1="0" x2="0" y2="${r1(-h * 1.1)}"/><rect class="valve-act" x="${r1(-h * 0.5)}" y="${r1(-h * 1.5)}" width="${h}" height="${r1(h * 0.45)}" rx="${r1(h * 0.1)}"/>`;
|
|
191
|
+
return `<g class="valve${p.faceplate ? " clickable" : ""}" ${bind({ kind: "on", v: p.open })} ${p.faceplate ? face(p.label ?? "Valve", p.faceplate, { open: p.open }) : ""}><g transform="translate(${cx} ${cy})${p.vertical ? " rotate(90)" : ""}">${body}</g>${p.label ? (p.vertical ? `<text class="p-label left" x="${r1(p.x + s * 0.75)}" y="${r1(cy + 0.6)}">${esc(p.label)}</text>` : label(p.x, p.y + (s / 2 + 2.6) / sy, p.label)) : ""}</g>`;
|
|
192
|
+
}
|
|
193
|
+
case "sensor": {
|
|
194
|
+
const cx = r1(p.x), cy = Y(p.y);
|
|
195
|
+
return `<g class="sensor"><rect class="sen-box" x="${r1(cx - 6.5)}" y="${r1(cy - 2.1)}" width="13" height="4.2" rx="2.1"/><text class="sen-num" x="${cx}" y="${r1(cy + 0.75)}" ${bind({ kind: "text", v: p.value, decimals: p.decimals ?? 1, unit: p.unit })}>–</text>${p.label ? `<text class="sen-tag" x="${cx}" y="${r1(cy - 3)}">${esc(p.label)}</text>` : ""}</g>`;
|
|
196
|
+
}
|
|
197
|
+
case "lamp": {
|
|
198
|
+
const cx = r1(p.x), cy = Y(p.y);
|
|
199
|
+
return `<g class="plamp tone-${toneOf(p.tone ?? "ok")}" ${bind({ kind: "on", v: p.on })}><circle class="pl-halo" cx="${cx}" cy="${cy}" r="2.2"/><circle class="pl-dot" cx="${cx}" cy="${cy}" r="1.3"/>${p.label ? `<text class="p-label left" x="${r1(cx + 3)}" y="${r1(cy + 0.65)}">${esc(p.label)}</text>` : ""}</g>`;
|
|
200
|
+
}
|
|
201
|
+
case "junction":
|
|
202
|
+
return `<circle class="junction" cx="${r1(p.x)}" cy="${Y(p.y)}" r="1.1"/>`;
|
|
203
|
+
case "label":
|
|
204
|
+
return `<text class="p-text" x="${r1(p.x)}" y="${Y(p.y)}">${esc(p.text)}</text>`;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
export const HMI_CSS = String.raw `
|
|
208
|
+
.hmi{position:relative;overflow:hidden;font-family:"Segoe UI Variable Display","Segoe UI",Inter,system-ui,sans-serif;color:var(--fg);background:var(--bg);border-radius:18px;box-sizing:border-box;-webkit-font-smoothing:antialiased}
|
|
209
|
+
.hmi *{box-sizing:border-box}
|
|
210
|
+
.theme-dark{--bg:radial-gradient(1200px 600px at 15% -10%,#13284a 0%,transparent 60%),radial-gradient(900px 500px at 110% 110%,#1c1640 0%,transparent 55%),#070d1a;--fg:#e6edf7;--muted:#8193ad;--tile:linear-gradient(160deg,rgba(30,41,64,.72),rgba(14,21,37,.78));--tile-bd:rgba(148,163,184,.13);--tile-sh:0 10px 30px rgba(0,0,0,.35),inset 0 1px 0 rgba(255,255,255,.05);--track:rgba(148,163,184,.16);--accent:#38bdf8;--ok:#22c55e;--warn:#f59e0b;--alarm:#ef4444;--neutral:#64748b;--shell-a:#1e293b;--shell-b:#334155;--liq-a:#38bdf8;--liq-b:#0369a1;--hub-a:#475569;--hub-b:#0f172a;--pipe:#334155;--pipe-in:#1e293b;--btn:rgba(148,163,184,.1)}
|
|
211
|
+
.theme-light{--bg:radial-gradient(1000px 500px at 10% -10%,#dbeafe 0%,transparent 60%),#eef2f7;--fg:#0f172a;--muted:#64748b;--tile:linear-gradient(160deg,#ffffff,#f8fafc);--tile-bd:#e2e8f0;--tile-sh:0 6px 20px rgba(15,23,42,.06);--track:#e2e8f0;--accent:#0284c7;--ok:#16a34a;--warn:#d97706;--alarm:#dc2626;--neutral:#94a3b8;--shell-a:#cbd5e1;--shell-b:#f1f5f9;--liq-a:#38bdf8;--liq-b:#0284c7;--hub-a:#e2e8f0;--hub-b:#94a3b8;--pipe:#94a3b8;--pipe-in:#cbd5e1;--btn:#f1f5f9}
|
|
212
|
+
.glow{position:absolute;inset:0;pointer-events:none;background:linear-gradient(180deg,rgba(56,189,248,.06),transparent 30%)}
|
|
213
|
+
.h-bar{position:absolute;left:20px;right:20px;top:0;height:var(--hdr,76px);display:flex;align-items:center;justify-content:space-between}
|
|
214
|
+
.h-title{font-size:24px;font-weight:650;letter-spacing:-.01em}
|
|
215
|
+
.h-sub{font-size:13px;color:var(--muted);margin-top:2px}
|
|
216
|
+
.h-right{display:flex;gap:12px;align-items:center}
|
|
217
|
+
.h-sim{display:flex;align-items:center;gap:8px;padding:7px 13px;border-radius:999px;border:1px solid var(--tile-bd);background:var(--tile);font-size:12px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--muted)}
|
|
218
|
+
.h-sim .dot{width:8px;height:8px;border-radius:50%;background:var(--neutral)}
|
|
219
|
+
.h-sim.run{color:var(--ok)}.h-sim.run .dot{background:var(--ok);box-shadow:0 0 0 4px color-mix(in srgb,var(--ok) 25%,transparent);animation:pulse 1.6s infinite}
|
|
220
|
+
.h-sim.stop{color:var(--warn)}.h-sim.stop .dot{background:var(--warn)}
|
|
221
|
+
.h-nav{position:absolute;left:50%;transform:translateX(-50%);display:flex;gap:4px;padding:4px;border-radius:12px;background:var(--tile);border:1px solid var(--tile-bd)}
|
|
222
|
+
.h-page{border:0;border-radius:9px;padding:8px 16px;background:transparent;color:var(--muted);font:600 13px/1 inherit;cursor:pointer;letter-spacing:.02em}
|
|
223
|
+
.h-page:hover{color:var(--fg)}.h-page.cur{background:var(--accent);color:#04121f}
|
|
224
|
+
.h-alarm{display:flex;align-items:center;gap:7px;padding:7px 12px;border-radius:999px;border:1px solid var(--tile-bd);background:var(--tile);font-size:12px;font-weight:700;color:var(--muted)}
|
|
225
|
+
.h-alarm .dot{width:8px;height:8px;border-radius:50%;background:var(--ok)}.h-alarm.on{color:#fff;background:color-mix(in srgb,var(--alarm) 75%,transparent);border-color:var(--alarm);animation:blink 1.2s infinite}.h-alarm.on .dot{background:#fff}
|
|
226
|
+
.clickable{cursor:pointer}.clickable:hover .pump-ring,.clickable:hover .valve-body{filter:drop-shadow(0 0 1.5px var(--accent))}
|
|
227
|
+
.fp{position:absolute;inset:0;background:rgba(2,6,23,.55);backdrop-filter:blur(3px);display:flex;align-items:center;justify-content:center;z-index:20}.fp[hidden]{display:none}
|
|
228
|
+
.fp-card{width:380px;border-radius:18px;background:var(--tile);background-color:#111a2e;border:1px solid var(--tile-bd);box-shadow:0 30px 80px rgba(0,0,0,.55);padding:18px 20px;display:flex;flex-direction:column;gap:14px}
|
|
229
|
+
.theme-light .fp-card{background-color:#fff}
|
|
230
|
+
.fp-head{display:flex;align-items:center;justify-content:space-between}.fp-title{font-size:18px;font-weight:650}
|
|
231
|
+
.fp-x{border:0;background:var(--btn);color:var(--fg);width:32px;height:32px;border-radius:10px;font-size:18px;cursor:pointer}
|
|
232
|
+
.fp-status{display:flex;gap:16px}.fp-btns{height:auto}.fp-btns .btn{min-height:46px}
|
|
233
|
+
.fp-row{display:flex;justify-content:space-between;font-size:14px;color:var(--muted)}.fp-row b{color:var(--fg);font-variant-numeric:tabular-nums}
|
|
234
|
+
.h-clock{font-variant-numeric:tabular-nums;font-size:15px;color:var(--muted);min-width:76px;text-align:right}
|
|
235
|
+
.tile{position:absolute;border-radius:16px;background:var(--tile);border:1px solid var(--tile-bd);box-shadow:var(--tile-sh);backdrop-filter:blur(8px);display:flex;flex-direction:column;padding:14px 16px 12px}
|
|
236
|
+
.tile.compact{padding:8px 16px}.tile.compact .t-title{height:15px;font-size:10.5px}
|
|
237
|
+
.t-title{font-size:11.5px;font-weight:650;letter-spacing:.1em;text-transform:uppercase;color:var(--muted);height:20px;flex:none}
|
|
238
|
+
.t-body{flex:1;min-height:0;display:flex;flex-direction:column;justify-content:center;position:relative}
|
|
239
|
+
.tone-accent{--c:var(--accent)}.tone-ok{--c:var(--ok)}.tone-warn{--c:var(--warn)}.tone-alarm{--c:var(--alarm)}.tone-neutral{--c:var(--neutral)}
|
|
240
|
+
[data-tone=accent]{--c:var(--accent)}[data-tone=ok]{--c:var(--ok)}[data-tone=warn]{--c:var(--warn)}[data-tone=alarm]{--c:var(--alarm)}[data-tone=neutral]{--c:var(--neutral)}
|
|
241
|
+
.v-wrap{display:flex;align-items:baseline;gap:8px}
|
|
242
|
+
.v-num{font-weight:650;letter-spacing:-.02em;font-variant-numeric:tabular-nums;line-height:1;color:var(--c,var(--fg));transition:color .3s}
|
|
243
|
+
.v-unit{font-size:15px;color:var(--muted);font-weight:500}
|
|
244
|
+
.spark{width:100%;height:34%;margin-top:8px}.spark-line{fill:none;stroke:var(--accent);stroke-width:2;vector-effect:non-scaling-stroke}.spark-fill{fill:color-mix(in srgb,var(--accent) 16%,transparent)}
|
|
245
|
+
.gauge{display:block;margin:0 auto;--p:0}.g-track,.g-val{fill:none;stroke-width:14;stroke-linecap:round}.g-track{stroke:var(--track)}
|
|
246
|
+
.g-val{stroke:var(--c,var(--accent));stroke-dashoffset:calc(var(--len) * (1 - var(--p)));transition:stroke-dashoffset .5s cubic-bezier(.2,.8,.2,1),stroke .3s;filter:drop-shadow(0 0 6px color-mix(in srgb,var(--c,var(--accent)) 55%,transparent))}
|
|
247
|
+
.g-ticks line{stroke:var(--muted);stroke-width:1.5;opacity:.5}
|
|
248
|
+
.g-num{font-size:34px;font-weight:650;text-anchor:middle;fill:var(--fg);font-variant-numeric:tabular-nums}.g-unit{font-size:13px;text-anchor:middle;fill:var(--muted)}.g-lim{font-size:11px;fill:var(--muted);text-anchor:middle}
|
|
249
|
+
.bar-wrap{display:flex;flex-direction:column;gap:10px;--p:0}.bar{height:16px;border-radius:999px;background:var(--track);overflow:hidden;--p:0}
|
|
250
|
+
.bar-fill{height:100%;width:calc(var(--p) * 100%);border-radius:999px;background:linear-gradient(90deg,color-mix(in srgb,var(--c,var(--accent)) 70%,transparent),var(--c,var(--accent)));box-shadow:0 0 14px color-mix(in srgb,var(--c,var(--accent)) 45%,transparent);transition:width .5s cubic-bezier(.2,.8,.2,1)}
|
|
251
|
+
.bar-wrap.vert{flex-direction:row;height:100%;align-items:stretch}.bar-wrap.vert .bar{width:22px;height:auto;display:flex;align-items:flex-end}.bar-wrap.vert .bar-fill{width:100%;height:calc(var(--p) * 100%);transition:height .5s}
|
|
252
|
+
.bar-read{display:flex;align-items:baseline;gap:4px}.bar-num{font-size:26px;font-weight:650;font-variant-numeric:tabular-nums;color:var(--c,var(--fg))}.bar-unit{color:var(--muted);font-size:13px}.bar-lim{margin-left:auto;color:var(--muted);font-size:11px}
|
|
253
|
+
.status{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:9px}
|
|
254
|
+
.led{display:flex;align-items:center;gap:11px;font-size:14px;color:var(--muted);transition:color .3s}
|
|
255
|
+
.led-dot{width:12px;height:12px;border-radius:50%;background:var(--track);box-shadow:inset 0 1px 2px rgba(0,0,0,.4);transition:all .3s;flex:none}
|
|
256
|
+
.led.on{color:var(--fg)}.led.on .led-dot{background:radial-gradient(circle at 35% 35%,#fff 0,var(--c) 45%);box-shadow:0 0 0 3px color-mix(in srgb,var(--c) 22%,transparent),0 0 14px var(--c)}
|
|
257
|
+
.btns{display:flex;gap:10px;height:100%;align-items:center}.btns.col{flex-direction:column;align-items:stretch}
|
|
258
|
+
.btn{flex:1;min-height:52px;border-radius:12px;border:1px solid color-mix(in srgb,var(--c) 40%,var(--tile-bd));background:linear-gradient(180deg,color-mix(in srgb,var(--c) 22%,var(--btn)),color-mix(in srgb,var(--c) 10%,var(--btn)));color:var(--fg);font:650 16px/1 inherit;letter-spacing:.03em;cursor:pointer;transition:all .15s;box-shadow:0 4px 14px color-mix(in srgb,var(--c) 18%,transparent),inset 0 1px 0 rgba(255,255,255,.08)}
|
|
259
|
+
.btn:hover{filter:brightness(1.15)}.btn:active,.btn.on{transform:translateY(1px);background:color-mix(in srgb,var(--c) 45%,var(--btn));box-shadow:0 0 18px color-mix(in srgb,var(--c) 45%,transparent)}
|
|
260
|
+
.sw{display:flex;align-items:center;gap:14px;cursor:pointer;user-select:none}
|
|
261
|
+
.sw-track{width:58px;height:32px;border-radius:999px;background:var(--track);position:relative;transition:background .25s;flex:none}
|
|
262
|
+
.sw-knob{position:absolute;top:3px;left:3px;width:26px;height:26px;border-radius:50%;background:#fff;box-shadow:0 2px 6px rgba(0,0,0,.35);transition:transform .25s cubic-bezier(.2,.8,.2,1)}
|
|
263
|
+
.sw.on .sw-track{background:var(--ok);box-shadow:0 0 16px color-mix(in srgb,var(--ok) 45%,transparent)}.sw.on .sw-knob{transform:translateX(26px)}
|
|
264
|
+
.sw-lbl{font-size:15px;flex:1}.sw-state{font-size:12px;font-weight:700;letter-spacing:.08em;color:var(--muted)}.sw .s-on{display:none}.sw.on .s-on{display:inline;color:var(--ok)}.sw.on .s-off{display:none}
|
|
265
|
+
.sp{display:flex;flex-direction:column;gap:10px}.sp-row{display:flex;align-items:center;gap:10px}
|
|
266
|
+
.sp-btn{width:40px;height:40px;border-radius:12px;border:1px solid var(--tile-bd);background:var(--btn);color:var(--fg);font-size:22px;cursor:pointer}.sp-btn:hover{border-color:var(--accent)}
|
|
267
|
+
.sp-val{flex:1;text-align:center}.sp-num{font-size:30px;font-weight:650;font-variant-numeric:tabular-nums}.sp-unit{margin-left:6px;color:var(--muted);font-size:13px}
|
|
268
|
+
.sp-range{width:100%;accent-color:var(--accent)}.sp-lim{display:flex;justify-content:space-between;color:var(--muted);font-size:11px}
|
|
269
|
+
.tr-legend{display:flex;gap:14px;font-size:12px;color:var(--muted);margin-bottom:6px;flex-wrap:wrap}.tr-legend i{display:inline-block;width:10px;height:3px;border-radius:2px;margin-right:6px;vertical-align:middle}
|
|
270
|
+
.trend{flex:1;width:100%;min-height:0}.tr-grid line{stroke:var(--track);stroke-width:1;vector-effect:non-scaling-stroke}
|
|
271
|
+
.tr-line{fill:none;stroke-width:2.2;vector-effect:non-scaling-stroke;stroke-linejoin:round;filter:drop-shadow(0 0 4px rgba(56,189,248,.35))}
|
|
272
|
+
.tr-axis{display:flex;justify-content:space-between;font-size:10.5px;color:var(--muted);margin-top:4px}
|
|
273
|
+
.t-alarms .t-body,.t-status .t-body{justify-content:flex-start}
|
|
274
|
+
.alarms{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:7px;overflow:hidden}
|
|
275
|
+
.al{display:none;align-items:center;gap:9px;padding:8px 10px;border-radius:10px;font-size:12.5px;line-height:1.25;background:color-mix(in srgb,var(--c) 12%,transparent);border:1px solid color-mix(in srgb,var(--c) 35%,transparent)}
|
|
276
|
+
.al.active{display:flex}.sev-alarm{--c:var(--alarm)}.sev-warning{--c:var(--warn)}.sev-info{--c:var(--accent)}
|
|
277
|
+
.sev-alarm.active{animation:blink 1.2s infinite}
|
|
278
|
+
.al-badge{font-size:10px;font-weight:800;letter-spacing:.08em;padding:3px 7px;border-radius:6px;background:var(--c);color:#fff}
|
|
279
|
+
.al-none{display:flex;align-items:center;gap:9px;color:var(--ok);font-size:14px}.al-none::before{content:"";width:10px;height:10px;border-radius:50%;background:var(--ok);box-shadow:0 0 10px var(--ok)}
|
|
280
|
+
.alarms.has .al-none{display:none}
|
|
281
|
+
.txt{font-size:14px;line-height:1.5;color:var(--muted)}
|
|
282
|
+
.proc{width:100%;height:100%;overflow:visible}
|
|
283
|
+
.p-label{font-size:1.75px;fill:var(--muted);text-anchor:middle;font-weight:600;letter-spacing:.05em}.p-label.left{text-anchor:start}.p-text{font-size:2px;fill:var(--fg);font-weight:600}
|
|
284
|
+
.junction{fill:var(--pipe)}
|
|
285
|
+
.pipe-outer{fill:none;stroke:var(--pipe);stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}.pipe-inner{fill:none;stroke:var(--pipe-in);stroke-width:1;stroke-linecap:round;stroke-linejoin:round}
|
|
286
|
+
.pipe-flow{fill:none;stroke:var(--accent);stroke-width:.55;stroke-dasharray:1.1 1.9;stroke-linecap:round;opacity:0;transition:opacity .4s}.pipe.on .pipe-flow{opacity:1;animation:flow .8s linear infinite;filter:drop-shadow(0 0 1px var(--accent))}
|
|
287
|
+
.tank{--p:0}.tank-shell{fill:url(#gShell);stroke:var(--tile-bd);stroke-width:.4}.tank-liq{transform:scaleY(var(--p));transition:transform .8s cubic-bezier(.2,.8,.2,1)}
|
|
288
|
+
.tank-liq rect{fill:url(#gLiquid);opacity:.92}.tank[data-tone=warn] .tank-liq rect{fill:var(--warn)}.tank[data-tone=alarm] .tank-liq rect{fill:var(--alarm)}
|
|
289
|
+
.tank-wave{fill:rgba(255,255,255,.22);animation:wave 3s ease-in-out infinite alternate}
|
|
290
|
+
.tank-gloss{fill:rgba(255,255,255,.08)}.tank-ticks line{stroke:var(--muted);stroke-width:.3}
|
|
291
|
+
.tank-num{font-size:3.4px;font-weight:700;fill:#fff;text-anchor:middle;paint-order:stroke;stroke:rgba(2,6,23,.45);stroke-width:.6px;font-variant-numeric:tabular-nums}
|
|
292
|
+
.pump-ring{fill:none;stroke:var(--neutral);stroke-width:.9;transition:all .3s}.pump-body{stroke:var(--tile-bd);stroke-width:.3}.pump-out{fill:var(--shell-b);stroke:var(--tile-bd);stroke-width:.3}
|
|
293
|
+
.pump-imp path{fill:none;stroke:var(--muted);stroke-width:.9;stroke-linecap:round}.fan .pump-imp path{fill:var(--muted);stroke:none;opacity:.85}.pump-hub{fill:var(--muted)}
|
|
294
|
+
.pump.on .pump-ring{stroke:var(--ok);filter:url(#fGlow)}.pump.on .pump-imp{animation:spin 1s linear infinite}.pump.on .pump-imp path{stroke:var(--ok)}.fan.on .pump-imp path{fill:var(--ok)}.pump.on .pump-hub{fill:var(--ok)}
|
|
295
|
+
.fault .pump-ring{stroke:var(--alarm);animation:blink .8s infinite}
|
|
296
|
+
.valve-body{fill:var(--neutral);stroke:var(--tile-bd);stroke-width:.3;transition:fill .3s}.valve-stem{stroke:var(--muted);stroke-width:.6}.valve-act{fill:var(--shell-b);stroke:var(--tile-bd);stroke-width:.3}
|
|
297
|
+
.valve.on .valve-body{fill:var(--ok);filter:url(#fGlow)}
|
|
298
|
+
.sen-box{fill:rgba(2,6,23,.6);stroke:color-mix(in srgb,var(--accent) 70%,transparent);stroke-width:.22}.theme-light .sen-box{fill:#fff}
|
|
299
|
+
.sen-num{font-size:2px;font-weight:700;fill:var(--fg);text-anchor:middle;font-variant-numeric:tabular-nums}.sen-tag{font-size:1.5px;fill:var(--muted);text-anchor:middle;font-weight:600;letter-spacing:.06em}
|
|
300
|
+
.plamp .pl-dot{fill:var(--track);transition:all .3s}.plamp .pl-halo{fill:none}.plamp.on .pl-dot{fill:var(--c)}.plamp.on .pl-halo{fill:color-mix(in srgb,var(--c) 30%,transparent);filter:url(#fGlow)}
|
|
301
|
+
@keyframes spin{to{transform:rotate(360deg)}}@keyframes flow{to{stroke-dashoffset:-3}}@keyframes pulse{50%{opacity:.55}}@keyframes blink{50%{opacity:.45}}
|
|
302
|
+
@keyframes wave{from{transform:translateX(-6%)}to{transform:translateX(0)}}
|
|
303
|
+
.small .h-title{font-size:18px}.small .h-sub{display:none}.small .h-page{padding:6px 10px;font-size:11px}.small .t-title{font-size:10px}.small .tile{padding:9px 11px}
|
|
304
|
+
.large .h-title{font-size:32px}.large .h-page{font-size:16px;padding:10px 20px}.large .t-title{font-size:14px}
|
|
305
|
+
@media (prefers-reduced-motion:reduce){.hmi *{animation:none!important;transition:none!important}}
|
|
306
|
+
`;
|
|
307
|
+
//# sourceMappingURL=render.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.js","sourceRoot":"","sources":["../../src/hmi/render.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ports and pipe routing for process diagrams. Symbols have named ports at
|
|
3
|
+
* their edges; a pipe from 'T-101.right' to 'P-101.in' is routed with right
|
|
4
|
+
* angles from port to port, so it always meets the symbols exactly, in the
|
|
5
|
+
* browser and in the CODESYS visualization alike.
|
|
6
|
+
*
|
|
7
|
+
* Coordinates: x across the diagram in 0..100, y down in 0..100 of its height.
|
|
8
|
+
* Symbol sizes are in x units, so a round symbol's height in y units is
|
|
9
|
+
* size / aspect, where aspect = height / width of the diagram on screen.
|
|
10
|
+
*/
|
|
11
|
+
import type { ProcessItem } from "./spec.js";
|
|
12
|
+
type Pt = [number, number];
|
|
13
|
+
type Dir = "l" | "r" | "u" | "d";
|
|
14
|
+
export interface Port {
|
|
15
|
+
at: Pt;
|
|
16
|
+
dir: Dir;
|
|
17
|
+
}
|
|
18
|
+
/** The ports of a symbol (keyed by name), for a diagram of the given aspect. */
|
|
19
|
+
export declare function portsOf(p: ProcessItem, aspect: number): Record<string, Port>;
|
|
20
|
+
/** Port names per symbol type, for messages and the tool description. */
|
|
21
|
+
export declare const PORT_NAMES: Record<string, string[]>;
|
|
22
|
+
/** Problems with pipe ends: unknown symbols or ports. */
|
|
23
|
+
export declare function routeProblems(items: ProcessItem[]): string[];
|
|
24
|
+
/** The points of a pipe: right angles from port to port (or along raw points). */
|
|
25
|
+
export declare function routePipe(p: Extract<ProcessItem, {
|
|
26
|
+
type: "pipe";
|
|
27
|
+
}>, items: ProcessItem[], aspect: number): Pt[];
|
|
28
|
+
/** The diagram with every pipe's points resolved. */
|
|
29
|
+
export declare function routed(items: ProcessItem[], aspect: number): ProcessItem[];
|
|
30
|
+
/** Symbols that overlap each other or leave the diagram, as warnings (the screen still saves). */
|
|
31
|
+
export declare function overlapWarnings(items: ProcessItem[], aspect: number): string[];
|
|
32
|
+
export {};
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
const keyOf = (p) => ("id" in p && p.id) || ("label" in p && p.label) || undefined;
|
|
2
|
+
/** The ports of a symbol (keyed by name), for a diagram of the given aspect. */
|
|
3
|
+
export function portsOf(p, aspect) {
|
|
4
|
+
switch (p.type) {
|
|
5
|
+
case "tank": {
|
|
6
|
+
const { x, y, w, h } = p;
|
|
7
|
+
const cx = x + w / 2;
|
|
8
|
+
return {
|
|
9
|
+
top: { at: [cx, y], dir: "u" },
|
|
10
|
+
bottom: { at: [cx, y + h], dir: "d" },
|
|
11
|
+
left: { at: [x, y + h * 0.85], dir: "l" },
|
|
12
|
+
right: { at: [x + w, y + h * 0.85], dir: "r" },
|
|
13
|
+
"left-high": { at: [x, y + h * 0.15], dir: "l" },
|
|
14
|
+
"right-high": { at: [x + w, y + h * 0.15], dir: "r" },
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
case "pump":
|
|
18
|
+
case "fan": {
|
|
19
|
+
const r = p.size / 2;
|
|
20
|
+
const ry = r / aspect;
|
|
21
|
+
return {
|
|
22
|
+
in: { at: [p.x - r, p.y], dir: "l" },
|
|
23
|
+
out: { at: [p.x + r, p.y], dir: "r" },
|
|
24
|
+
top: { at: [p.x, p.y - ry], dir: "u" },
|
|
25
|
+
bottom: { at: [p.x, p.y + ry], dir: "d" },
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
case "valve": {
|
|
29
|
+
const r = p.size / 2;
|
|
30
|
+
return p.vertical
|
|
31
|
+
? { in: { at: [p.x, p.y + r / aspect], dir: "d" }, out: { at: [p.x, p.y - r / aspect], dir: "u" } }
|
|
32
|
+
: { in: { at: [p.x - r, p.y], dir: "l" }, out: { at: [p.x + r, p.y], dir: "r" } };
|
|
33
|
+
}
|
|
34
|
+
case "junction":
|
|
35
|
+
return { c: { at: [p.x, p.y], dir: "r" } };
|
|
36
|
+
default:
|
|
37
|
+
return {};
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/** Port names per symbol type, for messages and the tool description. */
|
|
41
|
+
export const PORT_NAMES = {
|
|
42
|
+
tank: ["top", "bottom", "left", "right", "left-high", "right-high"],
|
|
43
|
+
pump: ["in", "out", "top", "bottom"],
|
|
44
|
+
fan: ["in", "out", "top", "bottom"],
|
|
45
|
+
valve: ["in", "out"],
|
|
46
|
+
junction: ["c"],
|
|
47
|
+
};
|
|
48
|
+
/** Problems with pipe ends: unknown symbols or ports. */
|
|
49
|
+
export function routeProblems(items) {
|
|
50
|
+
const syms = new Map(items.flatMap((p) => (keyOf(p) && p.type in PORT_NAMES ? [[keyOf(p).toLowerCase(), p]] : [])));
|
|
51
|
+
const out = [];
|
|
52
|
+
items.forEach((p, i) => {
|
|
53
|
+
if (p.type !== "pipe")
|
|
54
|
+
return;
|
|
55
|
+
for (const e of [p.from, p.to]) {
|
|
56
|
+
if (typeof e !== "string")
|
|
57
|
+
continue;
|
|
58
|
+
const [name, port] = e.split(".");
|
|
59
|
+
const s = syms.get(name.toLowerCase());
|
|
60
|
+
if (!s)
|
|
61
|
+
out.push(`pipe ${i + 1}: no symbol named '${name}' (symbols: ${[...syms.keys()].join(", ") || "none"}).`);
|
|
62
|
+
else if (!PORT_NAMES[s.type].includes(port) || (s.type === "valve" && !["in", "out"].includes(port)))
|
|
63
|
+
out.push(`pipe ${i + 1}: ${s.type} '${name}' has no port '${port}' (ports: ${PORT_NAMES[s.type].join(", ")}).`);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
return out;
|
|
67
|
+
}
|
|
68
|
+
const STEP = { l: [-1, 0], r: [1, 0], u: [0, -1], d: [0, 1] };
|
|
69
|
+
const horiz = (d) => d === "l" || d === "r";
|
|
70
|
+
/** The points of a pipe: right angles from port to port (or along raw points). */
|
|
71
|
+
export function routePipe(p, items, aspect) {
|
|
72
|
+
if (!p.from || !p.to)
|
|
73
|
+
return p.points ?? [];
|
|
74
|
+
const syms = new Map(items.flatMap((s) => (keyOf(s) && s.type in PORT_NAMES ? [[keyOf(s).toLowerCase(), s]] : [])));
|
|
75
|
+
const resolve = (e, other) => {
|
|
76
|
+
if (typeof e !== "string") {
|
|
77
|
+
// A free end at the diagram's edge leaves through that edge.
|
|
78
|
+
if (e[0] <= 5)
|
|
79
|
+
return { at: e, dir: "l" };
|
|
80
|
+
if (e[0] >= 95)
|
|
81
|
+
return { at: e, dir: "r" };
|
|
82
|
+
if (e[1] <= 5)
|
|
83
|
+
return { at: e, dir: "u" };
|
|
84
|
+
if (e[1] >= 95)
|
|
85
|
+
return { at: e, dir: "d" };
|
|
86
|
+
// Otherwise it leaves towards the other end along the longer axis.
|
|
87
|
+
const o = other ?? [50, 50];
|
|
88
|
+
const dx = o[0] - e[0], dy = (o[1] - e[1]) / aspect;
|
|
89
|
+
return { at: e, dir: Math.abs(dx) >= Math.abs(dy) ? (dx >= 0 ? "r" : "l") : dy >= 0 ? "d" : "u" };
|
|
90
|
+
}
|
|
91
|
+
const [name, port] = e.split(".");
|
|
92
|
+
const s = syms.get(name.toLowerCase());
|
|
93
|
+
const ports = s ? portsOf(s, aspect) : {};
|
|
94
|
+
return ports[port] ?? { at: [50, 50], dir: "r" };
|
|
95
|
+
};
|
|
96
|
+
const a0 = typeof p.from === "string" ? resolve(p.from) : undefined;
|
|
97
|
+
const b0 = typeof p.to === "string" ? resolve(p.to) : undefined;
|
|
98
|
+
const a = a0 ?? resolve(p.from, b0?.at ?? (Array.isArray(p.to) ? p.to : undefined));
|
|
99
|
+
const b = b0 ?? resolve(p.to, a.at);
|
|
100
|
+
// A junction takes the side facing the other end.
|
|
101
|
+
const face = (port, toward) => {
|
|
102
|
+
if (!(typeof p.from === "string" && port === a && p.from.endsWith(".c")) && !(typeof p.to === "string" && port === b && p.to.endsWith(".c")))
|
|
103
|
+
return port;
|
|
104
|
+
const dx = toward[0] - port.at[0], dy = (toward[1] - port.at[1]) / aspect;
|
|
105
|
+
return { at: port.at, dir: Math.abs(dx) >= Math.abs(dy) ? (dx >= 0 ? "r" : "l") : dy >= 0 ? "d" : "u" };
|
|
106
|
+
};
|
|
107
|
+
const A = face(a, b.at);
|
|
108
|
+
const B = face(b, a.at);
|
|
109
|
+
const pts = [A.at];
|
|
110
|
+
const targets = [...(p.via ?? []), B.at];
|
|
111
|
+
let cur = A.at;
|
|
112
|
+
let dir = A.dir;
|
|
113
|
+
targets.forEach((t, k) => {
|
|
114
|
+
const last = k === targets.length - 1;
|
|
115
|
+
const endDir = last ? B.dir : undefined;
|
|
116
|
+
for (const q of orthogonal(cur, dir, t, endDir))
|
|
117
|
+
pts.push(q);
|
|
118
|
+
const prev = pts[pts.length - 2] ?? cur;
|
|
119
|
+
dir = prev[0] === t[0] ? (t[1] >= prev[1] ? "d" : "u") : t[0] >= prev[0] ? "r" : "l";
|
|
120
|
+
cur = t;
|
|
121
|
+
});
|
|
122
|
+
return dedupe(pts);
|
|
123
|
+
}
|
|
124
|
+
/** Right-angle path from `a` (leaving in `dir`) to `b` (entered against `endDir`), without `a` itself. */
|
|
125
|
+
function orthogonal(a, dir, b, endDir) {
|
|
126
|
+
const eq = (x, y) => Math.abs(x - y) < 1e-6;
|
|
127
|
+
if (eq(a[0], b[0]) || eq(a[1], b[1]))
|
|
128
|
+
return [b];
|
|
129
|
+
const inH = endDir ? horiz(endDir) : !horiz(dir);
|
|
130
|
+
if (horiz(dir) && inH) {
|
|
131
|
+
const mx = (a[0] + b[0]) / 2;
|
|
132
|
+
return [[mx, a[1]], [mx, b[1]], b];
|
|
133
|
+
}
|
|
134
|
+
if (!horiz(dir) && !inH) {
|
|
135
|
+
const my = (a[1] + b[1]) / 2;
|
|
136
|
+
return [[a[0], my], [b[0], my], b];
|
|
137
|
+
}
|
|
138
|
+
return horiz(dir) ? [[b[0], a[1]], b] : [[a[0], b[1]], b];
|
|
139
|
+
}
|
|
140
|
+
function dedupe(pts) {
|
|
141
|
+
const out = [];
|
|
142
|
+
for (const p of pts) {
|
|
143
|
+
const q = out[out.length - 1];
|
|
144
|
+
if (q && Math.abs(q[0] - p[0]) < 1e-6 && Math.abs(q[1] - p[1]) < 1e-6)
|
|
145
|
+
continue;
|
|
146
|
+
// drop a middle point on a straight line
|
|
147
|
+
const r = out[out.length - 2];
|
|
148
|
+
if (q && r && ((Math.abs(r[0] - q[0]) < 1e-6 && Math.abs(q[0] - p[0]) < 1e-6) || (Math.abs(r[1] - q[1]) < 1e-6 && Math.abs(q[1] - p[1]) < 1e-6)))
|
|
149
|
+
out.pop();
|
|
150
|
+
out.push(p);
|
|
151
|
+
}
|
|
152
|
+
return out;
|
|
153
|
+
}
|
|
154
|
+
/** The diagram with every pipe's points resolved. */
|
|
155
|
+
export function routed(items, aspect) {
|
|
156
|
+
return items.map((p) => (p.type === "pipe" ? { ...p, points: routePipe(p, items, aspect), from: undefined, to: undefined, via: undefined } : p));
|
|
157
|
+
}
|
|
158
|
+
/** Symbols that overlap each other or leave the diagram, as warnings (the screen still saves). */
|
|
159
|
+
export function overlapWarnings(items, aspect) {
|
|
160
|
+
const boxes = [];
|
|
161
|
+
items.forEach((p, i) => {
|
|
162
|
+
const name = `${p.type} ${keyOf(p) ?? i + 1}`;
|
|
163
|
+
if (p.type === "tank")
|
|
164
|
+
boxes.push({ name, x0: p.x, y0: p.y, x1: p.x + p.w, y1: p.y + p.h });
|
|
165
|
+
else if (p.type === "pump" || p.type === "fan" || p.type === "valve") {
|
|
166
|
+
const r = p.size / 2;
|
|
167
|
+
boxes.push({ name, x0: p.x - r, y0: p.y - r / aspect, x1: p.x + r, y1: p.y + r / aspect });
|
|
168
|
+
}
|
|
169
|
+
else if (p.type === "sensor")
|
|
170
|
+
boxes.push({ name, x0: p.x - 7, y0: p.y - 2.2 / aspect, x1: p.x + 7, y1: p.y + 2.2 / aspect });
|
|
171
|
+
});
|
|
172
|
+
const out = [];
|
|
173
|
+
for (const b of boxes)
|
|
174
|
+
if (b.x0 < 0 || b.y0 < 0 || b.x1 > 100 || b.y1 > 100)
|
|
175
|
+
out.push(`${b.name} reaches outside the diagram (0..100).`);
|
|
176
|
+
for (let i = 0; i < boxes.length; i++)
|
|
177
|
+
for (let j = i + 1; j < boxes.length; j++) {
|
|
178
|
+
const a = boxes[i], b = boxes[j];
|
|
179
|
+
if (a.x0 < b.x1 && b.x0 < a.x1 && a.y0 < b.y1 && b.y0 < a.y1)
|
|
180
|
+
out.push(`${a.name} overlaps ${b.name}.`);
|
|
181
|
+
}
|
|
182
|
+
return out;
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=route.js.map
|