schematex 0.2.4 → 0.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/README.md +4 -3
- package/dist/ai/ai-sdk.cjs +10 -10
- package/dist/ai/ai-sdk.d.cts +2 -2
- package/dist/ai/ai-sdk.d.ts +2 -2
- package/dist/ai/ai-sdk.js +5 -5
- package/dist/ai/index.cjs +13 -13
- package/dist/ai/index.d.cts +3 -3
- package/dist/ai/index.d.ts +3 -3
- package/dist/ai/index.js +5 -5
- package/dist/{api-bQZ98gkJ.d.cts → api-BuFilDQB.d.cts} +1 -1
- package/dist/{api-bQZ98gkJ.d.ts → api-BuFilDQB.d.ts} +1 -1
- package/dist/browser.cjs +7 -7
- package/dist/browser.d.cts +2 -2
- package/dist/browser.d.ts +2 -2
- package/dist/browser.js +5 -5
- package/dist/{chunk-UAGSCTYI.cjs → chunk-3FKS4KQK.cjs} +22 -6
- package/dist/chunk-3FKS4KQK.cjs.map +1 -0
- package/dist/{chunk-4S2WILLW.cjs → chunk-K2SOC3XF.cjs} +5 -3
- package/dist/chunk-K2SOC3XF.cjs.map +1 -0
- package/dist/{chunk-LR4X4ZRG.js → chunk-NB56L5QK.js} +18 -14
- package/dist/chunk-NB56L5QK.js.map +1 -0
- package/dist/{chunk-VPKCW4PB.js → chunk-NNU4RGT3.js} +2820 -20
- package/dist/chunk-NNU4RGT3.js.map +1 -0
- package/dist/{chunk-E65ITQXV.cjs → chunk-NZH4GWE6.cjs} +18 -14
- package/dist/chunk-NZH4GWE6.cjs.map +1 -0
- package/dist/{chunk-DPQYGWCT.cjs → chunk-SQKLKBBK.cjs} +32 -5
- package/dist/chunk-SQKLKBBK.cjs.map +1 -0
- package/dist/{chunk-J2LVOWVY.js → chunk-TYCHEOQX.js} +22 -6
- package/dist/chunk-TYCHEOQX.js.map +1 -0
- package/dist/{chunk-MR5HU5WU.js → chunk-VLMK7MQK.js} +30 -3
- package/dist/chunk-VLMK7MQK.js.map +1 -0
- package/dist/{chunk-MSYBSOU2.cjs → chunk-XTATRNUN.cjs} +2824 -22
- package/dist/chunk-XTATRNUN.cjs.map +1 -0
- package/dist/{chunk-PGALHQFF.js → chunk-XZNPAD6E.js} +5 -3
- package/dist/chunk-XZNPAD6E.js.map +1 -0
- package/dist/diagrams/blockdiagram/index.d.cts +1 -1
- package/dist/diagrams/blockdiagram/index.d.ts +1 -1
- package/dist/diagrams/circuit/index.cjs +7 -7
- package/dist/diagrams/circuit/index.d.cts +1 -1
- package/dist/diagrams/circuit/index.d.ts +1 -1
- package/dist/diagrams/circuit/index.js +1 -1
- package/dist/diagrams/ecomap/index.cjs +6 -6
- package/dist/diagrams/ecomap/index.d.cts +1 -1
- package/dist/diagrams/ecomap/index.d.ts +1 -1
- package/dist/diagrams/ecomap/index.js +1 -1
- package/dist/diagrams/entity/index.d.cts +1 -1
- package/dist/diagrams/entity/index.d.ts +1 -1
- package/dist/diagrams/fishbone/index.d.cts +1 -1
- package/dist/diagrams/fishbone/index.d.ts +1 -1
- package/dist/diagrams/flowchart/index.cjs +7 -7
- package/dist/diagrams/flowchart/index.d.cts +2 -2
- package/dist/diagrams/flowchart/index.d.ts +2 -2
- package/dist/diagrams/flowchart/index.js +1 -1
- package/dist/diagrams/genogram/index.d.cts +1 -1
- package/dist/diagrams/genogram/index.d.ts +1 -1
- package/dist/diagrams/ladder/index.d.cts +1 -1
- package/dist/diagrams/ladder/index.d.ts +1 -1
- package/dist/diagrams/logic/index.d.cts +1 -1
- package/dist/diagrams/logic/index.d.ts +1 -1
- package/dist/diagrams/orgchart/index.d.cts +1 -1
- package/dist/diagrams/orgchart/index.d.ts +1 -1
- package/dist/diagrams/pedigree/index.d.cts +1 -1
- package/dist/diagrams/pedigree/index.d.ts +1 -1
- package/dist/diagrams/phylo/index.d.cts +1 -1
- package/dist/diagrams/phylo/index.d.ts +1 -1
- package/dist/diagrams/sld/index.d.cts +1 -1
- package/dist/diagrams/sld/index.d.ts +1 -1
- package/dist/diagrams/sociogram/index.d.cts +1 -1
- package/dist/diagrams/sociogram/index.d.ts +1 -1
- package/dist/diagrams/timing/index.d.cts +1 -1
- package/dist/diagrams/timing/index.d.ts +1 -1
- package/dist/diagrams/venn/index.d.cts +1 -1
- package/dist/diagrams/venn/index.d.ts +1 -1
- package/dist/{index-DcU88F9i.d.ts → index-CUwp4GXI.d.ts} +1 -1
- package/dist/{index-BTZEka65.d.cts → index-ivhNGsyU.d.cts} +1 -1
- package/dist/index.cjs +19 -11
- package/dist/index.d.cts +8 -4
- package/dist/index.d.ts +8 -4
- package/dist/index.js +4 -4
- package/dist/react.cjs +5 -5
- package/dist/react.d.cts +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.js +4 -4
- package/dist/{types-C4LnMEcB.d.cts → types-Bl-Pn7Wj.d.cts} +1 -1
- package/dist/{types-C4LnMEcB.d.ts → types-Bl-Pn7Wj.d.ts} +1 -1
- package/package.json +2 -2
- package/dist/chunk-4S2WILLW.cjs.map +0 -1
- package/dist/chunk-DPQYGWCT.cjs.map +0 -1
- package/dist/chunk-E65ITQXV.cjs.map +0 -1
- package/dist/chunk-J2LVOWVY.js.map +0 -1
- package/dist/chunk-LR4X4ZRG.js.map +0 -1
- package/dist/chunk-MR5HU5WU.js.map +0 -1
- package/dist/chunk-MSYBSOU2.cjs.map +0 -1
- package/dist/chunk-PGALHQFF.js.map +0 -1
- package/dist/chunk-UAGSCTYI.cjs.map +0 -1
- package/dist/chunk-VPKCW4PB.js.map +0 -1
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var chunkA5D2IMOX_cjs = require('./chunk-A5D2IMOX.cjs');
|
|
4
|
-
var
|
|
4
|
+
var chunkK2SOC3XF_cjs = require('./chunk-K2SOC3XF.cjs');
|
|
5
5
|
var chunkMCFQAUQV_cjs = require('./chunk-MCFQAUQV.cjs');
|
|
6
6
|
var chunkB6INLQBU_cjs = require('./chunk-B6INLQBU.cjs');
|
|
7
7
|
var chunk3YZ6FPQW_cjs = require('./chunk-3YZ6FPQW.cjs');
|
|
8
8
|
var chunkZNOD4VZT_cjs = require('./chunk-ZNOD4VZT.cjs');
|
|
9
9
|
var chunk5AEN2PLB_cjs = require('./chunk-5AEN2PLB.cjs');
|
|
10
10
|
var chunkQSQX77S2_cjs = require('./chunk-QSQX77S2.cjs');
|
|
11
|
-
var
|
|
11
|
+
var chunk3FKS4KQK_cjs = require('./chunk-3FKS4KQK.cjs');
|
|
12
12
|
var chunkMJGDP3CS_cjs = require('./chunk-MJGDP3CS.cjs');
|
|
13
|
-
var
|
|
13
|
+
var chunkNZH4GWE6_cjs = require('./chunk-NZH4GWE6.cjs');
|
|
14
14
|
var chunkB37IKTI7_cjs = require('./chunk-B37IKTI7.cjs');
|
|
15
15
|
var chunkX7RPFTTR_cjs = require('./chunk-X7RPFTTR.cjs');
|
|
16
16
|
var chunkCOLTVQWR_cjs = require('./chunk-COLTVQWR.cjs');
|
|
@@ -623,7 +623,7 @@ function layoutDecisionTree(ast) {
|
|
|
623
623
|
enforceSibGap(root, sibH, sibGap);
|
|
624
624
|
const levelOffsets = computeLevelOffsets(root, sibH, levelGap);
|
|
625
625
|
setFinal(root, sibH, levelOffsets);
|
|
626
|
-
const
|
|
626
|
+
const PADDING3 = 40;
|
|
627
627
|
const extraLeft = ast.mode === "decision" && !sibH ? 110 : 0;
|
|
628
628
|
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
629
629
|
for (const n of all) {
|
|
@@ -648,8 +648,8 @@ function layoutDecisionTree(ast) {
|
|
|
648
648
|
maxX = Math.max(maxX, n.xFinal + n.size.w / 2);
|
|
649
649
|
}
|
|
650
650
|
}
|
|
651
|
-
const offsetX =
|
|
652
|
-
const offsetY =
|
|
651
|
+
const offsetX = PADDING3 + extraLeft - minX;
|
|
652
|
+
const offsetY = PADDING3 - minY;
|
|
653
653
|
const layoutNodes = all.map((w) => ({
|
|
654
654
|
node: w.node,
|
|
655
655
|
x: w.xFinal + offsetX,
|
|
@@ -710,8 +710,8 @@ function layoutDecisionTree(ast) {
|
|
|
710
710
|
for (const n of layoutNodes) if (n.node.kind === "end") endX = Math.max(endX, n.x + n.width / 2);
|
|
711
711
|
payoffColumnX = endX + payoffColGap;
|
|
712
712
|
}
|
|
713
|
-
const width = Math.ceil(maxX - minX +
|
|
714
|
-
const height = Math.ceil(maxY - minY +
|
|
713
|
+
const width = Math.ceil(maxX - minX + PADDING3 * 2 + extraRight + extraLeft);
|
|
714
|
+
const height = Math.ceil(maxY - minY + PADDING3 * 2);
|
|
715
715
|
return {
|
|
716
716
|
width,
|
|
717
717
|
height,
|
|
@@ -2628,6 +2628,2804 @@ var timeline = {
|
|
|
2628
2628
|
}
|
|
2629
2629
|
};
|
|
2630
2630
|
|
|
2631
|
+
// src/diagrams/state/parser.ts
|
|
2632
|
+
var StateParseError = class extends Error {
|
|
2633
|
+
constructor(message, line2) {
|
|
2634
|
+
super(line2 !== void 0 ? `Line ${line2}: ${message}` : message);
|
|
2635
|
+
this.line = line2;
|
|
2636
|
+
this.name = "StateParseError";
|
|
2637
|
+
}
|
|
2638
|
+
line;
|
|
2639
|
+
};
|
|
2640
|
+
var PSEUDO_KEYWORDS = {
|
|
2641
|
+
initial: "initial",
|
|
2642
|
+
final: "final",
|
|
2643
|
+
choice: "choice",
|
|
2644
|
+
junction: "junction",
|
|
2645
|
+
fork: "fork",
|
|
2646
|
+
join: "join",
|
|
2647
|
+
history: "history",
|
|
2648
|
+
dhistory: "dhistory",
|
|
2649
|
+
terminate: "terminate",
|
|
2650
|
+
entry_point: "entry_point",
|
|
2651
|
+
exit_point: "exit_point"
|
|
2652
|
+
};
|
|
2653
|
+
var MERMAID_STEREOTYPE = {
|
|
2654
|
+
choice: "choice",
|
|
2655
|
+
fork: "fork",
|
|
2656
|
+
join: "join",
|
|
2657
|
+
end: "final"
|
|
2658
|
+
};
|
|
2659
|
+
function preprocess3(src) {
|
|
2660
|
+
const out = [];
|
|
2661
|
+
const lines = src.split(/\r?\n/);
|
|
2662
|
+
for (let i = 0; i < lines.length; i++) {
|
|
2663
|
+
const raw = lines[i];
|
|
2664
|
+
if (raw === void 0) continue;
|
|
2665
|
+
const trimmed = raw.trim();
|
|
2666
|
+
if (!trimmed) continue;
|
|
2667
|
+
if (trimmed.startsWith("#") || trimmed.startsWith("//") || trimmed.startsWith("%%")) continue;
|
|
2668
|
+
const indent = raw.length - raw.replace(/^\s+/, "").length;
|
|
2669
|
+
out.push({ indent, text: trimmed, line: i + 1 });
|
|
2670
|
+
}
|
|
2671
|
+
return out;
|
|
2672
|
+
}
|
|
2673
|
+
function unquote2(s) {
|
|
2674
|
+
if (s.length >= 2 && s.startsWith('"') && s.endsWith('"')) {
|
|
2675
|
+
return s.slice(1, -1);
|
|
2676
|
+
}
|
|
2677
|
+
return s;
|
|
2678
|
+
}
|
|
2679
|
+
function parseProps(s) {
|
|
2680
|
+
const out = {};
|
|
2681
|
+
const inner = s.replace(/^\[/, "").replace(/\]$/, "");
|
|
2682
|
+
if (!inner.trim()) return out;
|
|
2683
|
+
for (const part of inner.split(",")) {
|
|
2684
|
+
const idx = part.indexOf(":");
|
|
2685
|
+
if (idx < 0) continue;
|
|
2686
|
+
out[part.slice(0, idx).trim()] = unquote2(part.slice(idx + 1).trim());
|
|
2687
|
+
}
|
|
2688
|
+
return out;
|
|
2689
|
+
}
|
|
2690
|
+
function parseTransitionLabel(label) {
|
|
2691
|
+
const out = {};
|
|
2692
|
+
let rest = label.trim();
|
|
2693
|
+
if (!rest) return out;
|
|
2694
|
+
let depth = 0;
|
|
2695
|
+
let slashIdx = -1;
|
|
2696
|
+
for (let i = 0; i < rest.length; i++) {
|
|
2697
|
+
const c = rest[i];
|
|
2698
|
+
if (c === "[") depth++;
|
|
2699
|
+
else if (c === "]") depth--;
|
|
2700
|
+
else if (c === "/" && depth === 0) {
|
|
2701
|
+
slashIdx = i;
|
|
2702
|
+
break;
|
|
2703
|
+
}
|
|
2704
|
+
}
|
|
2705
|
+
if (slashIdx >= 0) {
|
|
2706
|
+
out.action = rest.slice(slashIdx + 1).trim();
|
|
2707
|
+
rest = rest.slice(0, slashIdx).trim();
|
|
2708
|
+
}
|
|
2709
|
+
const gMatch = rest.match(/^(?<trig>[^[]*?)\s*\[(?<guard>[^\]]*)\]\s*$/);
|
|
2710
|
+
if (gMatch?.groups) {
|
|
2711
|
+
out.guard = gMatch.groups.guard.trim();
|
|
2712
|
+
const trig = gMatch.groups.trig.trim();
|
|
2713
|
+
if (trig) out.trigger = trig;
|
|
2714
|
+
} else if (rest.length) {
|
|
2715
|
+
out.trigger = rest;
|
|
2716
|
+
}
|
|
2717
|
+
return out;
|
|
2718
|
+
}
|
|
2719
|
+
function parseActivityLine(text2) {
|
|
2720
|
+
const match = text2.match(/^(entry|exit|do)\s*\/\s*(.*)$/);
|
|
2721
|
+
if (match) {
|
|
2722
|
+
return { kind: match[1], action: match[2].trim() };
|
|
2723
|
+
}
|
|
2724
|
+
const parsed = parseTransitionLabel(text2);
|
|
2725
|
+
if (!parsed.trigger && !parsed.guard && !parsed.action) return void 0;
|
|
2726
|
+
return {
|
|
2727
|
+
kind: "internal",
|
|
2728
|
+
trigger: parsed.trigger,
|
|
2729
|
+
guard: parsed.guard,
|
|
2730
|
+
action: parsed.action
|
|
2731
|
+
};
|
|
2732
|
+
}
|
|
2733
|
+
function newPseudoId(ctx, kind) {
|
|
2734
|
+
ctx.pseudoCounter += 1;
|
|
2735
|
+
return `__${kind}_${ctx.pseudoCounter}`;
|
|
2736
|
+
}
|
|
2737
|
+
function ensureInitialAlias(ctx, parent) {
|
|
2738
|
+
if (!parent) {
|
|
2739
|
+
if (ctx.initialAlias) {
|
|
2740
|
+
const existing = ctx.byId.get(ctx.initialAlias);
|
|
2741
|
+
if (existing) return existing;
|
|
2742
|
+
}
|
|
2743
|
+
const node2 = {
|
|
2744
|
+
id: newPseudoId(ctx, "initial"),
|
|
2745
|
+
label: "",
|
|
2746
|
+
kind: "pseudo",
|
|
2747
|
+
pseudoKind: "initial",
|
|
2748
|
+
activities: [],
|
|
2749
|
+
children: []
|
|
2750
|
+
};
|
|
2751
|
+
ctx.initialAlias = node2.id;
|
|
2752
|
+
ctx.byId.set(node2.id, node2);
|
|
2753
|
+
ctx.states.push(node2);
|
|
2754
|
+
return node2;
|
|
2755
|
+
}
|
|
2756
|
+
for (const child of parent.children) {
|
|
2757
|
+
if (child.id.startsWith("__initial_") && child.label === "") return child;
|
|
2758
|
+
}
|
|
2759
|
+
const node = {
|
|
2760
|
+
id: newPseudoId(ctx, "initial"),
|
|
2761
|
+
label: "",
|
|
2762
|
+
kind: "pseudo",
|
|
2763
|
+
pseudoKind: "initial",
|
|
2764
|
+
activities: [],
|
|
2765
|
+
children: [],
|
|
2766
|
+
parent: parent.id
|
|
2767
|
+
};
|
|
2768
|
+
ctx.byId.set(node.id, node);
|
|
2769
|
+
parent.children.push(node);
|
|
2770
|
+
return node;
|
|
2771
|
+
}
|
|
2772
|
+
function ensureFinalAlias(ctx, parent) {
|
|
2773
|
+
if (!parent) {
|
|
2774
|
+
if (ctx.finalAlias) {
|
|
2775
|
+
const existing = ctx.byId.get(ctx.finalAlias);
|
|
2776
|
+
if (existing) return existing;
|
|
2777
|
+
}
|
|
2778
|
+
const node2 = {
|
|
2779
|
+
id: newPseudoId(ctx, "final"),
|
|
2780
|
+
label: "",
|
|
2781
|
+
kind: "pseudo",
|
|
2782
|
+
pseudoKind: "final",
|
|
2783
|
+
activities: [],
|
|
2784
|
+
children: []
|
|
2785
|
+
};
|
|
2786
|
+
ctx.finalAlias = node2.id;
|
|
2787
|
+
ctx.byId.set(node2.id, node2);
|
|
2788
|
+
ctx.states.push(node2);
|
|
2789
|
+
return node2;
|
|
2790
|
+
}
|
|
2791
|
+
for (const child of parent.children) {
|
|
2792
|
+
if (child.id.startsWith("__final_") && child.label === "") return child;
|
|
2793
|
+
}
|
|
2794
|
+
const node = {
|
|
2795
|
+
id: newPseudoId(ctx, "final"),
|
|
2796
|
+
label: "",
|
|
2797
|
+
kind: "pseudo",
|
|
2798
|
+
pseudoKind: "final",
|
|
2799
|
+
activities: [],
|
|
2800
|
+
children: [],
|
|
2801
|
+
parent: parent.id
|
|
2802
|
+
};
|
|
2803
|
+
ctx.byId.set(node.id, node);
|
|
2804
|
+
parent.children.push(node);
|
|
2805
|
+
return node;
|
|
2806
|
+
}
|
|
2807
|
+
function ensureSimpleState(ctx, id, parent) {
|
|
2808
|
+
const existing = ctx.byId.get(id);
|
|
2809
|
+
if (existing) return existing;
|
|
2810
|
+
const node = {
|
|
2811
|
+
id,
|
|
2812
|
+
label: id,
|
|
2813
|
+
kind: "simple",
|
|
2814
|
+
activities: [],
|
|
2815
|
+
children: [],
|
|
2816
|
+
parent: parent?.id
|
|
2817
|
+
};
|
|
2818
|
+
ctx.byId.set(id, node);
|
|
2819
|
+
if (parent) parent.children.push(node);
|
|
2820
|
+
else ctx.states.push(node);
|
|
2821
|
+
return node;
|
|
2822
|
+
}
|
|
2823
|
+
function isIdent(tok) {
|
|
2824
|
+
return /^[A-Za-z_][A-Za-z0-9_]*$/.test(tok);
|
|
2825
|
+
}
|
|
2826
|
+
function parseStateDiagram(src) {
|
|
2827
|
+
const lines = preprocess3(src);
|
|
2828
|
+
if (lines.length === 0) {
|
|
2829
|
+
throw new StateParseError("Empty document");
|
|
2830
|
+
}
|
|
2831
|
+
const header = lines[0];
|
|
2832
|
+
const headerTok = header.text.match(/^(stateDiagram-v2|stateDiagram|state)\b/i);
|
|
2833
|
+
if (!headerTok) {
|
|
2834
|
+
throw new StateParseError(
|
|
2835
|
+
`Expected 'state' or 'stateDiagram' header, got '${header.text}'`,
|
|
2836
|
+
header.line
|
|
2837
|
+
);
|
|
2838
|
+
}
|
|
2839
|
+
let title2;
|
|
2840
|
+
let direction = "TB";
|
|
2841
|
+
const headerRest = header.text.slice(headerTok[0].length).trim();
|
|
2842
|
+
const propsMatch = headerRest.match(/\[[^\]]*\]\s*$/);
|
|
2843
|
+
let beforeProps = headerRest;
|
|
2844
|
+
if (propsMatch) {
|
|
2845
|
+
const props = parseProps(propsMatch[0]);
|
|
2846
|
+
if (props.direction === "TB" || props.direction === "LR") direction = props.direction;
|
|
2847
|
+
beforeProps = headerRest.slice(0, propsMatch.index).trim();
|
|
2848
|
+
}
|
|
2849
|
+
if (beforeProps.startsWith('"')) title2 = unquote2(beforeProps);
|
|
2850
|
+
else if (beforeProps.length > 0) title2 = beforeProps;
|
|
2851
|
+
const ctx = {
|
|
2852
|
+
states: [],
|
|
2853
|
+
transitions: [],
|
|
2854
|
+
notes: [],
|
|
2855
|
+
pseudoCounter: 0,
|
|
2856
|
+
noteCounter: 0,
|
|
2857
|
+
transCounter: 0,
|
|
2858
|
+
byId: /* @__PURE__ */ new Map()
|
|
2859
|
+
};
|
|
2860
|
+
const compositeStack = [{ parent: void 0, regionMode: false }];
|
|
2861
|
+
let i = 1;
|
|
2862
|
+
while (i < lines.length) {
|
|
2863
|
+
const ln = lines[i];
|
|
2864
|
+
const text2 = ln.text;
|
|
2865
|
+
const ctxTop = compositeStack[compositeStack.length - 1];
|
|
2866
|
+
const parent = ctxTop.parent;
|
|
2867
|
+
if (text2 === "}") {
|
|
2868
|
+
if (compositeStack.length <= 1) {
|
|
2869
|
+
throw new StateParseError("Unexpected '}'", ln.line);
|
|
2870
|
+
}
|
|
2871
|
+
compositeStack.pop();
|
|
2872
|
+
i++;
|
|
2873
|
+
continue;
|
|
2874
|
+
}
|
|
2875
|
+
if (text2 === "---" || text2 === "--") {
|
|
2876
|
+
if (!parent) {
|
|
2877
|
+
throw new StateParseError(
|
|
2878
|
+
"Region separator only allowed inside a composite",
|
|
2879
|
+
ln.line
|
|
2880
|
+
);
|
|
2881
|
+
}
|
|
2882
|
+
ctxTop.regionMode = true;
|
|
2883
|
+
if (!parent.regions) parent.regions = [];
|
|
2884
|
+
const lastIdx = parent.regions.reduce((s, r) => s + r.length, 0);
|
|
2885
|
+
const slice = parent.children.slice(lastIdx);
|
|
2886
|
+
parent.regions.push(slice);
|
|
2887
|
+
i++;
|
|
2888
|
+
continue;
|
|
2889
|
+
}
|
|
2890
|
+
const dirMatch = text2.match(/^direction\s+(TB|BT|LR|RL)\s*$/);
|
|
2891
|
+
if (dirMatch) {
|
|
2892
|
+
const d = dirMatch[1];
|
|
2893
|
+
direction = d === "BT" ? "TB" : d === "RL" ? "LR" : d;
|
|
2894
|
+
i++;
|
|
2895
|
+
continue;
|
|
2896
|
+
}
|
|
2897
|
+
const compMatch = text2.match(/^(?:composite|state)\s+([A-Za-z_][A-Za-z0-9_]*)\s*\{?\s*$/);
|
|
2898
|
+
const isCompositeWithBrace = compMatch && text2.endsWith("{");
|
|
2899
|
+
if (isCompositeWithBrace) {
|
|
2900
|
+
const id = compMatch[1];
|
|
2901
|
+
const node = ensureSimpleState(ctx, id, parent);
|
|
2902
|
+
node.kind = "composite";
|
|
2903
|
+
compositeStack.push({ parent: node, regionMode: false });
|
|
2904
|
+
i++;
|
|
2905
|
+
continue;
|
|
2906
|
+
}
|
|
2907
|
+
const aliasMatch = text2.match(/^state\s+"([^"]*)"\s+as\s+([A-Za-z_][A-Za-z0-9_]*)\s*$/);
|
|
2908
|
+
if (aliasMatch) {
|
|
2909
|
+
const node = ensureSimpleState(ctx, aliasMatch[2], parent);
|
|
2910
|
+
node.label = aliasMatch[1];
|
|
2911
|
+
i++;
|
|
2912
|
+
continue;
|
|
2913
|
+
}
|
|
2914
|
+
const stereoMatch = text2.match(/^state\s+([A-Za-z_][A-Za-z0-9_]*)\s+<<\s*(choice|fork|join|end)\s*>>\s*$/);
|
|
2915
|
+
if (stereoMatch) {
|
|
2916
|
+
const id = stereoMatch[1];
|
|
2917
|
+
const kind = MERMAID_STEREOTYPE[stereoMatch[2]];
|
|
2918
|
+
const node = {
|
|
2919
|
+
id,
|
|
2920
|
+
label: "",
|
|
2921
|
+
kind: "pseudo",
|
|
2922
|
+
pseudoKind: kind,
|
|
2923
|
+
activities: [],
|
|
2924
|
+
children: [],
|
|
2925
|
+
parent: parent?.id
|
|
2926
|
+
};
|
|
2927
|
+
ctx.byId.set(id, node);
|
|
2928
|
+
if (parent) parent.children.push(node);
|
|
2929
|
+
else ctx.states.push(node);
|
|
2930
|
+
i++;
|
|
2931
|
+
continue;
|
|
2932
|
+
}
|
|
2933
|
+
const stateLabelMatch = text2.match(/^state\s+([A-Za-z_][A-Za-z0-9_]*)\s*:\s*(.+)$/);
|
|
2934
|
+
if (stateLabelMatch) {
|
|
2935
|
+
const node = ensureSimpleState(ctx, stateLabelMatch[1], parent);
|
|
2936
|
+
node.label = unquote2(stateLabelMatch[2].trim());
|
|
2937
|
+
i++;
|
|
2938
|
+
continue;
|
|
2939
|
+
}
|
|
2940
|
+
const pseudoMatch = text2.match(
|
|
2941
|
+
/^(initial|final|choice|junction|fork|join|history|dhistory|terminate|entry_point|exit_point)\s+([A-Za-z_][A-Za-z0-9_]*)\s*$/
|
|
2942
|
+
);
|
|
2943
|
+
if (pseudoMatch) {
|
|
2944
|
+
const kindKw = pseudoMatch[1];
|
|
2945
|
+
const id = pseudoMatch[2];
|
|
2946
|
+
const pkind = PSEUDO_KEYWORDS[kindKw];
|
|
2947
|
+
const node = {
|
|
2948
|
+
id,
|
|
2949
|
+
label: "",
|
|
2950
|
+
kind: "pseudo",
|
|
2951
|
+
pseudoKind: pkind,
|
|
2952
|
+
activities: [],
|
|
2953
|
+
children: [],
|
|
2954
|
+
parent: parent?.id
|
|
2955
|
+
};
|
|
2956
|
+
ctx.byId.set(id, node);
|
|
2957
|
+
if (parent) parent.children.push(node);
|
|
2958
|
+
else ctx.states.push(node);
|
|
2959
|
+
i++;
|
|
2960
|
+
continue;
|
|
2961
|
+
}
|
|
2962
|
+
if (parent) {
|
|
2963
|
+
const activity = parseActivityLine(text2);
|
|
2964
|
+
if (activity && (activity.kind === "entry" || activity.kind === "exit" || activity.kind === "do")) {
|
|
2965
|
+
parent.activities.push(activity);
|
|
2966
|
+
i++;
|
|
2967
|
+
continue;
|
|
2968
|
+
}
|
|
2969
|
+
}
|
|
2970
|
+
const noteSimple = text2.match(
|
|
2971
|
+
/^note\s+(left[_ ]of|right[_ ]of)\s+([A-Za-z_][A-Za-z0-9_]*)\s*:\s*(.*)$/
|
|
2972
|
+
);
|
|
2973
|
+
if (noteSimple) {
|
|
2974
|
+
const side = noteSimple[1].startsWith("left") ? "left" : "right";
|
|
2975
|
+
const target = noteSimple[2];
|
|
2976
|
+
ctx.noteCounter += 1;
|
|
2977
|
+
ctx.notes.push({
|
|
2978
|
+
id: `__note_${ctx.noteCounter}`,
|
|
2979
|
+
target,
|
|
2980
|
+
side,
|
|
2981
|
+
text: noteSimple[3].trim()
|
|
2982
|
+
});
|
|
2983
|
+
i++;
|
|
2984
|
+
continue;
|
|
2985
|
+
}
|
|
2986
|
+
const noteBlockMermaid = text2.match(
|
|
2987
|
+
/^note\s+(left[_ ]of|right[_ ]of)\s+([A-Za-z_][A-Za-z0-9_]*)\s*$/
|
|
2988
|
+
);
|
|
2989
|
+
if (noteBlockMermaid) {
|
|
2990
|
+
const side = noteBlockMermaid[1].startsWith("left") ? "left" : "right";
|
|
2991
|
+
const target = noteBlockMermaid[2];
|
|
2992
|
+
const buf = [];
|
|
2993
|
+
i++;
|
|
2994
|
+
while (i < lines.length) {
|
|
2995
|
+
const t = lines[i].text;
|
|
2996
|
+
if (t === "end note" || t === "}") break;
|
|
2997
|
+
buf.push(t);
|
|
2998
|
+
i++;
|
|
2999
|
+
}
|
|
3000
|
+
if (i >= lines.length) {
|
|
3001
|
+
throw new StateParseError("Unterminated note block", ln.line);
|
|
3002
|
+
}
|
|
3003
|
+
i++;
|
|
3004
|
+
ctx.noteCounter += 1;
|
|
3005
|
+
ctx.notes.push({
|
|
3006
|
+
id: `__note_${ctx.noteCounter}`,
|
|
3007
|
+
target,
|
|
3008
|
+
side,
|
|
3009
|
+
text: buf.join("\n")
|
|
3010
|
+
});
|
|
3011
|
+
continue;
|
|
3012
|
+
}
|
|
3013
|
+
const noteBlockSchematex = text2.match(
|
|
3014
|
+
/^note\s+(left[_ ]of\s+|right[_ ]of\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*\{\s*$/
|
|
3015
|
+
);
|
|
3016
|
+
if (noteBlockSchematex) {
|
|
3017
|
+
const side = noteBlockSchematex[1]?.startsWith("left") ? "left" : "right";
|
|
3018
|
+
const target = noteBlockSchematex[2];
|
|
3019
|
+
const buf = [];
|
|
3020
|
+
i++;
|
|
3021
|
+
while (i < lines.length && lines[i].text !== "}") {
|
|
3022
|
+
buf.push(lines[i].text);
|
|
3023
|
+
i++;
|
|
3024
|
+
}
|
|
3025
|
+
if (i >= lines.length) {
|
|
3026
|
+
throw new StateParseError("Unterminated note block", ln.line);
|
|
3027
|
+
}
|
|
3028
|
+
i++;
|
|
3029
|
+
ctx.noteCounter += 1;
|
|
3030
|
+
ctx.notes.push({
|
|
3031
|
+
id: `__note_${ctx.noteCounter}`,
|
|
3032
|
+
target,
|
|
3033
|
+
side,
|
|
3034
|
+
text: buf.join("\n")
|
|
3035
|
+
});
|
|
3036
|
+
continue;
|
|
3037
|
+
}
|
|
3038
|
+
const transMatch = text2.match(
|
|
3039
|
+
/^(\[\*\]|[A-Za-z_][A-Za-z0-9_]*)\s*-+>\s*(\[\*\]|[A-Za-z_][A-Za-z0-9_]*)\s*(?::\s*(.*))?$/
|
|
3040
|
+
);
|
|
3041
|
+
if (transMatch) {
|
|
3042
|
+
const fromTok = transMatch[1];
|
|
3043
|
+
const toTok = transMatch[2];
|
|
3044
|
+
const labelRaw = transMatch[3];
|
|
3045
|
+
const resolveTok = (tok, position) => {
|
|
3046
|
+
if (tok === "[*]") {
|
|
3047
|
+
if (position === "from") return ensureInitialAlias(ctx, parent).id;
|
|
3048
|
+
return ensureFinalAlias(ctx, parent).id;
|
|
3049
|
+
}
|
|
3050
|
+
return ensureSimpleState(ctx, tok, parent).id;
|
|
3051
|
+
};
|
|
3052
|
+
const fromId = resolveTok(fromTok, "from");
|
|
3053
|
+
const toId = resolveTok(toTok, "to");
|
|
3054
|
+
ctx.transCounter += 1;
|
|
3055
|
+
const tid = `t${ctx.transCounter}`;
|
|
3056
|
+
const parsedLabel = labelRaw ? parseTransitionLabel(labelRaw) : {};
|
|
3057
|
+
ctx.transitions.push({
|
|
3058
|
+
id: tid,
|
|
3059
|
+
from: fromId,
|
|
3060
|
+
to: toId,
|
|
3061
|
+
trigger: parsedLabel.trigger,
|
|
3062
|
+
guard: parsedLabel.guard,
|
|
3063
|
+
action: parsedLabel.action
|
|
3064
|
+
});
|
|
3065
|
+
i++;
|
|
3066
|
+
continue;
|
|
3067
|
+
}
|
|
3068
|
+
const labelOnlyMatch = text2.match(/^([A-Za-z_][A-Za-z0-9_]*)\s*:\s*(.+)$/);
|
|
3069
|
+
if (labelOnlyMatch && isIdent(labelOnlyMatch[1])) {
|
|
3070
|
+
const node = ensureSimpleState(ctx, labelOnlyMatch[1], parent);
|
|
3071
|
+
node.label = unquote2(labelOnlyMatch[2].trim());
|
|
3072
|
+
i++;
|
|
3073
|
+
continue;
|
|
3074
|
+
}
|
|
3075
|
+
const bareIdent = text2.match(/^([A-Za-z_][A-Za-z0-9_]*)\s*$/);
|
|
3076
|
+
if (bareIdent) {
|
|
3077
|
+
ensureSimpleState(ctx, bareIdent[1], parent);
|
|
3078
|
+
i++;
|
|
3079
|
+
continue;
|
|
3080
|
+
}
|
|
3081
|
+
throw new StateParseError(`Unparseable line: ${text2}`, ln.line);
|
|
3082
|
+
}
|
|
3083
|
+
if (compositeStack.length > 1) {
|
|
3084
|
+
throw new StateParseError("Unclosed composite block (expected '}')");
|
|
3085
|
+
}
|
|
3086
|
+
function finalizeRegions(node) {
|
|
3087
|
+
if (node.regions) {
|
|
3088
|
+
const consumed = node.regions.reduce((s, r) => s + r.length, 0);
|
|
3089
|
+
if (node.children.length > consumed) {
|
|
3090
|
+
node.regions.push(node.children.slice(consumed));
|
|
3091
|
+
}
|
|
3092
|
+
}
|
|
3093
|
+
for (const child of node.children) finalizeRegions(child);
|
|
3094
|
+
}
|
|
3095
|
+
for (const s of ctx.states) finalizeRegions(s);
|
|
3096
|
+
return {
|
|
3097
|
+
type: "state",
|
|
3098
|
+
title: title2,
|
|
3099
|
+
direction,
|
|
3100
|
+
states: ctx.states,
|
|
3101
|
+
transitions: ctx.transitions,
|
|
3102
|
+
notes: ctx.notes
|
|
3103
|
+
};
|
|
3104
|
+
}
|
|
3105
|
+
|
|
3106
|
+
// src/diagrams/state/layout.ts
|
|
3107
|
+
var PSEUDO_BBOX = {
|
|
3108
|
+
initial: { w: 22, h: 22 },
|
|
3109
|
+
final: { w: 28, h: 28 },
|
|
3110
|
+
choice: { w: 32, h: 32 },
|
|
3111
|
+
junction: { w: 16, h: 16 },
|
|
3112
|
+
fork: { w: 100, h: 8 },
|
|
3113
|
+
// horizontal bar — rotated for LR direction below
|
|
3114
|
+
join: { w: 100, h: 8 },
|
|
3115
|
+
history: { w: 26, h: 26 },
|
|
3116
|
+
dhistory: { w: 30, h: 30 },
|
|
3117
|
+
terminate: { w: 22, h: 22 },
|
|
3118
|
+
entry_point: { w: 18, h: 18 },
|
|
3119
|
+
exit_point: { w: 18, h: 18 }
|
|
3120
|
+
};
|
|
3121
|
+
var NOTE_W = 180;
|
|
3122
|
+
var NOTE_LINE_H = 14;
|
|
3123
|
+
function shapeForState(node) {
|
|
3124
|
+
if (node.kind === "simple") return "round";
|
|
3125
|
+
if (node.kind === "composite") return "round";
|
|
3126
|
+
switch (node.pseudoKind) {
|
|
3127
|
+
case "initial":
|
|
3128
|
+
case "final":
|
|
3129
|
+
case "junction":
|
|
3130
|
+
case "history":
|
|
3131
|
+
case "dhistory":
|
|
3132
|
+
case "terminate":
|
|
3133
|
+
case "entry_point":
|
|
3134
|
+
case "exit_point":
|
|
3135
|
+
return "circle";
|
|
3136
|
+
case "choice":
|
|
3137
|
+
return "diamond";
|
|
3138
|
+
case "fork":
|
|
3139
|
+
case "join":
|
|
3140
|
+
return "rect";
|
|
3141
|
+
default:
|
|
3142
|
+
return "round";
|
|
3143
|
+
}
|
|
3144
|
+
}
|
|
3145
|
+
function buildLabel(t) {
|
|
3146
|
+
const parts = [];
|
|
3147
|
+
if (t.trigger) parts.push(t.trigger);
|
|
3148
|
+
if (t.guard) parts.push(`[${t.guard}]`);
|
|
3149
|
+
let s = parts.join(" ");
|
|
3150
|
+
if (t.action) s = s ? `${s} / ${t.action}` : `/ ${t.action}`;
|
|
3151
|
+
return s.trim() || void 0;
|
|
3152
|
+
}
|
|
3153
|
+
function convertToFlowchart(ast) {
|
|
3154
|
+
const fcNodes = [];
|
|
3155
|
+
const fcSubgraphs = [];
|
|
3156
|
+
const pseudoSizes = /* @__PURE__ */ new Map();
|
|
3157
|
+
const compositeEntryFor = /* @__PURE__ */ new Map();
|
|
3158
|
+
const compositeExitFor = /* @__PURE__ */ new Map();
|
|
3159
|
+
const visit = (s, parentId) => {
|
|
3160
|
+
if (s.kind === "composite") {
|
|
3161
|
+
const childIds = [];
|
|
3162
|
+
const childSgIds = [];
|
|
3163
|
+
for (const child of s.children) {
|
|
3164
|
+
if (child.kind === "composite") childSgIds.push(child.id);
|
|
3165
|
+
else childIds.push(child.id);
|
|
3166
|
+
}
|
|
3167
|
+
let entryChild;
|
|
3168
|
+
let exitChild;
|
|
3169
|
+
for (const child of s.children) {
|
|
3170
|
+
if (child.kind === "pseudo" && child.pseudoKind === "initial" && !entryChild) {
|
|
3171
|
+
entryChild = child.id;
|
|
3172
|
+
}
|
|
3173
|
+
if (child.kind === "pseudo" && child.pseudoKind === "final") {
|
|
3174
|
+
exitChild = child.id;
|
|
3175
|
+
}
|
|
3176
|
+
}
|
|
3177
|
+
if (!entryChild) entryChild = s.children[0]?.id;
|
|
3178
|
+
if (!exitChild) exitChild = s.children[s.children.length - 1]?.id;
|
|
3179
|
+
if (entryChild) compositeEntryFor.set(s.id, entryChild);
|
|
3180
|
+
if (exitChild) compositeExitFor.set(s.id, exitChild);
|
|
3181
|
+
fcSubgraphs.push({
|
|
3182
|
+
id: s.id,
|
|
3183
|
+
label: s.label || s.id,
|
|
3184
|
+
direction: ast.direction,
|
|
3185
|
+
children: childIds,
|
|
3186
|
+
subgraphs: childSgIds
|
|
3187
|
+
});
|
|
3188
|
+
for (const child of s.children) visit(child, s.id);
|
|
3189
|
+
return;
|
|
3190
|
+
}
|
|
3191
|
+
const node = {
|
|
3192
|
+
id: s.id,
|
|
3193
|
+
label: labelForFlowchart(s),
|
|
3194
|
+
shape: shapeForState(s),
|
|
3195
|
+
parent: parentId
|
|
3196
|
+
};
|
|
3197
|
+
fcNodes.push(node);
|
|
3198
|
+
if (s.kind === "pseudo" && s.pseudoKind) {
|
|
3199
|
+
pseudoSizes.set(s.id, { ...PSEUDO_BBOX[s.pseudoKind] });
|
|
3200
|
+
}
|
|
3201
|
+
};
|
|
3202
|
+
for (const s of ast.states) visit(s, void 0);
|
|
3203
|
+
const fcEdges = ast.transitions.map((t) => {
|
|
3204
|
+
let from = t.from;
|
|
3205
|
+
let to = t.to;
|
|
3206
|
+
const fromExit = compositeExitFor.get(t.from);
|
|
3207
|
+
if (fromExit) from = fromExit;
|
|
3208
|
+
const toEntry = compositeEntryFor.get(t.to);
|
|
3209
|
+
if (toEntry) to = toEntry;
|
|
3210
|
+
return {
|
|
3211
|
+
id: t.id,
|
|
3212
|
+
from,
|
|
3213
|
+
to,
|
|
3214
|
+
kind: "solid",
|
|
3215
|
+
label: buildLabel(t)
|
|
3216
|
+
};
|
|
3217
|
+
});
|
|
3218
|
+
const fc = {
|
|
3219
|
+
type: "flowchart",
|
|
3220
|
+
title: ast.title,
|
|
3221
|
+
direction: ast.direction === "LR" ? "LR" : "TB",
|
|
3222
|
+
nodes: fcNodes,
|
|
3223
|
+
edges: fcEdges,
|
|
3224
|
+
subgraphs: fcSubgraphs,
|
|
3225
|
+
classDefs: [],
|
|
3226
|
+
linkStyles: /* @__PURE__ */ new Map()
|
|
3227
|
+
};
|
|
3228
|
+
return { ast: fc, pseudoSizes };
|
|
3229
|
+
}
|
|
3230
|
+
function labelForFlowchart(s) {
|
|
3231
|
+
if (s.kind === "pseudo") return "";
|
|
3232
|
+
if (s.activities.length === 0) return s.label || s.id;
|
|
3233
|
+
const activityWidth = s.activities.map((a) => activityText(a).length).reduce((m, n) => Math.max(m, n), 0);
|
|
3234
|
+
const label = s.label || s.id;
|
|
3235
|
+
return label.length >= activityWidth ? label : "x".repeat(activityWidth);
|
|
3236
|
+
}
|
|
3237
|
+
function activityText(a) {
|
|
3238
|
+
if (a.kind === "entry" || a.kind === "exit" || a.kind === "do") {
|
|
3239
|
+
return `${a.kind} / ${a.action ?? ""}`;
|
|
3240
|
+
}
|
|
3241
|
+
const parts = [];
|
|
3242
|
+
if (a.trigger) parts.push(a.trigger);
|
|
3243
|
+
if (a.guard) parts.push(`[${a.guard}]`);
|
|
3244
|
+
let s = parts.join(" ");
|
|
3245
|
+
if (a.action) s = s ? `${s} / ${a.action}` : `/ ${a.action}`;
|
|
3246
|
+
return s;
|
|
3247
|
+
}
|
|
3248
|
+
function wrapNoteText(text2, charsPerLine = 28) {
|
|
3249
|
+
const out = [];
|
|
3250
|
+
for (const para of text2.split(/\n/)) {
|
|
3251
|
+
const words = para.split(/\s+/);
|
|
3252
|
+
let cur = "";
|
|
3253
|
+
for (const w of words) {
|
|
3254
|
+
if (!cur) cur = w;
|
|
3255
|
+
else if (cur.length + w.length + 1 <= charsPerLine) cur += ` ${w}`;
|
|
3256
|
+
else {
|
|
3257
|
+
out.push(cur);
|
|
3258
|
+
cur = w;
|
|
3259
|
+
}
|
|
3260
|
+
}
|
|
3261
|
+
if (cur) out.push(cur);
|
|
3262
|
+
if (para === "") out.push("");
|
|
3263
|
+
}
|
|
3264
|
+
return out.length ? out : [""];
|
|
3265
|
+
}
|
|
3266
|
+
function selfLoopPath(cx, cy, w, h) {
|
|
3267
|
+
const startX = cx + w / 2;
|
|
3268
|
+
const startY = cy - h * 0.15;
|
|
3269
|
+
const endX = cx + w * 0.15;
|
|
3270
|
+
const endY = cy - h / 2;
|
|
3271
|
+
const c1x = startX + 28;
|
|
3272
|
+
const c1y = startY - 12;
|
|
3273
|
+
const c2x = endX + 28;
|
|
3274
|
+
const c2y = endY - 28;
|
|
3275
|
+
const path2 = `M ${startX} ${startY} C ${c1x} ${c1y}, ${c2x} ${c2y}, ${endX} ${endY}`;
|
|
3276
|
+
return { path: path2, labelX: startX + 28, labelY: startY - 18 };
|
|
3277
|
+
}
|
|
3278
|
+
function layoutStateDiagram(ast) {
|
|
3279
|
+
const { ast: fcAst, pseudoSizes } = convertToFlowchart(ast);
|
|
3280
|
+
const selfLoops = [];
|
|
3281
|
+
fcAst.edges = fcAst.edges.filter((e) => {
|
|
3282
|
+
if (e.from === e.to) {
|
|
3283
|
+
const t = ast.transitions.find((tr) => tr.id === e.id);
|
|
3284
|
+
if (t) selfLoops.push(t);
|
|
3285
|
+
return false;
|
|
3286
|
+
}
|
|
3287
|
+
return true;
|
|
3288
|
+
});
|
|
3289
|
+
const fcResult = chunk3FKS4KQK_cjs.layoutFlowchart(fcAst);
|
|
3290
|
+
const stateById = /* @__PURE__ */ new Map();
|
|
3291
|
+
const collectStates = (s) => {
|
|
3292
|
+
stateById.set(s.id, s);
|
|
3293
|
+
for (const c of s.children) collectStates(c);
|
|
3294
|
+
};
|
|
3295
|
+
for (const s of ast.states) collectStates(s);
|
|
3296
|
+
const stateNodes = [];
|
|
3297
|
+
for (const fcNode of fcResult.nodes) {
|
|
3298
|
+
if (fcNode.isDummy) continue;
|
|
3299
|
+
const s = stateById.get(fcNode.node.id);
|
|
3300
|
+
if (!s) continue;
|
|
3301
|
+
if (s.kind === "composite") continue;
|
|
3302
|
+
const cx = fcNode.x + fcNode.width / 2;
|
|
3303
|
+
const cy = fcNode.y + fcNode.height / 2;
|
|
3304
|
+
let w = fcNode.width;
|
|
3305
|
+
let h = fcNode.height;
|
|
3306
|
+
if (s.kind === "pseudo" && s.pseudoKind) {
|
|
3307
|
+
const ps = pseudoSizes.get(s.id);
|
|
3308
|
+
if (ps) {
|
|
3309
|
+
if ((s.pseudoKind === "fork" || s.pseudoKind === "join") && ast.direction === "LR") {
|
|
3310
|
+
w = 8;
|
|
3311
|
+
h = 100;
|
|
3312
|
+
} else {
|
|
3313
|
+
w = ps.w;
|
|
3314
|
+
h = ps.h;
|
|
3315
|
+
}
|
|
3316
|
+
}
|
|
3317
|
+
}
|
|
3318
|
+
stateNodes.push({
|
|
3319
|
+
id: s.id,
|
|
3320
|
+
x: cx - w / 2,
|
|
3321
|
+
y: cy - h / 2,
|
|
3322
|
+
width: w,
|
|
3323
|
+
height: h,
|
|
3324
|
+
cx,
|
|
3325
|
+
cy,
|
|
3326
|
+
layer: fcNode.layer,
|
|
3327
|
+
node: s,
|
|
3328
|
+
parent: s.parent
|
|
3329
|
+
});
|
|
3330
|
+
}
|
|
3331
|
+
const clusters = fcResult.clusters.map((c) => {
|
|
3332
|
+
const s = stateById.get(c.subgraph.id);
|
|
3333
|
+
if (!s) {
|
|
3334
|
+
return {
|
|
3335
|
+
id: c.subgraph.id,
|
|
3336
|
+
state: { id: c.subgraph.id, label: c.subgraph.label, kind: "composite", activities: [], children: [] },
|
|
3337
|
+
x: c.x,
|
|
3338
|
+
y: c.y,
|
|
3339
|
+
width: c.width,
|
|
3340
|
+
height: c.height
|
|
3341
|
+
};
|
|
3342
|
+
}
|
|
3343
|
+
return {
|
|
3344
|
+
id: c.subgraph.id,
|
|
3345
|
+
state: s,
|
|
3346
|
+
x: c.x,
|
|
3347
|
+
y: c.y,
|
|
3348
|
+
width: c.width,
|
|
3349
|
+
height: c.height
|
|
3350
|
+
};
|
|
3351
|
+
});
|
|
3352
|
+
const stateById2 = new Map(stateNodes.map((n) => [n.id, n]));
|
|
3353
|
+
const stateEdges = [];
|
|
3354
|
+
for (const fcEdge of fcResult.edges) {
|
|
3355
|
+
const t = ast.transitions.find((tr) => tr.id === fcEdge.edge.id);
|
|
3356
|
+
if (!t) continue;
|
|
3357
|
+
let path2 = fcEdge.path;
|
|
3358
|
+
const sourceNode = stateById2.get(fcEdge.edge.from);
|
|
3359
|
+
const targetNode = stateById2.get(fcEdge.edge.to);
|
|
3360
|
+
if (sourceNode && sourceNode.node.kind === "pseudo") {
|
|
3361
|
+
path2 = trimPathStart(path2, sourceNode.cx, sourceNode.cy, symbolRadius(sourceNode));
|
|
3362
|
+
}
|
|
3363
|
+
if (targetNode && targetNode.node.kind === "pseudo") {
|
|
3364
|
+
path2 = trimPathEnd(path2, targetNode.cx, targetNode.cy, symbolRadius(targetNode));
|
|
3365
|
+
}
|
|
3366
|
+
stateEdges.push({
|
|
3367
|
+
id: t.id,
|
|
3368
|
+
from: t.from,
|
|
3369
|
+
to: t.to,
|
|
3370
|
+
path: path2,
|
|
3371
|
+
label: buildLabel(t),
|
|
3372
|
+
labelX: fcEdge.labelAnchor?.x ?? 0,
|
|
3373
|
+
labelY: fcEdge.labelAnchor?.y ?? 0,
|
|
3374
|
+
labelAnchor: fcEdge.labelAnchor?.textAnchor ?? "middle"
|
|
3375
|
+
});
|
|
3376
|
+
}
|
|
3377
|
+
for (const sl of selfLoops) {
|
|
3378
|
+
const host = stateById2.get(sl.from);
|
|
3379
|
+
if (!host) continue;
|
|
3380
|
+
const { path: path2, labelX, labelY } = selfLoopPath(host.cx, host.cy, host.width, host.height);
|
|
3381
|
+
stateEdges.push({
|
|
3382
|
+
id: sl.id,
|
|
3383
|
+
from: sl.from,
|
|
3384
|
+
to: sl.to,
|
|
3385
|
+
path: path2,
|
|
3386
|
+
label: buildLabel(sl),
|
|
3387
|
+
labelX,
|
|
3388
|
+
labelY,
|
|
3389
|
+
labelAnchor: "start",
|
|
3390
|
+
selfLoop: true
|
|
3391
|
+
});
|
|
3392
|
+
}
|
|
3393
|
+
const notes = [];
|
|
3394
|
+
for (const note of ast.notes) {
|
|
3395
|
+
const target = stateById2.get(note.target);
|
|
3396
|
+
if (!target) continue;
|
|
3397
|
+
const lines = wrapNoteText(note.text);
|
|
3398
|
+
const w = NOTE_W;
|
|
3399
|
+
const h = lines.length * NOTE_LINE_H + 14;
|
|
3400
|
+
let x;
|
|
3401
|
+
let y;
|
|
3402
|
+
let leaderX1;
|
|
3403
|
+
let leaderX2;
|
|
3404
|
+
if (note.side === "left") {
|
|
3405
|
+
x = target.x - w - 24;
|
|
3406
|
+
y = target.cy - h / 2;
|
|
3407
|
+
leaderX1 = target.x;
|
|
3408
|
+
leaderX2 = x + w;
|
|
3409
|
+
} else {
|
|
3410
|
+
x = target.x + target.width + 24;
|
|
3411
|
+
y = target.cy - h / 2;
|
|
3412
|
+
leaderX1 = target.x + target.width;
|
|
3413
|
+
leaderX2 = x;
|
|
3414
|
+
}
|
|
3415
|
+
notes.push({
|
|
3416
|
+
note,
|
|
3417
|
+
x,
|
|
3418
|
+
y,
|
|
3419
|
+
width: w,
|
|
3420
|
+
height: h,
|
|
3421
|
+
lines,
|
|
3422
|
+
leader: { x1: leaderX1, y1: target.cy, x2: leaderX2, y2: y + h / 2 }
|
|
3423
|
+
});
|
|
3424
|
+
}
|
|
3425
|
+
let maxX = fcResult.width;
|
|
3426
|
+
let maxY = fcResult.height;
|
|
3427
|
+
let minX = 0;
|
|
3428
|
+
for (const n of notes) {
|
|
3429
|
+
maxX = Math.max(maxX, n.x + n.width + 8);
|
|
3430
|
+
maxY = Math.max(maxY, n.y + n.height + 8);
|
|
3431
|
+
minX = Math.min(minX, n.x - 8);
|
|
3432
|
+
}
|
|
3433
|
+
if (minX < 0) {
|
|
3434
|
+
const dx = -minX;
|
|
3435
|
+
for (const n of stateNodes) {
|
|
3436
|
+
n.x += dx;
|
|
3437
|
+
n.cx += dx;
|
|
3438
|
+
}
|
|
3439
|
+
for (const c of clusters) {
|
|
3440
|
+
c.x += dx;
|
|
3441
|
+
}
|
|
3442
|
+
for (const e of stateEdges) {
|
|
3443
|
+
e.path = shiftPathX(e.path, dx);
|
|
3444
|
+
e.labelX += dx;
|
|
3445
|
+
}
|
|
3446
|
+
for (const n of notes) {
|
|
3447
|
+
n.x += dx;
|
|
3448
|
+
n.leader.x1 += dx;
|
|
3449
|
+
n.leader.x2 += dx;
|
|
3450
|
+
}
|
|
3451
|
+
maxX += dx;
|
|
3452
|
+
}
|
|
3453
|
+
for (const e of stateEdges) {
|
|
3454
|
+
if (!e.selfLoop) continue;
|
|
3455
|
+
maxX = Math.max(maxX, e.labelX + 60);
|
|
3456
|
+
maxY = Math.max(maxY, e.labelY + 60);
|
|
3457
|
+
}
|
|
3458
|
+
const titleOffset = ast.title ? 28 : 0;
|
|
3459
|
+
if (titleOffset) {
|
|
3460
|
+
for (const n of stateNodes) {
|
|
3461
|
+
n.y += titleOffset;
|
|
3462
|
+
n.cy += titleOffset;
|
|
3463
|
+
}
|
|
3464
|
+
for (const c of clusters) {
|
|
3465
|
+
c.y += titleOffset;
|
|
3466
|
+
}
|
|
3467
|
+
for (const e of stateEdges) {
|
|
3468
|
+
e.path = shiftPathY(e.path, titleOffset);
|
|
3469
|
+
e.labelY += titleOffset;
|
|
3470
|
+
}
|
|
3471
|
+
for (const n of notes) {
|
|
3472
|
+
n.y += titleOffset;
|
|
3473
|
+
n.leader.y1 += titleOffset;
|
|
3474
|
+
n.leader.y2 += titleOffset;
|
|
3475
|
+
}
|
|
3476
|
+
maxY += titleOffset;
|
|
3477
|
+
}
|
|
3478
|
+
return {
|
|
3479
|
+
width: maxX,
|
|
3480
|
+
height: maxY,
|
|
3481
|
+
nodes: stateNodes,
|
|
3482
|
+
edges: stateEdges,
|
|
3483
|
+
clusters,
|
|
3484
|
+
notes,
|
|
3485
|
+
title: ast.title,
|
|
3486
|
+
direction: ast.direction
|
|
3487
|
+
};
|
|
3488
|
+
}
|
|
3489
|
+
function symbolRadius(node) {
|
|
3490
|
+
const k = node.node.pseudoKind;
|
|
3491
|
+
switch (k) {
|
|
3492
|
+
case "initial":
|
|
3493
|
+
return 8;
|
|
3494
|
+
case "final":
|
|
3495
|
+
return 11;
|
|
3496
|
+
case "choice":
|
|
3497
|
+
return 14;
|
|
3498
|
+
case "junction":
|
|
3499
|
+
return 6;
|
|
3500
|
+
case "history":
|
|
3501
|
+
return 12;
|
|
3502
|
+
case "dhistory":
|
|
3503
|
+
return 13;
|
|
3504
|
+
case "terminate":
|
|
3505
|
+
return 8;
|
|
3506
|
+
case "entry_point":
|
|
3507
|
+
case "exit_point":
|
|
3508
|
+
return 7;
|
|
3509
|
+
case "fork":
|
|
3510
|
+
case "join":
|
|
3511
|
+
return Math.min(node.width, node.height) / 2;
|
|
3512
|
+
default:
|
|
3513
|
+
return Math.min(node.width, node.height) / 2;
|
|
3514
|
+
}
|
|
3515
|
+
}
|
|
3516
|
+
function parsePathPoints(d) {
|
|
3517
|
+
if (/[CSQTA]/.test(d)) return null;
|
|
3518
|
+
const tokens = d.match(/[ML]\s+(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?)/g) ?? [];
|
|
3519
|
+
const out = [];
|
|
3520
|
+
for (const tok of tokens) {
|
|
3521
|
+
const m = tok.match(/[ML]\s+(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?)/);
|
|
3522
|
+
if (!m) continue;
|
|
3523
|
+
out.push({ x: parseFloat(m[1]), y: parseFloat(m[2]) });
|
|
3524
|
+
}
|
|
3525
|
+
return out;
|
|
3526
|
+
}
|
|
3527
|
+
function pointsToPath(pts) {
|
|
3528
|
+
if (pts.length === 0) return "";
|
|
3529
|
+
const head = `M ${pts[0].x} ${pts[0].y}`;
|
|
3530
|
+
const rest = pts.slice(1).map((p) => `L ${p.x} ${p.y}`).join(" ");
|
|
3531
|
+
return rest ? `${head} ${rest}` : head;
|
|
3532
|
+
}
|
|
3533
|
+
function trimPathStart(d, cx, cy, r) {
|
|
3534
|
+
const pts = parsePathPoints(d);
|
|
3535
|
+
if (!pts || pts.length < 2) return d;
|
|
3536
|
+
const p0 = pts[0];
|
|
3537
|
+
const p1 = pts[1];
|
|
3538
|
+
const newP0 = projectOnPerimeter(p0, p1, cx, cy, r);
|
|
3539
|
+
pts[0] = newP0;
|
|
3540
|
+
return pointsToPath(pts);
|
|
3541
|
+
}
|
|
3542
|
+
function trimPathEnd(d, cx, cy, r) {
|
|
3543
|
+
const pts = parsePathPoints(d);
|
|
3544
|
+
if (!pts || pts.length < 2) return d;
|
|
3545
|
+
const last = pts[pts.length - 1];
|
|
3546
|
+
const prev = pts[pts.length - 2];
|
|
3547
|
+
const newLast = projectOnPerimeter(last, prev, cx, cy, r);
|
|
3548
|
+
pts[pts.length - 1] = newLast;
|
|
3549
|
+
return pointsToPath(pts);
|
|
3550
|
+
}
|
|
3551
|
+
function projectOnPerimeter(endpoint, neighbor, cx, cy, r) {
|
|
3552
|
+
const dx = endpoint.x - neighbor.x;
|
|
3553
|
+
const dy = endpoint.y - neighbor.y;
|
|
3554
|
+
if (Math.abs(dx) > Math.abs(dy)) {
|
|
3555
|
+
const sign2 = dx >= 0 ? 1 : -1;
|
|
3556
|
+
return { x: cx - sign2 * r, y: cy };
|
|
3557
|
+
}
|
|
3558
|
+
const sign = dy >= 0 ? 1 : -1;
|
|
3559
|
+
return { x: cx, y: cy - sign * r };
|
|
3560
|
+
}
|
|
3561
|
+
function shiftPathX(d, dx) {
|
|
3562
|
+
return d.replace(/([MLCQ])\s*((?:-?\d+(?:\.\d+)?\s+){1,5}-?\d+(?:\.\d+)?)/g, (_, cmd, args) => {
|
|
3563
|
+
const nums = args.trim().split(/\s+/).map(Number);
|
|
3564
|
+
const out = [];
|
|
3565
|
+
for (let i = 0; i < nums.length; i++) {
|
|
3566
|
+
out.push(i % 2 === 0 ? nums[i] + dx : nums[i]);
|
|
3567
|
+
}
|
|
3568
|
+
return `${cmd} ${out.join(" ")}`;
|
|
3569
|
+
});
|
|
3570
|
+
}
|
|
3571
|
+
function shiftPathY(d, dy) {
|
|
3572
|
+
return d.replace(/([MLCQ])\s*((?:-?\d+(?:\.\d+)?\s+){1,5}-?\d+(?:\.\d+)?)/g, (_, cmd, args) => {
|
|
3573
|
+
const nums = args.trim().split(/\s+/).map(Number);
|
|
3574
|
+
const out = [];
|
|
3575
|
+
for (let i = 0; i < nums.length; i++) {
|
|
3576
|
+
out.push(i % 2 === 1 ? nums[i] + dy : nums[i]);
|
|
3577
|
+
}
|
|
3578
|
+
return `${cmd} ${out.join(" ")}`;
|
|
3579
|
+
});
|
|
3580
|
+
}
|
|
3581
|
+
|
|
3582
|
+
// src/diagrams/state/renderer.ts
|
|
3583
|
+
var ARROW_MARKER_ID = "lt-state-arrow";
|
|
3584
|
+
var STYLE = `
|
|
3585
|
+
.lt-state-body { fill: #ffffff; stroke: #2a2a2a; stroke-width: 1.6; }
|
|
3586
|
+
.lt-state-name { font: 600 12px system-ui, sans-serif; fill: #1a1a1a; }
|
|
3587
|
+
.lt-state-div { stroke: #2a2a2a; stroke-width: 1; }
|
|
3588
|
+
.lt-state-activity { font: 11px ui-monospace, monospace; fill: #444; }
|
|
3589
|
+
|
|
3590
|
+
.lt-composite-body { fill: #fafafa; stroke: #2a2a2a; stroke-width: 1.6; }
|
|
3591
|
+
.lt-composite-title { font: 600 12px system-ui, sans-serif; fill: #1a1a1a; }
|
|
3592
|
+
.lt-composite-titlebar { fill: #f0f0f0; stroke: #2a2a2a; stroke-width: 1; }
|
|
3593
|
+
.lt-region-div { stroke: #888; stroke-width: 1; stroke-dasharray: 6 4; }
|
|
3594
|
+
|
|
3595
|
+
.lt-ps-initial { fill: #1a1a1a; }
|
|
3596
|
+
.lt-ps-final-outer { fill: #ffffff; stroke: #1a1a1a; stroke-width: 1.6; }
|
|
3597
|
+
.lt-ps-final-inner { fill: #1a1a1a; }
|
|
3598
|
+
.lt-ps-choice { fill: #ffffff; stroke: #1a1a1a; stroke-width: 1.6; }
|
|
3599
|
+
.lt-ps-junction { fill: #1a1a1a; }
|
|
3600
|
+
.lt-ps-bar { fill: #1a1a1a; }
|
|
3601
|
+
.lt-ps-history-body { fill: #ffffff; stroke: #1a1a1a; stroke-width: 1.6; }
|
|
3602
|
+
.lt-ps-history-text { font: 600 11px serif; fill: #1a1a1a; }
|
|
3603
|
+
.lt-ps-terminate { stroke: #1a1a1a; stroke-width: 2; }
|
|
3604
|
+
.lt-ps-entrypoint { fill: #ffffff; stroke: #1a1a1a; stroke-width: 1.6; }
|
|
3605
|
+
.lt-ps-exitpoint { fill: #ffffff; stroke: #1a1a1a; stroke-width: 1.6; }
|
|
3606
|
+
|
|
3607
|
+
.lt-transition { stroke: #2a2a2a; stroke-width: 1.4; fill: none; }
|
|
3608
|
+
.lt-transition-label { font: 11px system-ui, sans-serif; fill: #1a1a1a; }
|
|
3609
|
+
.lt-transition-label-bg { fill: #ffffff; opacity: 0.92; }
|
|
3610
|
+
|
|
3611
|
+
.lt-note-body { fill: #fff8c5; stroke: #b79400; stroke-width: 1; }
|
|
3612
|
+
.lt-note-text { font: 11px system-ui, sans-serif; fill: #2a2a2a; }
|
|
3613
|
+
.lt-note-leader { stroke: #b79400; stroke-width: 1; stroke-dasharray: 3 3; fill: none; }
|
|
3614
|
+
|
|
3615
|
+
.lt-title { font: 600 14px system-ui, sans-serif; fill: #1a1a1a; }
|
|
3616
|
+
`;
|
|
3617
|
+
function renderArrowMarker() {
|
|
3618
|
+
return chunkHDKDQAEQ_cjs.el(
|
|
3619
|
+
"marker",
|
|
3620
|
+
{
|
|
3621
|
+
id: ARROW_MARKER_ID,
|
|
3622
|
+
markerWidth: 10,
|
|
3623
|
+
markerHeight: 10,
|
|
3624
|
+
refX: 9,
|
|
3625
|
+
refY: 3,
|
|
3626
|
+
orient: "auto",
|
|
3627
|
+
markerUnits: "strokeWidth"
|
|
3628
|
+
},
|
|
3629
|
+
[chunkHDKDQAEQ_cjs.polygon({ points: "0,0 10,3 0,6", fill: "#2a2a2a" })]
|
|
3630
|
+
);
|
|
3631
|
+
}
|
|
3632
|
+
function activityText2(a) {
|
|
3633
|
+
if (a.kind === "entry" || a.kind === "exit" || a.kind === "do") {
|
|
3634
|
+
return `${a.kind} / ${a.action ?? ""}`;
|
|
3635
|
+
}
|
|
3636
|
+
const parts = [];
|
|
3637
|
+
if (a.trigger) parts.push(a.trigger);
|
|
3638
|
+
if (a.guard) parts.push(`[${a.guard}]`);
|
|
3639
|
+
let s = parts.join(" ");
|
|
3640
|
+
if (a.action) s = s ? `${s} / ${a.action}` : `/ ${a.action}`;
|
|
3641
|
+
return s;
|
|
3642
|
+
}
|
|
3643
|
+
function renderSimple(node) {
|
|
3644
|
+
const { x, y, width, height } = node;
|
|
3645
|
+
const children = [
|
|
3646
|
+
chunkHDKDQAEQ_cjs.rect({ x, y, width, height, rx: 8, ry: 8, class: "lt-state-body" })
|
|
3647
|
+
];
|
|
3648
|
+
const label = node.node.label || node.id;
|
|
3649
|
+
if (node.node.activities.length === 0) {
|
|
3650
|
+
children.push(
|
|
3651
|
+
chunkHDKDQAEQ_cjs.text(
|
|
3652
|
+
{ x: x + width / 2, y: y + height / 2 + 4, "text-anchor": "middle", class: "lt-state-name" },
|
|
3653
|
+
label
|
|
3654
|
+
)
|
|
3655
|
+
);
|
|
3656
|
+
} else {
|
|
3657
|
+
children.push(
|
|
3658
|
+
chunkHDKDQAEQ_cjs.text(
|
|
3659
|
+
{ x: x + width / 2, y: y + 16, "text-anchor": "middle", class: "lt-state-name" },
|
|
3660
|
+
label
|
|
3661
|
+
)
|
|
3662
|
+
);
|
|
3663
|
+
children.push(
|
|
3664
|
+
chunkHDKDQAEQ_cjs.line({ x1: x, y1: y + 22, x2: x + width, y2: y + 22, class: "lt-state-div" })
|
|
3665
|
+
);
|
|
3666
|
+
let cy = y + 36;
|
|
3667
|
+
for (const a of node.node.activities) {
|
|
3668
|
+
children.push(chunkHDKDQAEQ_cjs.text({ x: x + 8, y: cy, class: "lt-state-activity" }, activityText2(a)));
|
|
3669
|
+
cy += 14;
|
|
3670
|
+
}
|
|
3671
|
+
}
|
|
3672
|
+
return chunkHDKDQAEQ_cjs.group({ class: "lt-state lt-simple", "data-id": node.id }, children);
|
|
3673
|
+
}
|
|
3674
|
+
function renderComposite(c) {
|
|
3675
|
+
const { x, y, width, height } = c;
|
|
3676
|
+
const titleBarH = 22;
|
|
3677
|
+
const acts = c.state.activities;
|
|
3678
|
+
const actsH = acts.length ? acts.length * 14 + 6 : 0;
|
|
3679
|
+
const parts = [
|
|
3680
|
+
chunkHDKDQAEQ_cjs.rect({ x, y, width, height, rx: 10, ry: 10, class: "lt-composite-body" }),
|
|
3681
|
+
// Title bar background — only the top strip
|
|
3682
|
+
chunkHDKDQAEQ_cjs.path({
|
|
3683
|
+
d: `M ${x + 1} ${y + titleBarH} L ${x + width - 1} ${y + titleBarH}`,
|
|
3684
|
+
class: "lt-state-div"
|
|
3685
|
+
}),
|
|
3686
|
+
chunkHDKDQAEQ_cjs.text(
|
|
3687
|
+
{ x: x + 12, y: y + 16, class: "lt-composite-title" },
|
|
3688
|
+
c.state.label || c.state.id
|
|
3689
|
+
)
|
|
3690
|
+
];
|
|
3691
|
+
if (acts.length) {
|
|
3692
|
+
let cy = y + titleBarH + 14;
|
|
3693
|
+
for (const a of acts) {
|
|
3694
|
+
parts.push(chunkHDKDQAEQ_cjs.text({ x: x + 12, y: cy, class: "lt-state-activity" }, activityText2(a)));
|
|
3695
|
+
cy += 14;
|
|
3696
|
+
}
|
|
3697
|
+
parts.push(
|
|
3698
|
+
chunkHDKDQAEQ_cjs.path({
|
|
3699
|
+
d: `M ${x + 1} ${y + titleBarH + actsH} L ${x + width - 1} ${y + titleBarH + actsH}`,
|
|
3700
|
+
class: "lt-state-div"
|
|
3701
|
+
})
|
|
3702
|
+
);
|
|
3703
|
+
}
|
|
3704
|
+
if (c.regionDividers) {
|
|
3705
|
+
for (const yy of c.regionDividers) {
|
|
3706
|
+
parts.push(
|
|
3707
|
+
chunkHDKDQAEQ_cjs.line({ x1: x + 1, y1: yy, x2: x + width - 1, y2: yy, class: "lt-region-div" })
|
|
3708
|
+
);
|
|
3709
|
+
}
|
|
3710
|
+
}
|
|
3711
|
+
return chunkHDKDQAEQ_cjs.group(
|
|
3712
|
+
{ class: "lt-state lt-composite", "data-id": c.id },
|
|
3713
|
+
parts
|
|
3714
|
+
);
|
|
3715
|
+
}
|
|
3716
|
+
function renderPseudo(node) {
|
|
3717
|
+
const cx = node.cx;
|
|
3718
|
+
const cy = node.cy;
|
|
3719
|
+
const k = node.node.pseudoKind;
|
|
3720
|
+
switch (k) {
|
|
3721
|
+
case "initial":
|
|
3722
|
+
return chunkHDKDQAEQ_cjs.group(
|
|
3723
|
+
{ class: "lt-state lt-pseudo", "data-id": node.id, "data-kind": "initial" },
|
|
3724
|
+
[chunkHDKDQAEQ_cjs.circle({ cx, cy, r: 8, class: "lt-ps-initial" })]
|
|
3725
|
+
);
|
|
3726
|
+
case "final":
|
|
3727
|
+
return chunkHDKDQAEQ_cjs.group(
|
|
3728
|
+
{ class: "lt-state lt-pseudo", "data-id": node.id, "data-kind": "final" },
|
|
3729
|
+
[
|
|
3730
|
+
chunkHDKDQAEQ_cjs.circle({ cx, cy, r: 11, class: "lt-ps-final-outer" }),
|
|
3731
|
+
chunkHDKDQAEQ_cjs.circle({ cx, cy, r: 6, class: "lt-ps-final-inner" })
|
|
3732
|
+
]
|
|
3733
|
+
);
|
|
3734
|
+
case "choice": {
|
|
3735
|
+
const r = 14;
|
|
3736
|
+
return chunkHDKDQAEQ_cjs.group(
|
|
3737
|
+
{ class: "lt-state lt-pseudo", "data-id": node.id, "data-kind": "choice" },
|
|
3738
|
+
[
|
|
3739
|
+
chunkHDKDQAEQ_cjs.polygon({
|
|
3740
|
+
points: `${cx},${cy - r} ${cx + r},${cy} ${cx},${cy + r} ${cx - r},${cy}`,
|
|
3741
|
+
class: "lt-ps-choice"
|
|
3742
|
+
})
|
|
3743
|
+
]
|
|
3744
|
+
);
|
|
3745
|
+
}
|
|
3746
|
+
case "junction":
|
|
3747
|
+
return chunkHDKDQAEQ_cjs.group(
|
|
3748
|
+
{ class: "lt-state lt-pseudo", "data-id": node.id, "data-kind": "junction" },
|
|
3749
|
+
[chunkHDKDQAEQ_cjs.circle({ cx, cy, r: 6, class: "lt-ps-junction" })]
|
|
3750
|
+
);
|
|
3751
|
+
case "fork":
|
|
3752
|
+
case "join":
|
|
3753
|
+
return chunkHDKDQAEQ_cjs.group(
|
|
3754
|
+
{ class: "lt-state lt-pseudo", "data-id": node.id, "data-kind": k },
|
|
3755
|
+
[chunkHDKDQAEQ_cjs.rect({ x: node.x, y: node.y, width: node.width, height: node.height, rx: 2, ry: 2, class: "lt-ps-bar" })]
|
|
3756
|
+
);
|
|
3757
|
+
case "history":
|
|
3758
|
+
return chunkHDKDQAEQ_cjs.group(
|
|
3759
|
+
{ class: "lt-state lt-pseudo", "data-id": node.id, "data-kind": "history" },
|
|
3760
|
+
[
|
|
3761
|
+
chunkHDKDQAEQ_cjs.circle({ cx, cy, r: 12, class: "lt-ps-history-body" }),
|
|
3762
|
+
chunkHDKDQAEQ_cjs.text({ x: cx, y: cy + 4, "text-anchor": "middle", class: "lt-ps-history-text" }, "H")
|
|
3763
|
+
]
|
|
3764
|
+
);
|
|
3765
|
+
case "dhistory":
|
|
3766
|
+
return chunkHDKDQAEQ_cjs.group(
|
|
3767
|
+
{ class: "lt-state lt-pseudo", "data-id": node.id, "data-kind": "dhistory" },
|
|
3768
|
+
[
|
|
3769
|
+
chunkHDKDQAEQ_cjs.circle({ cx, cy, r: 13, class: "lt-ps-history-body" }),
|
|
3770
|
+
chunkHDKDQAEQ_cjs.text({ x: cx, y: cy + 4, "text-anchor": "middle", class: "lt-ps-history-text" }, "H*")
|
|
3771
|
+
]
|
|
3772
|
+
);
|
|
3773
|
+
case "terminate":
|
|
3774
|
+
return chunkHDKDQAEQ_cjs.group(
|
|
3775
|
+
{ class: "lt-state lt-pseudo", "data-id": node.id, "data-kind": "terminate" },
|
|
3776
|
+
[
|
|
3777
|
+
chunkHDKDQAEQ_cjs.line({ x1: cx - 8, y1: cy - 8, x2: cx + 8, y2: cy + 8, class: "lt-ps-terminate" }),
|
|
3778
|
+
chunkHDKDQAEQ_cjs.line({ x1: cx + 8, y1: cy - 8, x2: cx - 8, y2: cy + 8, class: "lt-ps-terminate" })
|
|
3779
|
+
]
|
|
3780
|
+
);
|
|
3781
|
+
case "entry_point":
|
|
3782
|
+
return chunkHDKDQAEQ_cjs.group(
|
|
3783
|
+
{ class: "lt-state lt-pseudo", "data-id": node.id, "data-kind": "entry_point" },
|
|
3784
|
+
[chunkHDKDQAEQ_cjs.circle({ cx, cy, r: 7, class: "lt-ps-entrypoint" })]
|
|
3785
|
+
);
|
|
3786
|
+
case "exit_point":
|
|
3787
|
+
return chunkHDKDQAEQ_cjs.group(
|
|
3788
|
+
{ class: "lt-state lt-pseudo", "data-id": node.id, "data-kind": "exit_point" },
|
|
3789
|
+
[
|
|
3790
|
+
chunkHDKDQAEQ_cjs.circle({ cx, cy, r: 7, class: "lt-ps-exitpoint" }),
|
|
3791
|
+
chunkHDKDQAEQ_cjs.line({ x1: cx - 4, y1: cy - 4, x2: cx + 4, y2: cy + 4, class: "lt-ps-terminate" }),
|
|
3792
|
+
chunkHDKDQAEQ_cjs.line({ x1: cx + 4, y1: cy - 4, x2: cx - 4, y2: cy + 4, class: "lt-ps-terminate" })
|
|
3793
|
+
]
|
|
3794
|
+
);
|
|
3795
|
+
default:
|
|
3796
|
+
return "";
|
|
3797
|
+
}
|
|
3798
|
+
}
|
|
3799
|
+
function renderNode(node) {
|
|
3800
|
+
if (node.node.kind === "pseudo") return renderPseudo(node);
|
|
3801
|
+
return renderSimple(node);
|
|
3802
|
+
}
|
|
3803
|
+
function renderEdge(edge) {
|
|
3804
|
+
const parts = [
|
|
3805
|
+
chunkHDKDQAEQ_cjs.path({
|
|
3806
|
+
d: edge.path,
|
|
3807
|
+
class: "lt-transition",
|
|
3808
|
+
"marker-end": `url(#${ARROW_MARKER_ID})`,
|
|
3809
|
+
"data-from": edge.from,
|
|
3810
|
+
"data-to": edge.to
|
|
3811
|
+
})
|
|
3812
|
+
];
|
|
3813
|
+
if (edge.label) {
|
|
3814
|
+
const w = Math.max(20, edge.label.length * 6.4 + 8);
|
|
3815
|
+
const anchor = edge.labelAnchor ?? "middle";
|
|
3816
|
+
const dx = anchor === "start" ? 0 : anchor === "end" ? -w : -w / 2;
|
|
3817
|
+
parts.push(
|
|
3818
|
+
chunkHDKDQAEQ_cjs.rect({
|
|
3819
|
+
x: edge.labelX + dx,
|
|
3820
|
+
y: edge.labelY - 10,
|
|
3821
|
+
width: w,
|
|
3822
|
+
height: 14,
|
|
3823
|
+
rx: 2,
|
|
3824
|
+
ry: 2,
|
|
3825
|
+
class: "lt-transition-label-bg"
|
|
3826
|
+
})
|
|
3827
|
+
);
|
|
3828
|
+
parts.push(
|
|
3829
|
+
chunkHDKDQAEQ_cjs.text(
|
|
3830
|
+
{
|
|
3831
|
+
x: edge.labelX,
|
|
3832
|
+
y: edge.labelY,
|
|
3833
|
+
"text-anchor": anchor,
|
|
3834
|
+
class: "lt-transition-label"
|
|
3835
|
+
},
|
|
3836
|
+
edge.label
|
|
3837
|
+
)
|
|
3838
|
+
);
|
|
3839
|
+
}
|
|
3840
|
+
return chunkHDKDQAEQ_cjs.group({ class: "lt-edge", "data-edge-id": edge.id }, parts);
|
|
3841
|
+
}
|
|
3842
|
+
function renderNote(n) {
|
|
3843
|
+
const parts = [
|
|
3844
|
+
chunkHDKDQAEQ_cjs.line({
|
|
3845
|
+
x1: n.leader.x1,
|
|
3846
|
+
y1: n.leader.y1,
|
|
3847
|
+
x2: n.leader.x2,
|
|
3848
|
+
y2: n.leader.y2,
|
|
3849
|
+
class: "lt-note-leader"
|
|
3850
|
+
}),
|
|
3851
|
+
chunkHDKDQAEQ_cjs.rect({ x: n.x, y: n.y, width: n.width, height: n.height, rx: 4, ry: 4, class: "lt-note-body" })
|
|
3852
|
+
];
|
|
3853
|
+
let yy = n.y + 14;
|
|
3854
|
+
for (const ln of n.lines) {
|
|
3855
|
+
parts.push(chunkHDKDQAEQ_cjs.text({ x: n.x + 8, y: yy, class: "lt-note-text" }, ln));
|
|
3856
|
+
yy += 14;
|
|
3857
|
+
}
|
|
3858
|
+
return chunkHDKDQAEQ_cjs.group({ class: "lt-note", "data-target": n.note.target }, parts);
|
|
3859
|
+
}
|
|
3860
|
+
function renderStateDiagram(ast, _config) {
|
|
3861
|
+
const layout = layoutStateDiagram(ast);
|
|
3862
|
+
return renderLayout(layout);
|
|
3863
|
+
}
|
|
3864
|
+
function renderLayout(layout) {
|
|
3865
|
+
const titleNode = layout.title ? chunkHDKDQAEQ_cjs.text({ x: 16, y: 22, class: "lt-title" }, layout.title) : "";
|
|
3866
|
+
return chunkHDKDQAEQ_cjs.svgRoot(
|
|
3867
|
+
{
|
|
3868
|
+
width: layout.width,
|
|
3869
|
+
height: layout.height,
|
|
3870
|
+
viewBox: `0 0 ${layout.width} ${layout.height}`,
|
|
3871
|
+
class: "lt-state",
|
|
3872
|
+
"data-diagram-type": "state"
|
|
3873
|
+
},
|
|
3874
|
+
[
|
|
3875
|
+
chunkHDKDQAEQ_cjs.el("title", {}, chunkHDKDQAEQ_cjs.escapeXml(`State Diagram${layout.title ? " \u2014 " + layout.title : ""}`)),
|
|
3876
|
+
chunkHDKDQAEQ_cjs.el("desc", {}, "UML 2.5 / Harel statechart rendered by Schematex"),
|
|
3877
|
+
chunkHDKDQAEQ_cjs.defs([renderArrowMarker(), chunkHDKDQAEQ_cjs.el("style", {}, STYLE)]),
|
|
3878
|
+
titleNode,
|
|
3879
|
+
// Composite clusters first so simple-state bodies sit on top.
|
|
3880
|
+
chunkHDKDQAEQ_cjs.group({ class: "lt-clusters" }, layout.clusters.map(renderComposite)),
|
|
3881
|
+
chunkHDKDQAEQ_cjs.group({ class: "lt-state-bodies" }, layout.nodes.map(renderNode)),
|
|
3882
|
+
chunkHDKDQAEQ_cjs.group({ class: "lt-edges" }, layout.edges.map(renderEdge)),
|
|
3883
|
+
chunkHDKDQAEQ_cjs.group({ class: "lt-notes" }, layout.notes.map(renderNote))
|
|
3884
|
+
]
|
|
3885
|
+
);
|
|
3886
|
+
}
|
|
3887
|
+
|
|
3888
|
+
// src/diagrams/state/index.ts
|
|
3889
|
+
var state = {
|
|
3890
|
+
type: "state",
|
|
3891
|
+
detect(text2) {
|
|
3892
|
+
return /^\s*state\b/i.test(text2);
|
|
3893
|
+
},
|
|
3894
|
+
parse: parseStateDiagram,
|
|
3895
|
+
render(text2, config) {
|
|
3896
|
+
const ast = parseStateDiagram(text2);
|
|
3897
|
+
return renderStateDiagram(ast);
|
|
3898
|
+
}
|
|
3899
|
+
};
|
|
3900
|
+
|
|
3901
|
+
// src/diagrams/pid/parser.ts
|
|
3902
|
+
var PidParseError = class extends Error {
|
|
3903
|
+
constructor(message, line2) {
|
|
3904
|
+
super(line2 !== void 0 ? `Line ${line2}: ${message}` : message);
|
|
3905
|
+
this.line = line2;
|
|
3906
|
+
this.name = "PidParseError";
|
|
3907
|
+
}
|
|
3908
|
+
line;
|
|
3909
|
+
};
|
|
3910
|
+
var EQUIP_TYPES = /* @__PURE__ */ new Set([
|
|
3911
|
+
"tank_atm",
|
|
3912
|
+
"tank_cone_roof",
|
|
3913
|
+
"vessel_v",
|
|
3914
|
+
"vessel_h",
|
|
3915
|
+
"sphere",
|
|
3916
|
+
"column_tray",
|
|
3917
|
+
"column_packed",
|
|
3918
|
+
"hx_shell_tube",
|
|
3919
|
+
"hx_air_cooled",
|
|
3920
|
+
"reboiler",
|
|
3921
|
+
"condenser",
|
|
3922
|
+
"pump_centrifugal",
|
|
3923
|
+
"pump_pd",
|
|
3924
|
+
"compressor",
|
|
3925
|
+
"blower",
|
|
3926
|
+
"reactor_cstr",
|
|
3927
|
+
"reactor_pfr",
|
|
3928
|
+
"filter",
|
|
3929
|
+
"cyclone",
|
|
3930
|
+
"flare",
|
|
3931
|
+
"cooling_tower",
|
|
3932
|
+
"valve_gate",
|
|
3933
|
+
"valve_ball",
|
|
3934
|
+
"valve_globe",
|
|
3935
|
+
"valve_butterfly",
|
|
3936
|
+
"valve_check",
|
|
3937
|
+
"valve_control",
|
|
3938
|
+
"valve_psv"
|
|
3939
|
+
]);
|
|
3940
|
+
var LINE_TYPES = /* @__PURE__ */ new Set([
|
|
3941
|
+
"process",
|
|
3942
|
+
"process_minor",
|
|
3943
|
+
"pneumatic",
|
|
3944
|
+
"electric",
|
|
3945
|
+
"hydraulic",
|
|
3946
|
+
"capillary",
|
|
3947
|
+
"software",
|
|
3948
|
+
"mechanical"
|
|
3949
|
+
]);
|
|
3950
|
+
var INST_CATEGORIES = /* @__PURE__ */ new Set([
|
|
3951
|
+
"field_discrete",
|
|
3952
|
+
"field_shared",
|
|
3953
|
+
"field_computer",
|
|
3954
|
+
"field_plc",
|
|
3955
|
+
"cr_discrete",
|
|
3956
|
+
"cr_shared",
|
|
3957
|
+
"cr_computer",
|
|
3958
|
+
"cr_plc",
|
|
3959
|
+
"local_discrete",
|
|
3960
|
+
"local_shared"
|
|
3961
|
+
]);
|
|
3962
|
+
function preprocess4(src) {
|
|
3963
|
+
const out = [];
|
|
3964
|
+
const lines = src.split(/\r?\n/);
|
|
3965
|
+
for (let i = 0; i < lines.length; i++) {
|
|
3966
|
+
const raw = lines[i];
|
|
3967
|
+
if (raw === void 0) continue;
|
|
3968
|
+
let stripped = "";
|
|
3969
|
+
let inQuote = false;
|
|
3970
|
+
for (const ch of raw) {
|
|
3971
|
+
if (ch === '"') inQuote = !inQuote;
|
|
3972
|
+
if (ch === "#" && !inQuote) break;
|
|
3973
|
+
stripped += ch;
|
|
3974
|
+
}
|
|
3975
|
+
const trimmed = stripped.trim();
|
|
3976
|
+
if (!trimmed) continue;
|
|
3977
|
+
const indent = stripped.length - stripped.replace(/^\s+/, "").length;
|
|
3978
|
+
out.push({ text: trimmed, indent, line: i + 1 });
|
|
3979
|
+
}
|
|
3980
|
+
return out;
|
|
3981
|
+
}
|
|
3982
|
+
function unquote3(s) {
|
|
3983
|
+
const t = s.trim();
|
|
3984
|
+
if (t.length >= 2 && t.startsWith('"') && t.endsWith('"')) {
|
|
3985
|
+
return t.slice(1, -1).replace(/\\"/g, '"');
|
|
3986
|
+
}
|
|
3987
|
+
return t;
|
|
3988
|
+
}
|
|
3989
|
+
function parseAttrList(inside) {
|
|
3990
|
+
const out = {};
|
|
3991
|
+
const parts = [];
|
|
3992
|
+
let depth = 0;
|
|
3993
|
+
let inQuote = false;
|
|
3994
|
+
let cur = "";
|
|
3995
|
+
for (const ch of inside) {
|
|
3996
|
+
if (ch === '"') inQuote = !inQuote;
|
|
3997
|
+
if (!inQuote && ch === "[") depth++;
|
|
3998
|
+
if (!inQuote && ch === "]") depth--;
|
|
3999
|
+
if (!inQuote && depth === 0 && ch === ",") {
|
|
4000
|
+
parts.push(cur);
|
|
4001
|
+
cur = "";
|
|
4002
|
+
} else {
|
|
4003
|
+
cur += ch;
|
|
4004
|
+
}
|
|
4005
|
+
}
|
|
4006
|
+
if (cur.trim()) parts.push(cur);
|
|
4007
|
+
for (const p of parts) {
|
|
4008
|
+
const idx = p.indexOf(":");
|
|
4009
|
+
if (idx < 0) continue;
|
|
4010
|
+
const key = p.slice(0, idx).trim();
|
|
4011
|
+
const val = unquote3(p.slice(idx + 1).trim());
|
|
4012
|
+
out[key] = val;
|
|
4013
|
+
}
|
|
4014
|
+
return out;
|
|
4015
|
+
}
|
|
4016
|
+
function extractAttrs(text2) {
|
|
4017
|
+
let depth = 0;
|
|
4018
|
+
let inQuote = false;
|
|
4019
|
+
let openIdx = -1;
|
|
4020
|
+
for (let i = 0; i < text2.length; i++) {
|
|
4021
|
+
const ch = text2[i];
|
|
4022
|
+
if (ch === '"') inQuote = !inQuote;
|
|
4023
|
+
if (inQuote) continue;
|
|
4024
|
+
if (ch === "[") {
|
|
4025
|
+
if (depth === 0) openIdx = i;
|
|
4026
|
+
depth++;
|
|
4027
|
+
} else if (ch === "]") {
|
|
4028
|
+
depth--;
|
|
4029
|
+
if (depth === 0 && i === text2.length - 1) {
|
|
4030
|
+
const inside = text2.slice(openIdx + 1, i);
|
|
4031
|
+
return {
|
|
4032
|
+
rest: text2.slice(0, openIdx).trim(),
|
|
4033
|
+
attrs: parseAttrList(inside)
|
|
4034
|
+
};
|
|
4035
|
+
}
|
|
4036
|
+
}
|
|
4037
|
+
}
|
|
4038
|
+
return { rest: text2, attrs: {} };
|
|
4039
|
+
}
|
|
4040
|
+
function parseAnchor(tok) {
|
|
4041
|
+
const dot = tok.indexOf(".");
|
|
4042
|
+
if (dot < 0) return { id: tok };
|
|
4043
|
+
return { id: tok.slice(0, dot), port: tok.slice(dot + 1) };
|
|
4044
|
+
}
|
|
4045
|
+
function parsePid(src) {
|
|
4046
|
+
const lines = preprocess4(src);
|
|
4047
|
+
if (lines.length === 0) {
|
|
4048
|
+
throw new PidParseError("Empty document");
|
|
4049
|
+
}
|
|
4050
|
+
const header = lines[0];
|
|
4051
|
+
if (!/^pid\b/i.test(header.text)) {
|
|
4052
|
+
throw new PidParseError(`Expected 'pid' header, got '${header.text}'`, header.line);
|
|
4053
|
+
}
|
|
4054
|
+
let title2;
|
|
4055
|
+
let direction = "LR";
|
|
4056
|
+
const headerRest = header.text.replace(/^pid\b/i, "").trim();
|
|
4057
|
+
const { rest, attrs: headerAttrs } = extractAttrs(headerRest);
|
|
4058
|
+
if (headerAttrs.direction === "TB") direction = "TB";
|
|
4059
|
+
if (headerAttrs.direction === "LR") direction = "LR";
|
|
4060
|
+
if (rest) title2 = unquote3(rest);
|
|
4061
|
+
const equipment = [];
|
|
4062
|
+
const linesAst = [];
|
|
4063
|
+
const instruments = [];
|
|
4064
|
+
let currentInst;
|
|
4065
|
+
for (let idx = 1; idx < lines.length; idx++) {
|
|
4066
|
+
const ln = lines[idx];
|
|
4067
|
+
const text2 = ln.text;
|
|
4068
|
+
const measuresMatch = text2.match(/^measures\s+(.+)$/);
|
|
4069
|
+
if (measuresMatch && currentInst) {
|
|
4070
|
+
currentInst.measures = measuresMatch[1].trim();
|
|
4071
|
+
continue;
|
|
4072
|
+
}
|
|
4073
|
+
const controlsMatch = text2.match(/^controls\s+(.+)$/);
|
|
4074
|
+
if (controlsMatch && currentInst) {
|
|
4075
|
+
currentInst.controls = controlsMatch[1].trim();
|
|
4076
|
+
continue;
|
|
4077
|
+
}
|
|
4078
|
+
currentInst = void 0;
|
|
4079
|
+
const equipMatch = text2.match(/^equip\s+([A-Za-z][A-Za-z0-9_-]*)\s*:\s*(.+)$/);
|
|
4080
|
+
if (equipMatch) {
|
|
4081
|
+
const id = equipMatch[1];
|
|
4082
|
+
const tail = equipMatch[2];
|
|
4083
|
+
const { rest: typeRest, attrs } = extractAttrs(tail);
|
|
4084
|
+
const equipType = typeRest.trim();
|
|
4085
|
+
if (!EQUIP_TYPES.has(equipType)) {
|
|
4086
|
+
throw new PidParseError(`Unknown equipment type '${equipType}'`, ln.line);
|
|
4087
|
+
}
|
|
4088
|
+
equipment.push({
|
|
4089
|
+
id,
|
|
4090
|
+
equipType,
|
|
4091
|
+
tag: attrs.tag ?? id,
|
|
4092
|
+
attrs
|
|
4093
|
+
});
|
|
4094
|
+
continue;
|
|
4095
|
+
}
|
|
4096
|
+
const lineMatch = text2.match(/^line\s+([A-Za-z0-9_-]+)\s+from\s+(\S+)\s+to\s+(\S+)\s*(.*)$/);
|
|
4097
|
+
if (lineMatch) {
|
|
4098
|
+
const id = lineMatch[1];
|
|
4099
|
+
const fromTok = lineMatch[2];
|
|
4100
|
+
const toTok = lineMatch[3];
|
|
4101
|
+
const tail = lineMatch[4];
|
|
4102
|
+
const { attrs } = extractAttrs(tail);
|
|
4103
|
+
const lt = attrs.type ?? "process";
|
|
4104
|
+
if (!LINE_TYPES.has(lt)) {
|
|
4105
|
+
throw new PidParseError(`Unknown line type '${lt}'`, ln.line);
|
|
4106
|
+
}
|
|
4107
|
+
linesAst.push({
|
|
4108
|
+
id,
|
|
4109
|
+
from: parseAnchor(fromTok),
|
|
4110
|
+
to: parseAnchor(toTok),
|
|
4111
|
+
lineType: lt,
|
|
4112
|
+
tag: attrs.tag,
|
|
4113
|
+
size: attrs.size,
|
|
4114
|
+
service: attrs.service,
|
|
4115
|
+
attrs
|
|
4116
|
+
});
|
|
4117
|
+
continue;
|
|
4118
|
+
}
|
|
4119
|
+
const instMatch = text2.match(/^inst\s+([A-Z][A-Z0-9]*-[A-Za-z0-9]+)\s*:\s*(.+)$/);
|
|
4120
|
+
if (instMatch) {
|
|
4121
|
+
const tag = instMatch[1];
|
|
4122
|
+
const { rest: catRest, attrs } = extractAttrs(instMatch[2]);
|
|
4123
|
+
const category = catRest.trim();
|
|
4124
|
+
if (!INST_CATEGORIES.has(category)) {
|
|
4125
|
+
throw new PidParseError(`Unknown instrument category '${category}'`, ln.line);
|
|
4126
|
+
}
|
|
4127
|
+
const inst = {
|
|
4128
|
+
tag,
|
|
4129
|
+
category,
|
|
4130
|
+
attrs
|
|
4131
|
+
};
|
|
4132
|
+
instruments.push(inst);
|
|
4133
|
+
currentInst = inst;
|
|
4134
|
+
continue;
|
|
4135
|
+
}
|
|
4136
|
+
throw new PidParseError(`Unparseable line: ${text2}`, ln.line);
|
|
4137
|
+
}
|
|
4138
|
+
return {
|
|
4139
|
+
type: "pid",
|
|
4140
|
+
title: title2,
|
|
4141
|
+
direction,
|
|
4142
|
+
equipment,
|
|
4143
|
+
lines: linesAst,
|
|
4144
|
+
instruments
|
|
4145
|
+
};
|
|
4146
|
+
}
|
|
4147
|
+
|
|
4148
|
+
// src/diagrams/pid/symbols.ts
|
|
4149
|
+
var GEOMETRY = {
|
|
4150
|
+
// ── Tanks & vessels ─────────────────────────────────────
|
|
4151
|
+
tank_atm: {
|
|
4152
|
+
width: 90,
|
|
4153
|
+
height: 90,
|
|
4154
|
+
ports: {
|
|
4155
|
+
top: { x: 0, y: -45 },
|
|
4156
|
+
bottom: { x: 0, y: 45 },
|
|
4157
|
+
left: { x: -45, y: 0 },
|
|
4158
|
+
right: { x: 45, y: 0 },
|
|
4159
|
+
in: { x: -45, y: 0 },
|
|
4160
|
+
out: { x: 45, y: 0 }
|
|
4161
|
+
}
|
|
4162
|
+
},
|
|
4163
|
+
tank_cone_roof: {
|
|
4164
|
+
width: 90,
|
|
4165
|
+
height: 100,
|
|
4166
|
+
ports: {
|
|
4167
|
+
top: { x: 0, y: -50 },
|
|
4168
|
+
bottom: { x: 0, y: 50 },
|
|
4169
|
+
left: { x: -45, y: 0 },
|
|
4170
|
+
right: { x: 45, y: 0 }
|
|
4171
|
+
}
|
|
4172
|
+
},
|
|
4173
|
+
vessel_v: {
|
|
4174
|
+
width: 70,
|
|
4175
|
+
height: 130,
|
|
4176
|
+
ports: {
|
|
4177
|
+
top: { x: 0, y: -65 },
|
|
4178
|
+
bottom: { x: 0, y: 65 },
|
|
4179
|
+
left: { x: -35, y: 0 },
|
|
4180
|
+
right: { x: 35, y: 0 },
|
|
4181
|
+
in: { x: -35, y: -25 },
|
|
4182
|
+
out: { x: 35, y: 25 }
|
|
4183
|
+
}
|
|
4184
|
+
},
|
|
4185
|
+
vessel_h: {
|
|
4186
|
+
width: 130,
|
|
4187
|
+
height: 70,
|
|
4188
|
+
ports: {
|
|
4189
|
+
top: { x: 0, y: -35 },
|
|
4190
|
+
bottom: { x: 0, y: 35 },
|
|
4191
|
+
left: { x: -65, y: 0 },
|
|
4192
|
+
right: { x: 65, y: 0 },
|
|
4193
|
+
in: { x: -65, y: 0 },
|
|
4194
|
+
out: { x: 65, y: 0 }
|
|
4195
|
+
}
|
|
4196
|
+
},
|
|
4197
|
+
sphere: {
|
|
4198
|
+
width: 90,
|
|
4199
|
+
height: 90,
|
|
4200
|
+
ports: {
|
|
4201
|
+
top: { x: 0, y: -45 },
|
|
4202
|
+
bottom: { x: 0, y: 45 },
|
|
4203
|
+
left: { x: -45, y: 0 },
|
|
4204
|
+
right: { x: 45, y: 0 }
|
|
4205
|
+
}
|
|
4206
|
+
},
|
|
4207
|
+
column_tray: {
|
|
4208
|
+
width: 60,
|
|
4209
|
+
height: 180,
|
|
4210
|
+
ports: {
|
|
4211
|
+
top: { x: 0, y: -90 },
|
|
4212
|
+
bottom: { x: 0, y: 90 },
|
|
4213
|
+
feed: { x: -30, y: 0 },
|
|
4214
|
+
reflux: { x: 0, y: -90 },
|
|
4215
|
+
bottom_return: { x: -30, y: 70 },
|
|
4216
|
+
vapor_out: { x: 0, y: -90 },
|
|
4217
|
+
liquid_out: { x: 0, y: 90 }
|
|
4218
|
+
}
|
|
4219
|
+
},
|
|
4220
|
+
column_packed: {
|
|
4221
|
+
width: 60,
|
|
4222
|
+
height: 180,
|
|
4223
|
+
ports: {
|
|
4224
|
+
top: { x: 0, y: -90 },
|
|
4225
|
+
bottom: { x: 0, y: 90 },
|
|
4226
|
+
feed: { x: -30, y: 0 }
|
|
4227
|
+
}
|
|
4228
|
+
},
|
|
4229
|
+
hx_shell_tube: {
|
|
4230
|
+
width: 130,
|
|
4231
|
+
height: 60,
|
|
4232
|
+
ports: {
|
|
4233
|
+
shell_in: { x: 0, y: -30 },
|
|
4234
|
+
shell_out: { x: 0, y: 30 },
|
|
4235
|
+
tube_in: { x: -65, y: 0 },
|
|
4236
|
+
tube_out: { x: 65, y: 0 },
|
|
4237
|
+
in: { x: -65, y: 0 },
|
|
4238
|
+
out: { x: 65, y: 0 }
|
|
4239
|
+
}
|
|
4240
|
+
},
|
|
4241
|
+
hx_air_cooled: {
|
|
4242
|
+
width: 130,
|
|
4243
|
+
height: 80,
|
|
4244
|
+
ports: {
|
|
4245
|
+
in: { x: -65, y: 10 },
|
|
4246
|
+
out: { x: 65, y: 10 }
|
|
4247
|
+
}
|
|
4248
|
+
},
|
|
4249
|
+
reboiler: {
|
|
4250
|
+
width: 110,
|
|
4251
|
+
height: 60,
|
|
4252
|
+
ports: {
|
|
4253
|
+
in: { x: -55, y: 0 },
|
|
4254
|
+
out: { x: 55, y: 0 },
|
|
4255
|
+
bottom: { x: 0, y: 30 }
|
|
4256
|
+
}
|
|
4257
|
+
},
|
|
4258
|
+
condenser: {
|
|
4259
|
+
width: 130,
|
|
4260
|
+
height: 60,
|
|
4261
|
+
ports: {
|
|
4262
|
+
shell_in: { x: -50, y: -30 },
|
|
4263
|
+
shell_out: { x: 50, y: 30 },
|
|
4264
|
+
tube_in: { x: -65, y: 0 },
|
|
4265
|
+
tube_out: { x: 65, y: 0 },
|
|
4266
|
+
in: { x: -65, y: 0 },
|
|
4267
|
+
out: { x: 65, y: 0 }
|
|
4268
|
+
}
|
|
4269
|
+
},
|
|
4270
|
+
pump_centrifugal: {
|
|
4271
|
+
width: 70,
|
|
4272
|
+
height: 60,
|
|
4273
|
+
ports: {
|
|
4274
|
+
in: { x: -30, y: 0 },
|
|
4275
|
+
out: { x: 28, y: -22 },
|
|
4276
|
+
top: { x: 28, y: -22 },
|
|
4277
|
+
left: { x: -30, y: 0 },
|
|
4278
|
+
right: { x: 28, y: -22 }
|
|
4279
|
+
}
|
|
4280
|
+
},
|
|
4281
|
+
pump_pd: {
|
|
4282
|
+
width: 70,
|
|
4283
|
+
height: 60,
|
|
4284
|
+
ports: {
|
|
4285
|
+
in: { x: -35, y: 0 },
|
|
4286
|
+
out: { x: 35, y: 0 }
|
|
4287
|
+
}
|
|
4288
|
+
},
|
|
4289
|
+
compressor: {
|
|
4290
|
+
width: 90,
|
|
4291
|
+
height: 60,
|
|
4292
|
+
ports: {
|
|
4293
|
+
in: { x: -45, y: 0 },
|
|
4294
|
+
out: { x: 45, y: 0 }
|
|
4295
|
+
}
|
|
4296
|
+
},
|
|
4297
|
+
blower: {
|
|
4298
|
+
width: 70,
|
|
4299
|
+
height: 60,
|
|
4300
|
+
ports: {
|
|
4301
|
+
in: { x: -35, y: 0 },
|
|
4302
|
+
out: { x: 35, y: 0 }
|
|
4303
|
+
}
|
|
4304
|
+
},
|
|
4305
|
+
reactor_cstr: {
|
|
4306
|
+
width: 90,
|
|
4307
|
+
height: 110,
|
|
4308
|
+
ports: {
|
|
4309
|
+
top: { x: 0, y: -55 },
|
|
4310
|
+
bottom: { x: 0, y: 55 },
|
|
4311
|
+
in: { x: -45, y: -10 },
|
|
4312
|
+
out: { x: 0, y: 55 }
|
|
4313
|
+
}
|
|
4314
|
+
},
|
|
4315
|
+
reactor_pfr: {
|
|
4316
|
+
width: 130,
|
|
4317
|
+
height: 50,
|
|
4318
|
+
ports: {
|
|
4319
|
+
in: { x: -65, y: 0 },
|
|
4320
|
+
out: { x: 65, y: 0 }
|
|
4321
|
+
}
|
|
4322
|
+
},
|
|
4323
|
+
filter: {
|
|
4324
|
+
width: 70,
|
|
4325
|
+
height: 70,
|
|
4326
|
+
ports: {
|
|
4327
|
+
in: { x: -35, y: 0 },
|
|
4328
|
+
out: { x: 35, y: 0 }
|
|
4329
|
+
}
|
|
4330
|
+
},
|
|
4331
|
+
cyclone: {
|
|
4332
|
+
width: 70,
|
|
4333
|
+
height: 100,
|
|
4334
|
+
ports: {
|
|
4335
|
+
top: { x: 0, y: -50 },
|
|
4336
|
+
in: { x: -35, y: -30 },
|
|
4337
|
+
bottom: { x: 0, y: 50 },
|
|
4338
|
+
out: { x: 0, y: -50 }
|
|
4339
|
+
}
|
|
4340
|
+
},
|
|
4341
|
+
flare: {
|
|
4342
|
+
width: 30,
|
|
4343
|
+
height: 110,
|
|
4344
|
+
ports: {
|
|
4345
|
+
top: { x: 0, y: -55 },
|
|
4346
|
+
bottom: { x: 0, y: 55 },
|
|
4347
|
+
in: { x: 0, y: 55 }
|
|
4348
|
+
}
|
|
4349
|
+
},
|
|
4350
|
+
cooling_tower: {
|
|
4351
|
+
width: 100,
|
|
4352
|
+
height: 90,
|
|
4353
|
+
ports: {
|
|
4354
|
+
top: { x: 0, y: -45 },
|
|
4355
|
+
in: { x: -50, y: 0 },
|
|
4356
|
+
out: { x: 50, y: 0 }
|
|
4357
|
+
}
|
|
4358
|
+
},
|
|
4359
|
+
// ── Valves (in-line) ──────────────────────────────────
|
|
4360
|
+
valve_gate: {
|
|
4361
|
+
width: 36,
|
|
4362
|
+
height: 22,
|
|
4363
|
+
ports: { in: { x: -18, y: 0 }, out: { x: 18, y: 0 }, left: { x: -18, y: 0 }, right: { x: 18, y: 0 } }
|
|
4364
|
+
},
|
|
4365
|
+
valve_ball: {
|
|
4366
|
+
width: 36,
|
|
4367
|
+
height: 22,
|
|
4368
|
+
ports: { in: { x: -18, y: 0 }, out: { x: 18, y: 0 } }
|
|
4369
|
+
},
|
|
4370
|
+
valve_globe: {
|
|
4371
|
+
width: 36,
|
|
4372
|
+
height: 28,
|
|
4373
|
+
ports: { in: { x: -18, y: 0 }, out: { x: 18, y: 0 } }
|
|
4374
|
+
},
|
|
4375
|
+
valve_butterfly: {
|
|
4376
|
+
width: 36,
|
|
4377
|
+
height: 22,
|
|
4378
|
+
ports: { in: { x: -18, y: 0 }, out: { x: 18, y: 0 } }
|
|
4379
|
+
},
|
|
4380
|
+
valve_check: {
|
|
4381
|
+
width: 36,
|
|
4382
|
+
height: 22,
|
|
4383
|
+
ports: { in: { x: -18, y: 0 }, out: { x: 18, y: 0 } }
|
|
4384
|
+
},
|
|
4385
|
+
valve_control: {
|
|
4386
|
+
width: 36,
|
|
4387
|
+
height: 60,
|
|
4388
|
+
ports: { in: { x: -18, y: 12 }, out: { x: 18, y: 12 }, top: { x: 0, y: -22 } }
|
|
4389
|
+
},
|
|
4390
|
+
valve_psv: {
|
|
4391
|
+
width: 36,
|
|
4392
|
+
height: 60,
|
|
4393
|
+
ports: { in: { x: -18, y: 12 }, out: { x: 18, y: -8 } }
|
|
4394
|
+
}
|
|
4395
|
+
};
|
|
4396
|
+
var STROKE_BLACK = "#1d1d1d";
|
|
4397
|
+
var FILL_WHITE = "#ffffff";
|
|
4398
|
+
function bowtie() {
|
|
4399
|
+
return chunkHDKDQAEQ_cjs.polygon({
|
|
4400
|
+
points: "-18,-11 0,0 -18,11 18,11 0,0 18,-11",
|
|
4401
|
+
class: "lt-pid-valve-body"
|
|
4402
|
+
});
|
|
4403
|
+
}
|
|
4404
|
+
function renderEquip(type, label) {
|
|
4405
|
+
switch (type) {
|
|
4406
|
+
case "tank_atm": {
|
|
4407
|
+
const w = 90;
|
|
4408
|
+
const h = 90;
|
|
4409
|
+
const cylTop = -h / 2 + 14;
|
|
4410
|
+
const parts = [
|
|
4411
|
+
// dome top
|
|
4412
|
+
chunkHDKDQAEQ_cjs.path({
|
|
4413
|
+
d: `M ${-w / 2} ${cylTop} A ${w / 2} 14 0 0 1 ${w / 2} ${cylTop}`,
|
|
4414
|
+
class: "lt-pid-equip"
|
|
4415
|
+
}),
|
|
4416
|
+
// body
|
|
4417
|
+
chunkHDKDQAEQ_cjs.rect({
|
|
4418
|
+
x: -w / 2,
|
|
4419
|
+
y: cylTop,
|
|
4420
|
+
width: w,
|
|
4421
|
+
height: h - 14,
|
|
4422
|
+
class: "lt-pid-equip"
|
|
4423
|
+
}),
|
|
4424
|
+
// tag
|
|
4425
|
+
chunkHDKDQAEQ_cjs.text(
|
|
4426
|
+
{ x: 0, y: 4, "text-anchor": "middle", class: "lt-pid-equip-tag" },
|
|
4427
|
+
label
|
|
4428
|
+
)
|
|
4429
|
+
];
|
|
4430
|
+
return chunkHDKDQAEQ_cjs.group({ class: "lt-pid-equip-group" }, parts);
|
|
4431
|
+
}
|
|
4432
|
+
case "tank_cone_roof": {
|
|
4433
|
+
const w = 90;
|
|
4434
|
+
const h = 100;
|
|
4435
|
+
const roofH = 18;
|
|
4436
|
+
const top = -h / 2;
|
|
4437
|
+
return chunkHDKDQAEQ_cjs.group({}, [
|
|
4438
|
+
chunkHDKDQAEQ_cjs.polygon({
|
|
4439
|
+
points: `${-w / 2},${top + roofH} 0,${top} ${w / 2},${top + roofH}`,
|
|
4440
|
+
class: "lt-pid-equip"
|
|
4441
|
+
}),
|
|
4442
|
+
chunkHDKDQAEQ_cjs.rect({
|
|
4443
|
+
x: -w / 2,
|
|
4444
|
+
y: top + roofH,
|
|
4445
|
+
width: w,
|
|
4446
|
+
height: h - roofH,
|
|
4447
|
+
class: "lt-pid-equip"
|
|
4448
|
+
}),
|
|
4449
|
+
chunkHDKDQAEQ_cjs.text({ x: 0, y: 4, "text-anchor": "middle", class: "lt-pid-equip-tag" }, label)
|
|
4450
|
+
]);
|
|
4451
|
+
}
|
|
4452
|
+
case "vessel_v": {
|
|
4453
|
+
const w = 70;
|
|
4454
|
+
const h = 130;
|
|
4455
|
+
const headH = 16;
|
|
4456
|
+
const top = -h / 2;
|
|
4457
|
+
const bot = h / 2;
|
|
4458
|
+
return chunkHDKDQAEQ_cjs.group({}, [
|
|
4459
|
+
chunkHDKDQAEQ_cjs.path({
|
|
4460
|
+
d: `M ${-w / 2} ${top + headH}
|
|
4461
|
+
A ${w / 2} ${headH} 0 0 1 ${w / 2} ${top + headH}
|
|
4462
|
+
L ${w / 2} ${bot - headH}
|
|
4463
|
+
A ${w / 2} ${headH} 0 0 1 ${-w / 2} ${bot - headH}
|
|
4464
|
+
Z`,
|
|
4465
|
+
class: "lt-pid-equip"
|
|
4466
|
+
}),
|
|
4467
|
+
chunkHDKDQAEQ_cjs.text(
|
|
4468
|
+
{ x: 0, y: 4, "text-anchor": "middle", class: "lt-pid-equip-tag" },
|
|
4469
|
+
label
|
|
4470
|
+
)
|
|
4471
|
+
]);
|
|
4472
|
+
}
|
|
4473
|
+
case "vessel_h": {
|
|
4474
|
+
const w = 130;
|
|
4475
|
+
const h = 70;
|
|
4476
|
+
const headW = 14;
|
|
4477
|
+
const left = -w / 2;
|
|
4478
|
+
const right = w / 2;
|
|
4479
|
+
return chunkHDKDQAEQ_cjs.group({}, [
|
|
4480
|
+
chunkHDKDQAEQ_cjs.path({
|
|
4481
|
+
d: `M ${left + headW} ${-h / 2}
|
|
4482
|
+
L ${right - headW} ${-h / 2}
|
|
4483
|
+
A ${headW} ${h / 2} 0 0 1 ${right - headW} ${h / 2}
|
|
4484
|
+
L ${left + headW} ${h / 2}
|
|
4485
|
+
A ${headW} ${h / 2} 0 0 1 ${left + headW} ${-h / 2}
|
|
4486
|
+
Z`,
|
|
4487
|
+
class: "lt-pid-equip"
|
|
4488
|
+
}),
|
|
4489
|
+
chunkHDKDQAEQ_cjs.text(
|
|
4490
|
+
{ x: 0, y: 4, "text-anchor": "middle", class: "lt-pid-equip-tag" },
|
|
4491
|
+
label
|
|
4492
|
+
)
|
|
4493
|
+
]);
|
|
4494
|
+
}
|
|
4495
|
+
case "sphere": {
|
|
4496
|
+
return chunkHDKDQAEQ_cjs.group({}, [
|
|
4497
|
+
chunkHDKDQAEQ_cjs.circle({ cx: 0, cy: 0, r: 45, class: "lt-pid-equip" }),
|
|
4498
|
+
chunkHDKDQAEQ_cjs.text({ x: 0, y: 4, "text-anchor": "middle", class: "lt-pid-equip-tag" }, label)
|
|
4499
|
+
]);
|
|
4500
|
+
}
|
|
4501
|
+
case "column_tray": {
|
|
4502
|
+
const w = 60;
|
|
4503
|
+
const h = 180;
|
|
4504
|
+
const headH = 12;
|
|
4505
|
+
const trays = 12;
|
|
4506
|
+
const inner = h - headH * 2;
|
|
4507
|
+
const traySpacing = inner / (trays + 1);
|
|
4508
|
+
const trayLines = [];
|
|
4509
|
+
for (let i = 1; i <= trays; i++) {
|
|
4510
|
+
const y = -h / 2 + headH + traySpacing * i;
|
|
4511
|
+
trayLines.push(
|
|
4512
|
+
chunkHDKDQAEQ_cjs.line({
|
|
4513
|
+
x1: -w / 2 + 6,
|
|
4514
|
+
y1: y,
|
|
4515
|
+
x2: w / 2 - 6,
|
|
4516
|
+
y2: y,
|
|
4517
|
+
class: "lt-pid-tray-line"
|
|
4518
|
+
})
|
|
4519
|
+
);
|
|
4520
|
+
}
|
|
4521
|
+
return chunkHDKDQAEQ_cjs.group({}, [
|
|
4522
|
+
chunkHDKDQAEQ_cjs.path({
|
|
4523
|
+
d: `M ${-w / 2} ${-h / 2 + headH}
|
|
4524
|
+
A ${w / 2} ${headH} 0 0 1 ${w / 2} ${-h / 2 + headH}
|
|
4525
|
+
L ${w / 2} ${h / 2 - headH}
|
|
4526
|
+
A ${w / 2} ${headH} 0 0 1 ${-w / 2} ${h / 2 - headH}
|
|
4527
|
+
Z`,
|
|
4528
|
+
class: "lt-pid-equip"
|
|
4529
|
+
}),
|
|
4530
|
+
...trayLines,
|
|
4531
|
+
chunkHDKDQAEQ_cjs.text(
|
|
4532
|
+
{
|
|
4533
|
+
x: 0,
|
|
4534
|
+
y: -h / 2 - 6,
|
|
4535
|
+
"text-anchor": "middle",
|
|
4536
|
+
class: "lt-pid-equip-tag"
|
|
4537
|
+
},
|
|
4538
|
+
label
|
|
4539
|
+
)
|
|
4540
|
+
]);
|
|
4541
|
+
}
|
|
4542
|
+
case "column_packed": {
|
|
4543
|
+
const w = 60;
|
|
4544
|
+
const h = 180;
|
|
4545
|
+
const headH = 12;
|
|
4546
|
+
const packing = chunkHDKDQAEQ_cjs.path({
|
|
4547
|
+
d: `M ${-w / 2 + 6} ${-h / 2 + headH + 6}
|
|
4548
|
+
L ${w / 2 - 6} ${h / 2 - headH - 6}
|
|
4549
|
+
M ${w / 2 - 6} ${-h / 2 + headH + 6}
|
|
4550
|
+
L ${-w / 2 + 6} ${h / 2 - headH - 6}`,
|
|
4551
|
+
class: "lt-pid-tray-line"
|
|
4552
|
+
});
|
|
4553
|
+
return chunkHDKDQAEQ_cjs.group({}, [
|
|
4554
|
+
chunkHDKDQAEQ_cjs.path({
|
|
4555
|
+
d: `M ${-w / 2} ${-h / 2 + headH}
|
|
4556
|
+
A ${w / 2} ${headH} 0 0 1 ${w / 2} ${-h / 2 + headH}
|
|
4557
|
+
L ${w / 2} ${h / 2 - headH}
|
|
4558
|
+
A ${w / 2} ${headH} 0 0 1 ${-w / 2} ${h / 2 - headH}
|
|
4559
|
+
Z`,
|
|
4560
|
+
class: "lt-pid-equip"
|
|
4561
|
+
}),
|
|
4562
|
+
packing,
|
|
4563
|
+
chunkHDKDQAEQ_cjs.text(
|
|
4564
|
+
{
|
|
4565
|
+
x: 0,
|
|
4566
|
+
y: -h / 2 - 6,
|
|
4567
|
+
"text-anchor": "middle",
|
|
4568
|
+
class: "lt-pid-equip-tag"
|
|
4569
|
+
},
|
|
4570
|
+
label
|
|
4571
|
+
)
|
|
4572
|
+
]);
|
|
4573
|
+
}
|
|
4574
|
+
case "hx_shell_tube": {
|
|
4575
|
+
const w = 130;
|
|
4576
|
+
const h = 60;
|
|
4577
|
+
const headW = 12;
|
|
4578
|
+
const left = -w / 2;
|
|
4579
|
+
const right = w / 2;
|
|
4580
|
+
const tubes = [];
|
|
4581
|
+
for (let yy = -h / 2 + 12; yy <= h / 2 - 12; yy += 8) {
|
|
4582
|
+
tubes.push(
|
|
4583
|
+
chunkHDKDQAEQ_cjs.line({
|
|
4584
|
+
x1: left + headW + 4,
|
|
4585
|
+
y1: yy,
|
|
4586
|
+
x2: right - headW - 4,
|
|
4587
|
+
y2: yy,
|
|
4588
|
+
class: "lt-pid-tray-line"
|
|
4589
|
+
})
|
|
4590
|
+
);
|
|
4591
|
+
}
|
|
4592
|
+
return chunkHDKDQAEQ_cjs.group({}, [
|
|
4593
|
+
chunkHDKDQAEQ_cjs.path({
|
|
4594
|
+
d: `M ${left + headW} ${-h / 2}
|
|
4595
|
+
L ${right - headW} ${-h / 2}
|
|
4596
|
+
A ${headW} ${h / 2} 0 0 1 ${right - headW} ${h / 2}
|
|
4597
|
+
L ${left + headW} ${h / 2}
|
|
4598
|
+
A ${headW} ${h / 2} 0 0 1 ${left + headW} ${-h / 2}
|
|
4599
|
+
Z`,
|
|
4600
|
+
class: "lt-pid-equip"
|
|
4601
|
+
}),
|
|
4602
|
+
...tubes,
|
|
4603
|
+
chunkHDKDQAEQ_cjs.text(
|
|
4604
|
+
{
|
|
4605
|
+
x: 0,
|
|
4606
|
+
y: h / 2 + 14,
|
|
4607
|
+
"text-anchor": "middle",
|
|
4608
|
+
class: "lt-pid-equip-tag"
|
|
4609
|
+
},
|
|
4610
|
+
label
|
|
4611
|
+
)
|
|
4612
|
+
]);
|
|
4613
|
+
}
|
|
4614
|
+
case "hx_air_cooled": {
|
|
4615
|
+
const w = 130;
|
|
4616
|
+
const h = 80;
|
|
4617
|
+
return chunkHDKDQAEQ_cjs.group({}, [
|
|
4618
|
+
chunkHDKDQAEQ_cjs.rect({
|
|
4619
|
+
x: -w / 2,
|
|
4620
|
+
y: -h / 2 + 18,
|
|
4621
|
+
width: w,
|
|
4622
|
+
height: h - 18,
|
|
4623
|
+
class: "lt-pid-equip"
|
|
4624
|
+
}),
|
|
4625
|
+
chunkHDKDQAEQ_cjs.circle({ cx: 0, cy: -h / 2 + 14, r: 18, class: "lt-pid-equip" }),
|
|
4626
|
+
// 3-blade fan
|
|
4627
|
+
chunkHDKDQAEQ_cjs.path({
|
|
4628
|
+
d: `M 0 ${-h / 2 + 14} L 14 ${-h / 2 + 6}
|
|
4629
|
+
M 0 ${-h / 2 + 14} L -14 ${-h / 2 + 6}
|
|
4630
|
+
M 0 ${-h / 2 + 14} L 0 ${-h / 2 + 30}`,
|
|
4631
|
+
class: "lt-pid-tray-line"
|
|
4632
|
+
}),
|
|
4633
|
+
chunkHDKDQAEQ_cjs.text(
|
|
4634
|
+
{ x: 0, y: h / 2 + 14, "text-anchor": "middle", class: "lt-pid-equip-tag" },
|
|
4635
|
+
label
|
|
4636
|
+
)
|
|
4637
|
+
]);
|
|
4638
|
+
}
|
|
4639
|
+
case "reboiler": {
|
|
4640
|
+
const w = 110;
|
|
4641
|
+
const h = 60;
|
|
4642
|
+
const headW = 14;
|
|
4643
|
+
return chunkHDKDQAEQ_cjs.group({}, [
|
|
4644
|
+
chunkHDKDQAEQ_cjs.path({
|
|
4645
|
+
d: `M ${-w / 2 + headW} ${-h / 2}
|
|
4646
|
+
L ${w / 2 - headW} ${-h / 2}
|
|
4647
|
+
A ${headW} ${h / 2} 0 0 1 ${w / 2 - headW} ${h / 2}
|
|
4648
|
+
L ${-w / 2 + headW} ${h / 2}
|
|
4649
|
+
A ${headW} ${h / 2} 0 0 1 ${-w / 2 + headW} ${-h / 2}
|
|
4650
|
+
Z`,
|
|
4651
|
+
class: "lt-pid-equip"
|
|
4652
|
+
}),
|
|
4653
|
+
chunkHDKDQAEQ_cjs.line({
|
|
4654
|
+
x1: -w / 2 + headW + 4,
|
|
4655
|
+
y1: -10,
|
|
4656
|
+
x2: w / 2 - headW - 4,
|
|
4657
|
+
y2: -10,
|
|
4658
|
+
class: "lt-pid-tray-line"
|
|
4659
|
+
}),
|
|
4660
|
+
chunkHDKDQAEQ_cjs.line({
|
|
4661
|
+
x1: -w / 2 + headW + 4,
|
|
4662
|
+
y1: 0,
|
|
4663
|
+
x2: w / 2 - headW - 4,
|
|
4664
|
+
y2: 0,
|
|
4665
|
+
class: "lt-pid-tray-line"
|
|
4666
|
+
}),
|
|
4667
|
+
chunkHDKDQAEQ_cjs.line({
|
|
4668
|
+
x1: -w / 2 + headW + 4,
|
|
4669
|
+
y1: 10,
|
|
4670
|
+
x2: w / 2 - headW - 4,
|
|
4671
|
+
y2: 10,
|
|
4672
|
+
class: "lt-pid-tray-line"
|
|
4673
|
+
}),
|
|
4674
|
+
chunkHDKDQAEQ_cjs.text({ x: 0, y: h / 2 + 14, "text-anchor": "middle", class: "lt-pid-equip-tag" }, label)
|
|
4675
|
+
]);
|
|
4676
|
+
}
|
|
4677
|
+
case "condenser": {
|
|
4678
|
+
const w = 130;
|
|
4679
|
+
const h = 60;
|
|
4680
|
+
const headW = 12;
|
|
4681
|
+
const left = -w / 2;
|
|
4682
|
+
const right = w / 2;
|
|
4683
|
+
const tubes = [];
|
|
4684
|
+
for (let yy = -h / 2 + 12; yy <= h / 2 - 12; yy += 10) {
|
|
4685
|
+
tubes.push(
|
|
4686
|
+
chunkHDKDQAEQ_cjs.line({
|
|
4687
|
+
x1: left + headW + 4,
|
|
4688
|
+
y1: yy,
|
|
4689
|
+
x2: right - headW - 4,
|
|
4690
|
+
y2: yy,
|
|
4691
|
+
class: "lt-pid-tray-line"
|
|
4692
|
+
})
|
|
4693
|
+
);
|
|
4694
|
+
}
|
|
4695
|
+
return chunkHDKDQAEQ_cjs.group({}, [
|
|
4696
|
+
chunkHDKDQAEQ_cjs.path({
|
|
4697
|
+
d: `M ${left + headW} ${-h / 2}
|
|
4698
|
+
L ${right - headW} ${-h / 2}
|
|
4699
|
+
A ${headW} ${h / 2} 0 0 1 ${right - headW} ${h / 2}
|
|
4700
|
+
L ${left + headW} ${h / 2}
|
|
4701
|
+
A ${headW} ${h / 2} 0 0 1 ${left + headW} ${-h / 2}
|
|
4702
|
+
Z`,
|
|
4703
|
+
class: "lt-pid-equip"
|
|
4704
|
+
}),
|
|
4705
|
+
...tubes,
|
|
4706
|
+
chunkHDKDQAEQ_cjs.text({ x: 0, y: h / 2 + 14, "text-anchor": "middle", class: "lt-pid-equip-tag" }, label)
|
|
4707
|
+
]);
|
|
4708
|
+
}
|
|
4709
|
+
case "pump_centrifugal": {
|
|
4710
|
+
const r = 22;
|
|
4711
|
+
return chunkHDKDQAEQ_cjs.group({}, [
|
|
4712
|
+
chunkHDKDQAEQ_cjs.circle({ cx: 0, cy: 0, r, class: "lt-pid-equip" }),
|
|
4713
|
+
chunkHDKDQAEQ_cjs.polygon({
|
|
4714
|
+
points: `${r * 0.4},${-r * 0.9} ${r + 6},${-r * 0.9} ${r * 0.4},${0}`,
|
|
4715
|
+
class: "lt-pid-equip"
|
|
4716
|
+
}),
|
|
4717
|
+
chunkHDKDQAEQ_cjs.text(
|
|
4718
|
+
{ x: 0, y: r + 14, "text-anchor": "middle", class: "lt-pid-equip-tag" },
|
|
4719
|
+
label
|
|
4720
|
+
)
|
|
4721
|
+
]);
|
|
4722
|
+
}
|
|
4723
|
+
case "pump_pd": {
|
|
4724
|
+
const r = 22;
|
|
4725
|
+
return chunkHDKDQAEQ_cjs.group({}, [
|
|
4726
|
+
chunkHDKDQAEQ_cjs.circle({ cx: 0, cy: 0, r, class: "lt-pid-equip" }),
|
|
4727
|
+
chunkHDKDQAEQ_cjs.circle({ cx: -8, cy: 0, r: 6, class: "lt-pid-tray-line", fill: "none" }),
|
|
4728
|
+
chunkHDKDQAEQ_cjs.circle({ cx: 8, cy: 0, r: 6, class: "lt-pid-tray-line", fill: "none" }),
|
|
4729
|
+
chunkHDKDQAEQ_cjs.text(
|
|
4730
|
+
{ x: 0, y: r + 14, "text-anchor": "middle", class: "lt-pid-equip-tag" },
|
|
4731
|
+
label
|
|
4732
|
+
)
|
|
4733
|
+
]);
|
|
4734
|
+
}
|
|
4735
|
+
case "compressor": {
|
|
4736
|
+
return chunkHDKDQAEQ_cjs.group({}, [
|
|
4737
|
+
chunkHDKDQAEQ_cjs.polygon({
|
|
4738
|
+
points: "-45,-20 45,-12 45,12 -45,20",
|
|
4739
|
+
class: "lt-pid-equip"
|
|
4740
|
+
}),
|
|
4741
|
+
chunkHDKDQAEQ_cjs.text({ x: 0, y: 36, "text-anchor": "middle", class: "lt-pid-equip-tag" }, label)
|
|
4742
|
+
]);
|
|
4743
|
+
}
|
|
4744
|
+
case "blower": {
|
|
4745
|
+
const r = 22;
|
|
4746
|
+
return chunkHDKDQAEQ_cjs.group({}, [
|
|
4747
|
+
chunkHDKDQAEQ_cjs.circle({ cx: 0, cy: 0, r, class: "lt-pid-equip" }),
|
|
4748
|
+
chunkHDKDQAEQ_cjs.path({
|
|
4749
|
+
d: `M 0 0 L ${r * 0.8} ${-r * 0.5} M 0 0 L ${-r * 0.6} ${-r * 0.6} M 0 0 L 0 ${r * 0.8}`,
|
|
4750
|
+
class: "lt-pid-tray-line"
|
|
4751
|
+
}),
|
|
4752
|
+
chunkHDKDQAEQ_cjs.text({ x: 0, y: r + 14, "text-anchor": "middle", class: "lt-pid-equip-tag" }, label)
|
|
4753
|
+
]);
|
|
4754
|
+
}
|
|
4755
|
+
case "reactor_cstr": {
|
|
4756
|
+
const w = 90;
|
|
4757
|
+
const h = 110;
|
|
4758
|
+
const headH = 14;
|
|
4759
|
+
const top = -h / 2;
|
|
4760
|
+
const bot = h / 2;
|
|
4761
|
+
return chunkHDKDQAEQ_cjs.group({}, [
|
|
4762
|
+
chunkHDKDQAEQ_cjs.path({
|
|
4763
|
+
d: `M ${-w / 2} ${top + headH}
|
|
4764
|
+
A ${w / 2} ${headH} 0 0 1 ${w / 2} ${top + headH}
|
|
4765
|
+
L ${w / 2} ${bot - headH}
|
|
4766
|
+
A ${w / 2} ${headH} 0 0 1 ${-w / 2} ${bot - headH}
|
|
4767
|
+
Z`,
|
|
4768
|
+
class: "lt-pid-equip"
|
|
4769
|
+
}),
|
|
4770
|
+
// agitator shaft + paddle
|
|
4771
|
+
chunkHDKDQAEQ_cjs.line({ x1: 0, y1: top - 14, x2: 0, y2: 4, class: "lt-pid-tray-line" }),
|
|
4772
|
+
chunkHDKDQAEQ_cjs.rect({ x: -10, y: 4, width: 20, height: 4, class: "lt-pid-equip" }),
|
|
4773
|
+
chunkHDKDQAEQ_cjs.text(
|
|
4774
|
+
{ x: 0, y: bot + 14, "text-anchor": "middle", class: "lt-pid-equip-tag" },
|
|
4775
|
+
label
|
|
4776
|
+
)
|
|
4777
|
+
]);
|
|
4778
|
+
}
|
|
4779
|
+
case "reactor_pfr": {
|
|
4780
|
+
const w = 130;
|
|
4781
|
+
const h = 50;
|
|
4782
|
+
const headW = 12;
|
|
4783
|
+
const left = -w / 2;
|
|
4784
|
+
const right = w / 2;
|
|
4785
|
+
const dots = [];
|
|
4786
|
+
for (let xx = left + headW + 8; xx <= right - headW - 8; xx += 12) {
|
|
4787
|
+
for (let yy = -h / 2 + 12; yy <= h / 2 - 8; yy += 10) {
|
|
4788
|
+
dots.push(chunkHDKDQAEQ_cjs.circle({ cx: xx, cy: yy, r: 1.6, fill: STROKE_BLACK }));
|
|
4789
|
+
}
|
|
4790
|
+
}
|
|
4791
|
+
return chunkHDKDQAEQ_cjs.group({}, [
|
|
4792
|
+
chunkHDKDQAEQ_cjs.path({
|
|
4793
|
+
d: `M ${left + headW} ${-h / 2}
|
|
4794
|
+
L ${right - headW} ${-h / 2}
|
|
4795
|
+
A ${headW} ${h / 2} 0 0 1 ${right - headW} ${h / 2}
|
|
4796
|
+
L ${left + headW} ${h / 2}
|
|
4797
|
+
A ${headW} ${h / 2} 0 0 1 ${left + headW} ${-h / 2}
|
|
4798
|
+
Z`,
|
|
4799
|
+
class: "lt-pid-equip"
|
|
4800
|
+
}),
|
|
4801
|
+
...dots,
|
|
4802
|
+
chunkHDKDQAEQ_cjs.text({ x: 0, y: h / 2 + 14, "text-anchor": "middle", class: "lt-pid-equip-tag" }, label)
|
|
4803
|
+
]);
|
|
4804
|
+
}
|
|
4805
|
+
case "filter": {
|
|
4806
|
+
const w = 70;
|
|
4807
|
+
const h = 70;
|
|
4808
|
+
return chunkHDKDQAEQ_cjs.group({}, [
|
|
4809
|
+
chunkHDKDQAEQ_cjs.rect({ x: -w / 2, y: -h / 2, width: w, height: h, class: "lt-pid-equip" }),
|
|
4810
|
+
chunkHDKDQAEQ_cjs.line({ x1: -w / 2, y1: 0, x2: w / 2, y2: 0, class: "lt-pid-tray-line" }),
|
|
4811
|
+
chunkHDKDQAEQ_cjs.line({ x1: -w / 2 + 8, y1: -h / 2 + 8, x2: w / 2 - 8, y2: -8, class: "lt-pid-tray-line" }),
|
|
4812
|
+
chunkHDKDQAEQ_cjs.line({ x1: -w / 2 + 8, y1: 8, x2: w / 2 - 8, y2: h / 2 - 8, class: "lt-pid-tray-line" }),
|
|
4813
|
+
chunkHDKDQAEQ_cjs.text({ x: 0, y: h / 2 + 14, "text-anchor": "middle", class: "lt-pid-equip-tag" }, label)
|
|
4814
|
+
]);
|
|
4815
|
+
}
|
|
4816
|
+
case "cyclone": {
|
|
4817
|
+
const w = 70;
|
|
4818
|
+
const h = 100;
|
|
4819
|
+
const cyl = 30;
|
|
4820
|
+
return chunkHDKDQAEQ_cjs.group({}, [
|
|
4821
|
+
chunkHDKDQAEQ_cjs.path({
|
|
4822
|
+
d: `M ${-w / 2} ${-h / 2}
|
|
4823
|
+
L ${w / 2} ${-h / 2}
|
|
4824
|
+
L ${w / 2} ${-h / 2 + cyl}
|
|
4825
|
+
L 0 ${h / 2}
|
|
4826
|
+
L ${-w / 2} ${-h / 2 + cyl}
|
|
4827
|
+
Z`,
|
|
4828
|
+
class: "lt-pid-equip"
|
|
4829
|
+
}),
|
|
4830
|
+
chunkHDKDQAEQ_cjs.text({ x: 0, y: h / 2 + 14, "text-anchor": "middle", class: "lt-pid-equip-tag" }, label)
|
|
4831
|
+
]);
|
|
4832
|
+
}
|
|
4833
|
+
case "flare": {
|
|
4834
|
+
const w = 30;
|
|
4835
|
+
const h = 110;
|
|
4836
|
+
return chunkHDKDQAEQ_cjs.group({}, [
|
|
4837
|
+
chunkHDKDQAEQ_cjs.rect({ x: -w / 2, y: -h / 2, width: w, height: h, class: "lt-pid-equip" }),
|
|
4838
|
+
chunkHDKDQAEQ_cjs.polygon({
|
|
4839
|
+
points: `${ -8},${-h / 2 - 4} 0,${-h / 2 - 22} 8,${-h / 2 - 4}`,
|
|
4840
|
+
fill: "#ff7755",
|
|
4841
|
+
stroke: STROKE_BLACK
|
|
4842
|
+
}),
|
|
4843
|
+
chunkHDKDQAEQ_cjs.text({ x: 0, y: h / 2 + 14, "text-anchor": "middle", class: "lt-pid-equip-tag" }, label)
|
|
4844
|
+
]);
|
|
4845
|
+
}
|
|
4846
|
+
case "cooling_tower": {
|
|
4847
|
+
const w = 100;
|
|
4848
|
+
const h = 90;
|
|
4849
|
+
return chunkHDKDQAEQ_cjs.group({}, [
|
|
4850
|
+
chunkHDKDQAEQ_cjs.path({
|
|
4851
|
+
d: `M ${-w / 2} ${-h / 2}
|
|
4852
|
+
L ${w / 2} ${-h / 2}
|
|
4853
|
+
L ${w / 4} 0
|
|
4854
|
+
L ${w / 2} ${h / 2}
|
|
4855
|
+
L ${-w / 2} ${h / 2}
|
|
4856
|
+
L ${-w / 4} 0
|
|
4857
|
+
Z`,
|
|
4858
|
+
class: "lt-pid-equip"
|
|
4859
|
+
}),
|
|
4860
|
+
chunkHDKDQAEQ_cjs.text({ x: 0, y: h / 2 + 14, "text-anchor": "middle", class: "lt-pid-equip-tag" }, label)
|
|
4861
|
+
]);
|
|
4862
|
+
}
|
|
4863
|
+
// ── Valves ──────────────────────────────────────────
|
|
4864
|
+
case "valve_gate":
|
|
4865
|
+
return chunkHDKDQAEQ_cjs.group({}, [
|
|
4866
|
+
bowtie(),
|
|
4867
|
+
chunkHDKDQAEQ_cjs.text({ x: 0, y: 22, "text-anchor": "middle", class: "lt-pid-equip-tag" }, label)
|
|
4868
|
+
]);
|
|
4869
|
+
case "valve_ball":
|
|
4870
|
+
return chunkHDKDQAEQ_cjs.group({}, [
|
|
4871
|
+
bowtie(),
|
|
4872
|
+
chunkHDKDQAEQ_cjs.circle({ cx: 0, cy: 0, r: 4, fill: STROKE_BLACK }),
|
|
4873
|
+
chunkHDKDQAEQ_cjs.text({ x: 0, y: 22, "text-anchor": "middle", class: "lt-pid-equip-tag" }, label)
|
|
4874
|
+
]);
|
|
4875
|
+
case "valve_globe":
|
|
4876
|
+
return chunkHDKDQAEQ_cjs.group({}, [
|
|
4877
|
+
bowtie(),
|
|
4878
|
+
chunkHDKDQAEQ_cjs.circle({ cx: 0, cy: -5, r: 5, class: "lt-pid-valve-body", fill: FILL_WHITE }),
|
|
4879
|
+
chunkHDKDQAEQ_cjs.text({ x: 0, y: 22, "text-anchor": "middle", class: "lt-pid-equip-tag" }, label)
|
|
4880
|
+
]);
|
|
4881
|
+
case "valve_butterfly":
|
|
4882
|
+
return chunkHDKDQAEQ_cjs.group({}, [
|
|
4883
|
+
bowtie(),
|
|
4884
|
+
chunkHDKDQAEQ_cjs.line({ x1: 0, y1: -10, x2: 0, y2: 10, class: "lt-pid-tray-line" }),
|
|
4885
|
+
chunkHDKDQAEQ_cjs.text({ x: 0, y: 22, "text-anchor": "middle", class: "lt-pid-equip-tag" }, label)
|
|
4886
|
+
]);
|
|
4887
|
+
case "valve_check":
|
|
4888
|
+
return chunkHDKDQAEQ_cjs.group({}, [
|
|
4889
|
+
bowtie(),
|
|
4890
|
+
chunkHDKDQAEQ_cjs.path({ d: "M -10 -8 A 10 10 0 0 1 -10 8", class: "lt-pid-tray-line", fill: "none" }),
|
|
4891
|
+
chunkHDKDQAEQ_cjs.text({ x: 0, y: 22, "text-anchor": "middle", class: "lt-pid-equip-tag" }, label)
|
|
4892
|
+
]);
|
|
4893
|
+
case "valve_control":
|
|
4894
|
+
return chunkHDKDQAEQ_cjs.group({}, [
|
|
4895
|
+
bowtie(),
|
|
4896
|
+
// actuator: diaphragm
|
|
4897
|
+
chunkHDKDQAEQ_cjs.line({ x1: 0, y1: -11, x2: 0, y2: -22, class: "lt-pid-tray-line" }),
|
|
4898
|
+
chunkHDKDQAEQ_cjs.path({ d: "M -14 -22 A 14 8 0 0 1 14 -22 L -14 -22 Z", class: "lt-pid-equip" }),
|
|
4899
|
+
chunkHDKDQAEQ_cjs.text({ x: 0, y: 24, "text-anchor": "middle", class: "lt-pid-equip-tag" }, label)
|
|
4900
|
+
]);
|
|
4901
|
+
case "valve_psv":
|
|
4902
|
+
return chunkHDKDQAEQ_cjs.group({}, [
|
|
4903
|
+
bowtie(),
|
|
4904
|
+
// diagonal outlet (45°)
|
|
4905
|
+
chunkHDKDQAEQ_cjs.line({
|
|
4906
|
+
x1: 18,
|
|
4907
|
+
y1: -11,
|
|
4908
|
+
x2: 26,
|
|
4909
|
+
y2: -22,
|
|
4910
|
+
class: "lt-pid-process"
|
|
4911
|
+
}),
|
|
4912
|
+
// spring stack
|
|
4913
|
+
chunkHDKDQAEQ_cjs.path({
|
|
4914
|
+
d: "M -6 -11 L -10 -16 L -2 -20 L -10 -24 L -2 -28",
|
|
4915
|
+
class: "lt-pid-tray-line",
|
|
4916
|
+
fill: "none"
|
|
4917
|
+
}),
|
|
4918
|
+
chunkHDKDQAEQ_cjs.text({ x: 0, y: 24, "text-anchor": "middle", class: "lt-pid-equip-tag" }, label)
|
|
4919
|
+
]);
|
|
4920
|
+
default:
|
|
4921
|
+
return chunkHDKDQAEQ_cjs.group({}, [
|
|
4922
|
+
chunkHDKDQAEQ_cjs.rect({ x: -30, y: -20, width: 60, height: 40, class: "lt-pid-equip" }),
|
|
4923
|
+
chunkHDKDQAEQ_cjs.text({ x: 0, y: 4, "text-anchor": "middle", class: "lt-pid-equip-tag" }, label)
|
|
4924
|
+
]);
|
|
4925
|
+
}
|
|
4926
|
+
}
|
|
4927
|
+
function renderInstrument(category, letterCode, loopNumber) {
|
|
4928
|
+
const r = 14;
|
|
4929
|
+
const isComputer = category.endsWith("computer");
|
|
4930
|
+
const isPlc = category.endsWith("plc");
|
|
4931
|
+
const isShared = category.endsWith("shared");
|
|
4932
|
+
const isControlRoom = category.startsWith("cr_");
|
|
4933
|
+
const isLocal = category.startsWith("local_");
|
|
4934
|
+
const parts = [];
|
|
4935
|
+
if (isComputer) {
|
|
4936
|
+
parts.push(chunkHDKDQAEQ_cjs.circle({ cx: 0, cy: 0, r, class: "lt-inst-body" }));
|
|
4937
|
+
parts.push(
|
|
4938
|
+
chunkHDKDQAEQ_cjs.polygon({
|
|
4939
|
+
points: `0,${-r + 1} ${r - 1},0 0,${r - 1} ${ -13},0`,
|
|
4940
|
+
class: "lt-inst-body",
|
|
4941
|
+
fill: "none"
|
|
4942
|
+
})
|
|
4943
|
+
);
|
|
4944
|
+
} else if (isPlc) {
|
|
4945
|
+
parts.push(chunkHDKDQAEQ_cjs.circle({ cx: 0, cy: 0, r, class: "lt-inst-body" }));
|
|
4946
|
+
const side = r * Math.SQRT1_2 * 2 - 2;
|
|
4947
|
+
parts.push(
|
|
4948
|
+
chunkHDKDQAEQ_cjs.rect({
|
|
4949
|
+
x: -side / 2,
|
|
4950
|
+
y: -side / 2,
|
|
4951
|
+
width: side,
|
|
4952
|
+
height: side,
|
|
4953
|
+
class: "lt-inst-body",
|
|
4954
|
+
fill: "none"
|
|
4955
|
+
})
|
|
4956
|
+
);
|
|
4957
|
+
} else if (isShared) {
|
|
4958
|
+
parts.push(chunkHDKDQAEQ_cjs.circle({ cx: 0, cy: 0, r, class: "lt-inst-body" }));
|
|
4959
|
+
const hex = [];
|
|
4960
|
+
for (let i = 0; i < 6; i++) {
|
|
4961
|
+
const a = Math.PI / 3 * i - Math.PI / 2;
|
|
4962
|
+
hex.push(`${(r - 2) * Math.cos(a)},${(r - 2) * Math.sin(a)}`);
|
|
4963
|
+
}
|
|
4964
|
+
parts.push(
|
|
4965
|
+
chunkHDKDQAEQ_cjs.polygon({
|
|
4966
|
+
points: hex.join(" "),
|
|
4967
|
+
class: "lt-inst-body",
|
|
4968
|
+
fill: "none"
|
|
4969
|
+
})
|
|
4970
|
+
);
|
|
4971
|
+
} else {
|
|
4972
|
+
parts.push(chunkHDKDQAEQ_cjs.circle({ cx: 0, cy: 0, r, class: "lt-inst-body" }));
|
|
4973
|
+
}
|
|
4974
|
+
if (isControlRoom) {
|
|
4975
|
+
parts.push(chunkHDKDQAEQ_cjs.line({ x1: -r, y1: 0, x2: r, y2: 0, class: "lt-inst-cr-line" }));
|
|
4976
|
+
} else if (isLocal) {
|
|
4977
|
+
parts.push(chunkHDKDQAEQ_cjs.line({ x1: -r, y1: 0, x2: r, y2: 0, class: "lt-inst-local-line" }));
|
|
4978
|
+
}
|
|
4979
|
+
parts.push(
|
|
4980
|
+
chunkHDKDQAEQ_cjs.text(
|
|
4981
|
+
{
|
|
4982
|
+
x: 0,
|
|
4983
|
+
y: -3,
|
|
4984
|
+
"text-anchor": "middle",
|
|
4985
|
+
class: "lt-inst-tag"
|
|
4986
|
+
},
|
|
4987
|
+
letterCode
|
|
4988
|
+
)
|
|
4989
|
+
);
|
|
4990
|
+
parts.push(
|
|
4991
|
+
chunkHDKDQAEQ_cjs.text(
|
|
4992
|
+
{
|
|
4993
|
+
x: 0,
|
|
4994
|
+
y: 9,
|
|
4995
|
+
"text-anchor": "middle",
|
|
4996
|
+
class: "lt-inst-tag"
|
|
4997
|
+
},
|
|
4998
|
+
loopNumber
|
|
4999
|
+
)
|
|
5000
|
+
);
|
|
5001
|
+
return chunkHDKDQAEQ_cjs.group({ class: "lt-inst-symbol" }, parts);
|
|
5002
|
+
}
|
|
5003
|
+
|
|
5004
|
+
// src/diagrams/pid/layout.ts
|
|
5005
|
+
var PADDING = 30;
|
|
5006
|
+
var TITLE_AREA = 26;
|
|
5007
|
+
var EQUIP_GAP_X = 70;
|
|
5008
|
+
var INST_RADIUS = 14;
|
|
5009
|
+
var INST_OFFSET = 38;
|
|
5010
|
+
function defaultPort(direction, equip) {
|
|
5011
|
+
if (equip.equipType === "tank_atm" || equip.equipType === "tank_cone_roof") {
|
|
5012
|
+
return direction === "out" ? "bottom" : "top";
|
|
5013
|
+
}
|
|
5014
|
+
if (equip.equipType === "vessel_v" || equip.equipType === "column_tray" || equip.equipType === "column_packed") {
|
|
5015
|
+
return direction === "out" ? "bottom" : "top";
|
|
5016
|
+
}
|
|
5017
|
+
return direction === "out" ? "out" : "in";
|
|
5018
|
+
}
|
|
5019
|
+
function resolveSide(port) {
|
|
5020
|
+
if (port === "top" || port === "vapor_out" || port === "reflux") return "top";
|
|
5021
|
+
if (port === "bottom" || port === "liquid_out" || port === "bottom_return") return "bottom";
|
|
5022
|
+
if (port === "left" || port === "in" || port === "feed" || port === "tube_in" || port === "shell_in") return "left";
|
|
5023
|
+
return "right";
|
|
5024
|
+
}
|
|
5025
|
+
function getAnchor(layoutEq, port, fallback) {
|
|
5026
|
+
const ports = layoutEq.ports;
|
|
5027
|
+
let key = port;
|
|
5028
|
+
if (!key || !(key in ports)) {
|
|
5029
|
+
key = defaultPort(fallback, layoutEq.equip);
|
|
5030
|
+
}
|
|
5031
|
+
const p = ports[key] ?? ports.right ?? ports.out ?? ports.left ?? ports.in;
|
|
5032
|
+
if (!p) return { x: layoutEq.cx, y: layoutEq.cy, side: "right" };
|
|
5033
|
+
return { x: p.x, y: p.y, side: resolveSide(key ?? "right") };
|
|
5034
|
+
}
|
|
5035
|
+
function manhattanPath(fromX, fromY, fromSide, toX, toY, toSide) {
|
|
5036
|
+
const isHFrom = fromSide === "left" || fromSide === "right";
|
|
5037
|
+
const isHTo = toSide === "left" || toSide === "right";
|
|
5038
|
+
if (isHFrom && isHTo) {
|
|
5039
|
+
const midX = (fromX + toX) / 2;
|
|
5040
|
+
return {
|
|
5041
|
+
d: `M ${fromX} ${fromY} L ${midX} ${fromY} L ${midX} ${toY} L ${toX} ${toY}`,
|
|
5042
|
+
midX,
|
|
5043
|
+
midY: (fromY + toY) / 2
|
|
5044
|
+
};
|
|
5045
|
+
}
|
|
5046
|
+
if (!isHFrom && !isHTo) {
|
|
5047
|
+
const midY = (fromY + toY) / 2;
|
|
5048
|
+
return {
|
|
5049
|
+
d: `M ${fromX} ${fromY} L ${fromX} ${midY} L ${toX} ${midY} L ${toX} ${toY}`,
|
|
5050
|
+
midX: (fromX + toX) / 2,
|
|
5051
|
+
midY
|
|
5052
|
+
};
|
|
5053
|
+
}
|
|
5054
|
+
if (isHFrom) {
|
|
5055
|
+
return {
|
|
5056
|
+
d: `M ${fromX} ${fromY} L ${toX} ${fromY} L ${toX} ${toY}`,
|
|
5057
|
+
midX: toX,
|
|
5058
|
+
midY: (fromY + toY) / 2
|
|
5059
|
+
};
|
|
5060
|
+
}
|
|
5061
|
+
return {
|
|
5062
|
+
d: `M ${fromX} ${fromY} L ${fromX} ${toY} L ${toX} ${toY}`,
|
|
5063
|
+
midX: (fromX + toX) / 2,
|
|
5064
|
+
midY: toY
|
|
5065
|
+
};
|
|
5066
|
+
}
|
|
5067
|
+
function layoutPid(ast) {
|
|
5068
|
+
const equipment = [];
|
|
5069
|
+
const equipById = /* @__PURE__ */ new Map();
|
|
5070
|
+
const heights = ast.equipment.map((e) => GEOMETRY[e.equipType]?.height ?? 60);
|
|
5071
|
+
const maxH = Math.max(...heights, 0);
|
|
5072
|
+
const rowY = PADDING + TITLE_AREA + maxH / 2 + 30;
|
|
5073
|
+
let cursorX = PADDING + 40;
|
|
5074
|
+
for (const equip of ast.equipment) {
|
|
5075
|
+
const geo = GEOMETRY[equip.equipType] ?? { width: 60, height: 40, ports: {} };
|
|
5076
|
+
const cx = cursorX + geo.width / 2;
|
|
5077
|
+
const cy = rowY;
|
|
5078
|
+
const x = cx - geo.width / 2;
|
|
5079
|
+
const y = cy - geo.height / 2;
|
|
5080
|
+
const ports = {};
|
|
5081
|
+
for (const [name, p] of Object.entries(geo.ports)) {
|
|
5082
|
+
ports[name] = { x: cx + p.x, y: cy + p.y };
|
|
5083
|
+
}
|
|
5084
|
+
const layoutEq = {
|
|
5085
|
+
equip,
|
|
5086
|
+
x,
|
|
5087
|
+
y,
|
|
5088
|
+
width: geo.width,
|
|
5089
|
+
height: geo.height,
|
|
5090
|
+
cx,
|
|
5091
|
+
cy,
|
|
5092
|
+
ports
|
|
5093
|
+
};
|
|
5094
|
+
equipment.push(layoutEq);
|
|
5095
|
+
equipById.set(equip.id, layoutEq);
|
|
5096
|
+
cursorX += geo.width + EQUIP_GAP_X;
|
|
5097
|
+
}
|
|
5098
|
+
const instruments = [];
|
|
5099
|
+
const instById = /* @__PURE__ */ new Map();
|
|
5100
|
+
const crBandY = PADDING + TITLE_AREA + 40;
|
|
5101
|
+
let crSlot = 0;
|
|
5102
|
+
for (const inst of ast.instruments) {
|
|
5103
|
+
let cx = 0;
|
|
5104
|
+
let cy = 0;
|
|
5105
|
+
if (inst.category.startsWith("cr_")) {
|
|
5106
|
+
const tgt = inst.controls ?? inst.measures ?? "";
|
|
5107
|
+
const tgtEq = equipById.get(tgt);
|
|
5108
|
+
cx = tgtEq ? tgtEq.cx : PADDING + 80 + crSlot * (INST_RADIUS * 2 + 28);
|
|
5109
|
+
cy = crBandY;
|
|
5110
|
+
crSlot += 1;
|
|
5111
|
+
} else if (inst.category.startsWith("local_")) {
|
|
5112
|
+
cy = rowY + maxH / 2 + INST_OFFSET + INST_RADIUS;
|
|
5113
|
+
const tgt = inst.measures ?? inst.controls ?? "";
|
|
5114
|
+
const tgtEq = equipById.get(tgt);
|
|
5115
|
+
cx = tgtEq ? tgtEq.cx : PADDING + 80;
|
|
5116
|
+
} else {
|
|
5117
|
+
cy = rowY + maxH / 2 + INST_OFFSET;
|
|
5118
|
+
const tgt = inst.measures ?? inst.controls ?? "";
|
|
5119
|
+
const tgtEq = equipById.get(tgt);
|
|
5120
|
+
cx = tgtEq ? tgtEq.cx : PADDING + 80;
|
|
5121
|
+
}
|
|
5122
|
+
const lay = {
|
|
5123
|
+
inst,
|
|
5124
|
+
cx,
|
|
5125
|
+
cy,
|
|
5126
|
+
r: INST_RADIUS
|
|
5127
|
+
};
|
|
5128
|
+
instruments.push(lay);
|
|
5129
|
+
instById.set(inst.tag, lay);
|
|
5130
|
+
}
|
|
5131
|
+
const sameRow = (a, b) => Math.abs(a.cy - b.cy) < INST_RADIUS && Math.abs(a.cx - b.cx) < INST_RADIUS * 2 + 8;
|
|
5132
|
+
const sortedByX = [...instruments].sort((a, b) => a.cx - b.cx);
|
|
5133
|
+
for (let i = 1; i < sortedByX.length; i++) {
|
|
5134
|
+
const prev = sortedByX[i - 1];
|
|
5135
|
+
const cur = sortedByX[i];
|
|
5136
|
+
if (sameRow(prev, cur)) {
|
|
5137
|
+
cur.cx = prev.cx + INST_RADIUS * 2 + 14;
|
|
5138
|
+
}
|
|
5139
|
+
}
|
|
5140
|
+
const lines = [];
|
|
5141
|
+
for (const ln of ast.lines) {
|
|
5142
|
+
const path2 = routeLine(ln, equipById, instById);
|
|
5143
|
+
if (path2) lines.push(path2);
|
|
5144
|
+
}
|
|
5145
|
+
const allX = [];
|
|
5146
|
+
const allY = [];
|
|
5147
|
+
for (const e of equipment) {
|
|
5148
|
+
const tagPad = Math.max(0, ((e.equip.tag ?? e.equip.id).length * 6.6 - e.width) / 2 + 4);
|
|
5149
|
+
allX.push(e.x - tagPad, e.x + e.width + tagPad);
|
|
5150
|
+
allY.push(e.y, e.y + e.height + 30);
|
|
5151
|
+
}
|
|
5152
|
+
for (const i of instruments) {
|
|
5153
|
+
allX.push(i.cx - i.r, i.cx + i.r);
|
|
5154
|
+
allY.push(i.cy - i.r, i.cy + i.r + 14);
|
|
5155
|
+
}
|
|
5156
|
+
if (allX.length === 0) {
|
|
5157
|
+
allX.push(0, 400);
|
|
5158
|
+
allY.push(0, 200);
|
|
5159
|
+
}
|
|
5160
|
+
const maxX = Math.max(...allX);
|
|
5161
|
+
const maxY = Math.max(...allY);
|
|
5162
|
+
return {
|
|
5163
|
+
width: Math.max(maxX + PADDING, 400),
|
|
5164
|
+
height: Math.max(maxY + PADDING, 200),
|
|
5165
|
+
equipment,
|
|
5166
|
+
instruments,
|
|
5167
|
+
lines,
|
|
5168
|
+
title: ast.title
|
|
5169
|
+
};
|
|
5170
|
+
}
|
|
5171
|
+
function routeLine(ln, equipById, instById) {
|
|
5172
|
+
const fromAnchor = resolveAnchor(ln.from.id, ln.from.port, "out", equipById, instById);
|
|
5173
|
+
const toAnchor = resolveAnchor(ln.to.id, ln.to.port, "in", equipById, instById);
|
|
5174
|
+
if (!fromAnchor || !toAnchor) return void 0;
|
|
5175
|
+
const { d, midX, midY } = manhattanPath(
|
|
5176
|
+
fromAnchor.x,
|
|
5177
|
+
fromAnchor.y,
|
|
5178
|
+
fromAnchor.side,
|
|
5179
|
+
toAnchor.x,
|
|
5180
|
+
toAnchor.y,
|
|
5181
|
+
toAnchor.side
|
|
5182
|
+
);
|
|
5183
|
+
return {
|
|
5184
|
+
line: ln,
|
|
5185
|
+
path: d,
|
|
5186
|
+
midX,
|
|
5187
|
+
midY
|
|
5188
|
+
};
|
|
5189
|
+
}
|
|
5190
|
+
function resolveAnchor(id, port, fallback, equipById, instById) {
|
|
5191
|
+
const eq = equipById.get(id);
|
|
5192
|
+
if (eq) return getAnchor(eq, port, fallback);
|
|
5193
|
+
const inst = instById.get(id);
|
|
5194
|
+
if (inst) {
|
|
5195
|
+
return {
|
|
5196
|
+
x: inst.cx,
|
|
5197
|
+
y: inst.cy,
|
|
5198
|
+
side: fallback === "out" ? "right" : "left"
|
|
5199
|
+
};
|
|
5200
|
+
}
|
|
5201
|
+
return void 0;
|
|
5202
|
+
}
|
|
5203
|
+
|
|
5204
|
+
// src/diagrams/pid/renderer.ts
|
|
5205
|
+
var STYLE2 = `
|
|
5206
|
+
.lt-pid-equip { fill: #ffffff; stroke: #1d1d1d; stroke-width: 1.6; }
|
|
5207
|
+
.lt-pid-equip-tag { font: 600 11px system-ui, sans-serif; fill: #1d1d1d; }
|
|
5208
|
+
.lt-pid-tray-line { stroke: #555; stroke-width: 1; fill: none; }
|
|
5209
|
+
|
|
5210
|
+
.lt-pid-process { stroke: #1d1d1d; stroke-width: 2.6; fill: none; }
|
|
5211
|
+
.lt-pid-process-min { stroke: #1d1d1d; stroke-width: 1.5; fill: none; }
|
|
5212
|
+
.lt-pid-pneumatic { stroke: #1d1d1d; stroke-width: 1.4; fill: none; }
|
|
5213
|
+
.lt-pid-electric { stroke: #1d1d1d; stroke-width: 1.4; fill: none; stroke-dasharray: 6 4; }
|
|
5214
|
+
.lt-pid-hydraulic { stroke: #1d1d1d; stroke-width: 1.4; fill: none; stroke-dasharray: 10 4; }
|
|
5215
|
+
.lt-pid-capillary { stroke: #1d1d1d; stroke-width: 1.4; fill: none; stroke-dasharray: 1 5; stroke-linecap: round; }
|
|
5216
|
+
.lt-pid-software { stroke: #6a6a6a; stroke-width: 1.3; fill: none; stroke-dasharray: 2 4; }
|
|
5217
|
+
.lt-pid-mechanical { stroke: #1d1d1d; stroke-width: 1.4; fill: none; stroke-dasharray: 3 2 1 2; }
|
|
5218
|
+
|
|
5219
|
+
.lt-pid-pneumatic-tick { stroke: #1d1d1d; stroke-width: 1.2; }
|
|
5220
|
+
|
|
5221
|
+
.lt-inst-body { fill: #ffffff; stroke: #1d1d1d; stroke-width: 1.4; }
|
|
5222
|
+
.lt-inst-tag { font: 600 9.5px system-ui, sans-serif; fill: #1d1d1d; }
|
|
5223
|
+
.lt-inst-cr-line { stroke: #1d1d1d; stroke-width: 1; }
|
|
5224
|
+
.lt-inst-local-line { stroke: #1d1d1d; stroke-width: 1; stroke-dasharray: 2 2; }
|
|
5225
|
+
.lt-pid-valve-body { fill: #ffffff; stroke: #1d1d1d; stroke-width: 1.4; }
|
|
5226
|
+
|
|
5227
|
+
.lt-pid-line-tag-bg { fill: #ffffff; stroke: #1d1d1d; stroke-width: 0.6; }
|
|
5228
|
+
.lt-pid-line-tag-text { font: 9px ui-monospace, monospace; fill: #1d1d1d; }
|
|
5229
|
+
|
|
5230
|
+
.lt-pid-title { font: 600 14px system-ui, sans-serif; fill: #1d1d1d; }
|
|
5231
|
+
`;
|
|
5232
|
+
var ARROW_ID = "lt-pid-arrow";
|
|
5233
|
+
function lineClass(t) {
|
|
5234
|
+
return `lt-pid-${t.replace("_", "-")}`;
|
|
5235
|
+
}
|
|
5236
|
+
function renderLine(l) {
|
|
5237
|
+
const cls = lineClass(l.line.lineType);
|
|
5238
|
+
const parts = [
|
|
5239
|
+
chunkHDKDQAEQ_cjs.path({
|
|
5240
|
+
d: l.path,
|
|
5241
|
+
class: cls,
|
|
5242
|
+
"data-line-id": l.line.id,
|
|
5243
|
+
"data-service": l.line.service ?? ""
|
|
5244
|
+
})
|
|
5245
|
+
];
|
|
5246
|
+
if (l.line.lineType === "pneumatic") {
|
|
5247
|
+
parts.push(...pneumaticTicks(l.path));
|
|
5248
|
+
}
|
|
5249
|
+
if (l.line.tag) {
|
|
5250
|
+
const w = Math.max(28, l.line.tag.length * 6);
|
|
5251
|
+
parts.push(
|
|
5252
|
+
chunkHDKDQAEQ_cjs.rect({
|
|
5253
|
+
x: l.midX - w / 2,
|
|
5254
|
+
y: l.midY - 8,
|
|
5255
|
+
width: w,
|
|
5256
|
+
height: 14,
|
|
5257
|
+
rx: 2,
|
|
5258
|
+
ry: 2,
|
|
5259
|
+
class: "lt-pid-line-tag-bg"
|
|
5260
|
+
})
|
|
5261
|
+
);
|
|
5262
|
+
parts.push(
|
|
5263
|
+
chunkHDKDQAEQ_cjs.text(
|
|
5264
|
+
{
|
|
5265
|
+
x: l.midX,
|
|
5266
|
+
y: l.midY + 3,
|
|
5267
|
+
"text-anchor": "middle",
|
|
5268
|
+
class: "lt-pid-line-tag-text"
|
|
5269
|
+
},
|
|
5270
|
+
l.line.tag
|
|
5271
|
+
)
|
|
5272
|
+
);
|
|
5273
|
+
}
|
|
5274
|
+
return chunkHDKDQAEQ_cjs.group({ class: "lt-pid-line", "data-id": l.line.id }, parts);
|
|
5275
|
+
}
|
|
5276
|
+
function pneumaticTicks(d) {
|
|
5277
|
+
const tokens = d.match(/([MLC])\s+(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?)/g) ?? [];
|
|
5278
|
+
const points = [];
|
|
5279
|
+
for (const t of tokens) {
|
|
5280
|
+
const m = t.match(/[MLC]\s+(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?)/);
|
|
5281
|
+
if (!m) continue;
|
|
5282
|
+
points.push({ x: parseFloat(m[1]), y: parseFloat(m[2]) });
|
|
5283
|
+
}
|
|
5284
|
+
const ticks = [];
|
|
5285
|
+
for (let i = 1; i < points.length; i++) {
|
|
5286
|
+
const a = points[i - 1];
|
|
5287
|
+
const b = points[i];
|
|
5288
|
+
const dx = b.x - a.x;
|
|
5289
|
+
const dy = b.y - a.y;
|
|
5290
|
+
const len = Math.hypot(dx, dy);
|
|
5291
|
+
if (len < 12) continue;
|
|
5292
|
+
const ux = dx / len;
|
|
5293
|
+
const uy = dy / len;
|
|
5294
|
+
const px = -uy;
|
|
5295
|
+
const py = ux;
|
|
5296
|
+
for (let s = 18; s < len; s += 26) {
|
|
5297
|
+
const cx = a.x + ux * s;
|
|
5298
|
+
const cy = a.y + uy * s;
|
|
5299
|
+
ticks.push(
|
|
5300
|
+
chunkHDKDQAEQ_cjs.line({
|
|
5301
|
+
x1: cx + px * 4 - ux * 4,
|
|
5302
|
+
y1: cy + py * 4 - uy * 4,
|
|
5303
|
+
x2: cx - px * 4 + ux * 4,
|
|
5304
|
+
y2: cy - py * 4 + uy * 4,
|
|
5305
|
+
class: "lt-pid-pneumatic-tick"
|
|
5306
|
+
})
|
|
5307
|
+
);
|
|
5308
|
+
}
|
|
5309
|
+
}
|
|
5310
|
+
return ticks;
|
|
5311
|
+
}
|
|
5312
|
+
function renderPidAST(ast, _config) {
|
|
5313
|
+
const layout = layoutPid(ast);
|
|
5314
|
+
return renderLayout2(layout);
|
|
5315
|
+
}
|
|
5316
|
+
function renderLayout2(layout) {
|
|
5317
|
+
const equipNodes = layout.equipment.map((eq) => {
|
|
5318
|
+
const symbol = renderEquip(eq.equip.equipType, eq.equip.tag ?? eq.equip.id);
|
|
5319
|
+
return chunkHDKDQAEQ_cjs.group(
|
|
5320
|
+
{
|
|
5321
|
+
class: "lt-pid-equip-wrap",
|
|
5322
|
+
"data-id": eq.equip.id,
|
|
5323
|
+
"data-type": eq.equip.equipType,
|
|
5324
|
+
transform: `translate(${eq.cx} ${eq.cy})`
|
|
5325
|
+
},
|
|
5326
|
+
[symbol]
|
|
5327
|
+
);
|
|
5328
|
+
});
|
|
5329
|
+
const instNodes = layout.instruments.map((i) => {
|
|
5330
|
+
const { letter, number } = parseTag(i.inst.tag);
|
|
5331
|
+
return chunkHDKDQAEQ_cjs.group(
|
|
5332
|
+
{
|
|
5333
|
+
class: "lt-inst",
|
|
5334
|
+
"data-tag": i.inst.tag,
|
|
5335
|
+
"data-category": i.inst.category,
|
|
5336
|
+
transform: `translate(${i.cx} ${i.cy})`
|
|
5337
|
+
},
|
|
5338
|
+
[renderInstrument(i.inst.category, letter, number)]
|
|
5339
|
+
);
|
|
5340
|
+
});
|
|
5341
|
+
const autoSignals = [];
|
|
5342
|
+
for (const i of layout.instruments) {
|
|
5343
|
+
if (i.inst.measures) {
|
|
5344
|
+
const eq = layout.equipment.find((e) => e.equip.id === i.inst.measures);
|
|
5345
|
+
if (eq) {
|
|
5346
|
+
const ax = i.cx;
|
|
5347
|
+
const ay = i.cy;
|
|
5348
|
+
const bx = eq.cx;
|
|
5349
|
+
const by = eq.cy + eq.height / 2;
|
|
5350
|
+
autoSignals.push(
|
|
5351
|
+
chunkHDKDQAEQ_cjs.path({
|
|
5352
|
+
d: `M ${ax} ${ay} L ${ax} ${by + 8} L ${bx} ${by + 8} L ${bx} ${by}`,
|
|
5353
|
+
class: "lt-pid-electric"
|
|
5354
|
+
})
|
|
5355
|
+
);
|
|
5356
|
+
}
|
|
5357
|
+
}
|
|
5358
|
+
if (i.inst.controls) {
|
|
5359
|
+
const eq = layout.equipment.find((e) => e.equip.id === i.inst.controls);
|
|
5360
|
+
if (eq) {
|
|
5361
|
+
const ax = i.cx;
|
|
5362
|
+
const ay = i.cy + i.r;
|
|
5363
|
+
const bx = eq.cx;
|
|
5364
|
+
const by = eq.y;
|
|
5365
|
+
autoSignals.push(
|
|
5366
|
+
chunkHDKDQAEQ_cjs.path({
|
|
5367
|
+
d: `M ${ax} ${ay} L ${bx} ${ay} L ${bx} ${by}`,
|
|
5368
|
+
class: "lt-pid-pneumatic"
|
|
5369
|
+
})
|
|
5370
|
+
);
|
|
5371
|
+
}
|
|
5372
|
+
}
|
|
5373
|
+
}
|
|
5374
|
+
const titleNode = layout.title ? chunkHDKDQAEQ_cjs.text({ x: 16, y: 22, class: "lt-pid-title" }, layout.title) : "";
|
|
5375
|
+
return chunkHDKDQAEQ_cjs.svgRoot(
|
|
5376
|
+
{
|
|
5377
|
+
width: layout.width,
|
|
5378
|
+
height: layout.height,
|
|
5379
|
+
viewBox: `0 0 ${layout.width} ${layout.height}`,
|
|
5380
|
+
class: "lt-pid",
|
|
5381
|
+
"data-diagram-type": "pid"
|
|
5382
|
+
},
|
|
5383
|
+
[
|
|
5384
|
+
chunkHDKDQAEQ_cjs.el("title", {}, chunkHDKDQAEQ_cjs.escapeXml(`P&ID${layout.title ? " \u2014 " + layout.title : ""}`)),
|
|
5385
|
+
chunkHDKDQAEQ_cjs.el("desc", {}, "ISA-5.1 / ISO 10628 P&ID rendered by Schematex"),
|
|
5386
|
+
chunkHDKDQAEQ_cjs.defs([
|
|
5387
|
+
chunkHDKDQAEQ_cjs.el(
|
|
5388
|
+
"marker",
|
|
5389
|
+
{
|
|
5390
|
+
id: ARROW_ID,
|
|
5391
|
+
markerWidth: 10,
|
|
5392
|
+
markerHeight: 10,
|
|
5393
|
+
refX: 9,
|
|
5394
|
+
refY: 3,
|
|
5395
|
+
orient: "auto",
|
|
5396
|
+
markerUnits: "strokeWidth"
|
|
5397
|
+
},
|
|
5398
|
+
[chunkHDKDQAEQ_cjs.polygon({ points: "0,0 10,3 0,6", fill: "#1d1d1d" })]
|
|
5399
|
+
),
|
|
5400
|
+
chunkHDKDQAEQ_cjs.el("style", {}, STYLE2)
|
|
5401
|
+
]),
|
|
5402
|
+
titleNode,
|
|
5403
|
+
chunkHDKDQAEQ_cjs.group({ class: "lt-pid-equipment" }, equipNodes),
|
|
5404
|
+
chunkHDKDQAEQ_cjs.group({ class: "lt-pid-lines" }, layout.lines.map(renderLine)),
|
|
5405
|
+
chunkHDKDQAEQ_cjs.group({ class: "lt-pid-signals" }, autoSignals),
|
|
5406
|
+
chunkHDKDQAEQ_cjs.group({ class: "lt-pid-instruments" }, instNodes)
|
|
5407
|
+
]
|
|
5408
|
+
);
|
|
5409
|
+
}
|
|
5410
|
+
function parseTag(tag) {
|
|
5411
|
+
const idx = tag.indexOf("-");
|
|
5412
|
+
if (idx < 0) return { letter: tag, number: "" };
|
|
5413
|
+
return { letter: tag.slice(0, idx), number: tag.slice(idx + 1) };
|
|
5414
|
+
}
|
|
5415
|
+
|
|
5416
|
+
// src/diagrams/pid/index.ts
|
|
5417
|
+
var pid = {
|
|
5418
|
+
type: "pid",
|
|
5419
|
+
detect(text2) {
|
|
5420
|
+
return /^\s*pid\b/i.test(text2);
|
|
5421
|
+
},
|
|
5422
|
+
parse: parsePid,
|
|
5423
|
+
render(text2, config) {
|
|
5424
|
+
const ast = parsePid(text2);
|
|
5425
|
+
return renderPidAST(ast);
|
|
5426
|
+
}
|
|
5427
|
+
};
|
|
5428
|
+
|
|
2631
5429
|
// src/diagrams/mindmap/inline.ts
|
|
2632
5430
|
var RE_TASK = /^\[( |x|X)\]\s+(.*)$/;
|
|
2633
5431
|
function tokenizeInline(raw) {
|
|
@@ -2903,7 +5701,7 @@ function parseMindmap(text2) {
|
|
|
2903
5701
|
}
|
|
2904
5702
|
|
|
2905
5703
|
// src/diagrams/mindmap/layout.ts
|
|
2906
|
-
var
|
|
5704
|
+
var PADDING2 = 40;
|
|
2907
5705
|
var SIBLING_GAP = 18;
|
|
2908
5706
|
var MAIN_GAP = 44;
|
|
2909
5707
|
var UNDERLINE_GAP = 4;
|
|
@@ -3050,13 +5848,13 @@ function normalize(nodes) {
|
|
|
3050
5848
|
minY = Math.min(minY, n.y - lh / 2);
|
|
3051
5849
|
maxY = Math.max(maxY, n.y + lh / 2);
|
|
3052
5850
|
}
|
|
3053
|
-
const dx =
|
|
3054
|
-
const dy =
|
|
5851
|
+
const dx = PADDING2 - minX;
|
|
5852
|
+
const dy = PADDING2 - minY;
|
|
3055
5853
|
for (const n of nodes) {
|
|
3056
5854
|
n.x += dx;
|
|
3057
5855
|
n.y += dy;
|
|
3058
5856
|
}
|
|
3059
|
-
return { width: maxX - minX +
|
|
5857
|
+
return { width: maxX - minX + PADDING2 * 2, height: maxY - minY + PADDING2 * 2 };
|
|
3060
5858
|
}
|
|
3061
5859
|
function underlineY(n) {
|
|
3062
5860
|
return n.y + n.labelHeight / 2 - UNDERLINE_GAP / 2;
|
|
@@ -3184,7 +5982,7 @@ function paletteColor(theme, branchIndex) {
|
|
|
3184
5982
|
if (branchIndex < 0) return theme.centralFill;
|
|
3185
5983
|
return theme.branchPalette[branchIndex % theme.branchPalette.length];
|
|
3186
5984
|
}
|
|
3187
|
-
function
|
|
5985
|
+
function renderLine2(line2, leftX, cy, fontSize, fontFamily, fontWeight, theme) {
|
|
3188
5986
|
const baselineY = cy + fontSize * 0.35;
|
|
3189
5987
|
const tspans = [];
|
|
3190
5988
|
const decorations = [];
|
|
@@ -3299,7 +6097,7 @@ function tspan(attrs, content) {
|
|
|
3299
6097
|
}
|
|
3300
6098
|
return `<tspan ${pairs.join(" ")}>${chunkHDKDQAEQ_cjs.escapeXml(content)}</tspan>`;
|
|
3301
6099
|
}
|
|
3302
|
-
function
|
|
6100
|
+
function renderNode2(n, color, theme, fontFamily) {
|
|
3303
6101
|
const isRoot = n.node.depth === 0;
|
|
3304
6102
|
const isMain = n.node.depth === 1;
|
|
3305
6103
|
const fs = n.fontSize;
|
|
@@ -3314,7 +6112,7 @@ function renderNode(n, color, theme, fontFamily) {
|
|
|
3314
6112
|
for (let i = 0; i < lineCount; i++) {
|
|
3315
6113
|
const line2 = n.lines[i];
|
|
3316
6114
|
const cy = topY + (i + 0.5) * lh;
|
|
3317
|
-
const r =
|
|
6115
|
+
const r = renderLine2(line2, textLeft, cy, fs, fontFamily, weight, theme);
|
|
3318
6116
|
decorations.push(...r.decorations);
|
|
3319
6117
|
children.push(r.textElement);
|
|
3320
6118
|
}
|
|
@@ -3365,7 +6163,7 @@ function renderMindmapAST(ast, themeName = "default", fontFamily = "system-ui, -
|
|
|
3365
6163
|
const nodeSvgs = [];
|
|
3366
6164
|
for (const n of layout.nodes) {
|
|
3367
6165
|
const color = n.node.depth === 0 ? theme.centralFill : paletteColor(theme, n.branchIndex);
|
|
3368
|
-
nodeSvgs.push(
|
|
6166
|
+
nodeSvgs.push(renderNode2(n, color, theme, fontFamily));
|
|
3369
6167
|
}
|
|
3370
6168
|
const title2 = ast.title ?? tokensToPlainText(ast.root.tokens);
|
|
3371
6169
|
return chunkHDKDQAEQ_cjs.svgRoot(
|
|
@@ -4807,25 +7605,27 @@ var matrix = {
|
|
|
4807
7605
|
// src/core/api.ts
|
|
4808
7606
|
var plugins = [
|
|
4809
7607
|
chunkMJGDP3CS_cjs.genogram,
|
|
4810
|
-
|
|
7608
|
+
chunkNZH4GWE6_cjs.ecomap,
|
|
4811
7609
|
chunkB37IKTI7_cjs.pedigree,
|
|
4812
7610
|
chunkX7RPFTTR_cjs.phylo,
|
|
4813
7611
|
chunkCOLTVQWR_cjs.sociogram,
|
|
4814
7612
|
chunk2JDVJRR3_cjs.timing,
|
|
4815
7613
|
chunkWYFXOXVK_cjs.logic,
|
|
4816
|
-
|
|
7614
|
+
chunkK2SOC3XF_cjs.circuit,
|
|
4817
7615
|
chunkMCFQAUQV_cjs.blockdiagram,
|
|
4818
7616
|
chunkB6INLQBU_cjs.ladder,
|
|
4819
7617
|
chunk3YZ6FPQW_cjs.sld,
|
|
4820
7618
|
chunkZNOD4VZT_cjs.entity,
|
|
4821
7619
|
chunk5AEN2PLB_cjs.fishbone,
|
|
4822
7620
|
chunkQSQX77S2_cjs.venn,
|
|
4823
|
-
|
|
7621
|
+
chunk3FKS4KQK_cjs.flowchart,
|
|
4824
7622
|
mindmap,
|
|
4825
7623
|
matrix,
|
|
4826
7624
|
chunkA5D2IMOX_cjs.orgchart,
|
|
4827
7625
|
decisiontree,
|
|
4828
|
-
timeline
|
|
7626
|
+
timeline,
|
|
7627
|
+
state,
|
|
7628
|
+
pid
|
|
4829
7629
|
];
|
|
4830
7630
|
function detectPlugin(text2, config) {
|
|
4831
7631
|
if (config?.type) {
|
|
@@ -4859,7 +7659,9 @@ function render(text2, config) {
|
|
|
4859
7659
|
|
|
4860
7660
|
exports.decisiontree = decisiontree;
|
|
4861
7661
|
exports.parse = parse;
|
|
7662
|
+
exports.pid = pid;
|
|
4862
7663
|
exports.render = render;
|
|
7664
|
+
exports.state = state;
|
|
4863
7665
|
exports.timeline = timeline;
|
|
4864
|
-
//# sourceMappingURL=chunk-
|
|
4865
|
-
//# sourceMappingURL=chunk-
|
|
7666
|
+
//# sourceMappingURL=chunk-XTATRNUN.cjs.map
|
|
7667
|
+
//# sourceMappingURL=chunk-XTATRNUN.cjs.map
|