schematex 0.1.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/LICENSE +661 -0
- package/README.md +379 -0
- package/dist/chunk-2MQWZ2XY.cjs +453 -0
- package/dist/chunk-2MQWZ2XY.cjs.map +1 -0
- package/dist/chunk-2UKC6ZCY.cjs +1803 -0
- package/dist/chunk-2UKC6ZCY.cjs.map +1 -0
- package/dist/chunk-34X3ZJ6E.cjs +783 -0
- package/dist/chunk-34X3ZJ6E.cjs.map +1 -0
- package/dist/chunk-3FTUWAXK.cjs +1220 -0
- package/dist/chunk-3FTUWAXK.cjs.map +1 -0
- package/dist/chunk-3J7TFUOC.js +745 -0
- package/dist/chunk-3J7TFUOC.js.map +1 -0
- package/dist/chunk-47ZC6EMJ.js +1009 -0
- package/dist/chunk-47ZC6EMJ.js.map +1 -0
- package/dist/chunk-4DBRNOPA.cjs +750 -0
- package/dist/chunk-4DBRNOPA.cjs.map +1 -0
- package/dist/chunk-4G7ZIBHN.js +778 -0
- package/dist/chunk-4G7ZIBHN.js.map +1 -0
- package/dist/chunk-5C7DPDHQ.js +1321 -0
- package/dist/chunk-5C7DPDHQ.js.map +1 -0
- package/dist/chunk-ADOXGKAK.js +1251 -0
- package/dist/chunk-ADOXGKAK.js.map +1 -0
- package/dist/chunk-BE5HNDA5.cjs +874 -0
- package/dist/chunk-BE5HNDA5.cjs.map +1 -0
- package/dist/chunk-CZRM7LT7.js +889 -0
- package/dist/chunk-CZRM7LT7.js.map +1 -0
- package/dist/chunk-D4JTSPOL.js +1795 -0
- package/dist/chunk-D4JTSPOL.js.map +1 -0
- package/dist/chunk-DS47NTWZ.cjs +1034 -0
- package/dist/chunk-DS47NTWZ.cjs.map +1 -0
- package/dist/chunk-FDLZEKEB.js +449 -0
- package/dist/chunk-FDLZEKEB.js.map +1 -0
- package/dist/chunk-FGPTCDUT.cjs +1851 -0
- package/dist/chunk-FGPTCDUT.cjs.map +1 -0
- package/dist/chunk-HDKDQAEQ.cjs +86 -0
- package/dist/chunk-HDKDQAEQ.cjs.map +1 -0
- package/dist/chunk-IX554O5K.js +346 -0
- package/dist/chunk-IX554O5K.js.map +1 -0
- package/dist/chunk-KLJEK547.js +71 -0
- package/dist/chunk-KLJEK547.js.map +1 -0
- package/dist/chunk-LMFSHK45.js +1028 -0
- package/dist/chunk-LMFSHK45.js.map +1 -0
- package/dist/chunk-MDICUK6F.cjs +1258 -0
- package/dist/chunk-MDICUK6F.cjs.map +1 -0
- package/dist/chunk-N7KOXOMX.cjs +363 -0
- package/dist/chunk-N7KOXOMX.cjs.map +1 -0
- package/dist/chunk-NYCIK4SU.cjs +775 -0
- package/dist/chunk-NYCIK4SU.cjs.map +1 -0
- package/dist/chunk-PDPHRZZT.js +770 -0
- package/dist/chunk-PDPHRZZT.js.map +1 -0
- package/dist/chunk-ROFLJ74T.js +1212 -0
- package/dist/chunk-ROFLJ74T.js.map +1 -0
- package/dist/chunk-S6BK5DB6.cjs +845 -0
- package/dist/chunk-S6BK5DB6.cjs.map +1 -0
- package/dist/chunk-U4I37IBN.js +874 -0
- package/dist/chunk-U4I37IBN.js.map +1 -0
- package/dist/chunk-U5GGE6PJ.js +839 -0
- package/dist/chunk-U5GGE6PJ.js.map +1 -0
- package/dist/chunk-UHLYS3W5.cjs +1015 -0
- package/dist/chunk-UHLYS3W5.cjs.map +1 -0
- package/dist/chunk-URSKIHSY.cjs +881 -0
- package/dist/chunk-URSKIHSY.cjs.map +1 -0
- package/dist/chunk-V6WO7RK7.cjs +1056 -0
- package/dist/chunk-V6WO7RK7.cjs.map +1 -0
- package/dist/chunk-VFQCTXOX.js +869 -0
- package/dist/chunk-VFQCTXOX.js.map +1 -0
- package/dist/chunk-XQ52ICHU.cjs +895 -0
- package/dist/chunk-XQ52ICHU.cjs.map +1 -0
- package/dist/chunk-XX4BKS7Y.js +1051 -0
- package/dist/chunk-XX4BKS7Y.js.map +1 -0
- package/dist/chunk-XXU36667.js +1844 -0
- package/dist/chunk-XXU36667.js.map +1 -0
- package/dist/chunk-ZX7QKZK2.cjs +1326 -0
- package/dist/chunk-ZX7QKZK2.cjs.map +1 -0
- package/dist/diagrams/blockdiagram/index.cjs +25 -0
- package/dist/diagrams/blockdiagram/index.cjs.map +1 -0
- package/dist/diagrams/blockdiagram/index.d.cts +67 -0
- package/dist/diagrams/blockdiagram/index.d.ts +67 -0
- package/dist/diagrams/blockdiagram/index.js +4 -0
- package/dist/diagrams/blockdiagram/index.js.map +1 -0
- package/dist/diagrams/circuit/index.cjs +34 -0
- package/dist/diagrams/circuit/index.cjs.map +1 -0
- package/dist/diagrams/circuit/index.d.cts +138 -0
- package/dist/diagrams/circuit/index.d.ts +138 -0
- package/dist/diagrams/circuit/index.js +5 -0
- package/dist/diagrams/circuit/index.js.map +1 -0
- package/dist/diagrams/ecomap/index.cjs +30 -0
- package/dist/diagrams/ecomap/index.cjs.map +1 -0
- package/dist/diagrams/ecomap/index.d.cts +15 -0
- package/dist/diagrams/ecomap/index.d.ts +15 -0
- package/dist/diagrams/ecomap/index.js +5 -0
- package/dist/diagrams/ecomap/index.js.map +1 -0
- package/dist/diagrams/entity/index.cjs +26 -0
- package/dist/diagrams/entity/index.cjs.map +1 -0
- package/dist/diagrams/entity/index.d.cts +54 -0
- package/dist/diagrams/entity/index.d.ts +54 -0
- package/dist/diagrams/entity/index.js +5 -0
- package/dist/diagrams/entity/index.js.map +1 -0
- package/dist/diagrams/fishbone/index.cjs +34 -0
- package/dist/diagrams/fishbone/index.cjs.map +1 -0
- package/dist/diagrams/fishbone/index.d.cts +185 -0
- package/dist/diagrams/fishbone/index.d.ts +185 -0
- package/dist/diagrams/fishbone/index.js +5 -0
- package/dist/diagrams/fishbone/index.js.map +1 -0
- package/dist/diagrams/flowchart/index.cjs +34 -0
- package/dist/diagrams/flowchart/index.cjs.map +1 -0
- package/dist/diagrams/flowchart/index.d.cts +2 -0
- package/dist/diagrams/flowchart/index.d.ts +2 -0
- package/dist/diagrams/flowchart/index.js +5 -0
- package/dist/diagrams/flowchart/index.js.map +1 -0
- package/dist/diagrams/genogram/index.cjs +38 -0
- package/dist/diagrams/genogram/index.cjs.map +1 -0
- package/dist/diagrams/genogram/index.d.cts +20 -0
- package/dist/diagrams/genogram/index.d.ts +20 -0
- package/dist/diagrams/genogram/index.js +5 -0
- package/dist/diagrams/genogram/index.js.map +1 -0
- package/dist/diagrams/ladder/index.cjs +26 -0
- package/dist/diagrams/ladder/index.cjs.map +1 -0
- package/dist/diagrams/ladder/index.d.cts +49 -0
- package/dist/diagrams/ladder/index.d.ts +49 -0
- package/dist/diagrams/ladder/index.js +5 -0
- package/dist/diagrams/ladder/index.js.map +1 -0
- package/dist/diagrams/logic/index.cjs +26 -0
- package/dist/diagrams/logic/index.cjs.map +1 -0
- package/dist/diagrams/logic/index.d.cts +73 -0
- package/dist/diagrams/logic/index.d.ts +73 -0
- package/dist/diagrams/logic/index.js +5 -0
- package/dist/diagrams/logic/index.js.map +1 -0
- package/dist/diagrams/orgchart/index.cjs +30 -0
- package/dist/diagrams/orgchart/index.cjs.map +1 -0
- package/dist/diagrams/orgchart/index.d.cts +100 -0
- package/dist/diagrams/orgchart/index.d.ts +100 -0
- package/dist/diagrams/orgchart/index.js +5 -0
- package/dist/diagrams/orgchart/index.js.map +1 -0
- package/dist/diagrams/pedigree/index.cjs +30 -0
- package/dist/diagrams/pedigree/index.cjs.map +1 -0
- package/dist/diagrams/pedigree/index.d.cts +15 -0
- package/dist/diagrams/pedigree/index.d.ts +15 -0
- package/dist/diagrams/pedigree/index.js +5 -0
- package/dist/diagrams/pedigree/index.js.map +1 -0
- package/dist/diagrams/phylo/index.cjs +30 -0
- package/dist/diagrams/phylo/index.cjs.map +1 -0
- package/dist/diagrams/phylo/index.d.cts +32 -0
- package/dist/diagrams/phylo/index.d.ts +32 -0
- package/dist/diagrams/phylo/index.js +5 -0
- package/dist/diagrams/phylo/index.js.map +1 -0
- package/dist/diagrams/sld/index.cjs +26 -0
- package/dist/diagrams/sld/index.cjs.map +1 -0
- package/dist/diagrams/sld/index.d.cts +58 -0
- package/dist/diagrams/sld/index.d.ts +58 -0
- package/dist/diagrams/sld/index.js +5 -0
- package/dist/diagrams/sld/index.js.map +1 -0
- package/dist/diagrams/sociogram/index.cjs +26 -0
- package/dist/diagrams/sociogram/index.cjs.map +1 -0
- package/dist/diagrams/sociogram/index.d.cts +76 -0
- package/dist/diagrams/sociogram/index.d.ts +76 -0
- package/dist/diagrams/sociogram/index.js +5 -0
- package/dist/diagrams/sociogram/index.js.map +1 -0
- package/dist/diagrams/timing/index.cjs +21 -0
- package/dist/diagrams/timing/index.cjs.map +1 -0
- package/dist/diagrams/timing/index.d.cts +9 -0
- package/dist/diagrams/timing/index.d.ts +9 -0
- package/dist/diagrams/timing/index.js +4 -0
- package/dist/diagrams/timing/index.js.map +1 -0
- package/dist/diagrams/venn/index.cjs +38 -0
- package/dist/diagrams/venn/index.cjs.map +1 -0
- package/dist/diagrams/venn/index.d.cts +69 -0
- package/dist/diagrams/venn/index.d.ts +69 -0
- package/dist/diagrams/venn/index.js +5 -0
- package/dist/diagrams/venn/index.js.map +1 -0
- package/dist/index-BSlza1YY.d.ts +150 -0
- package/dist/index-BXefHVce.d.cts +150 -0
- package/dist/index.cjs +2033 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +29 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.js +1944 -0
- package/dist/index.js.map +1 -0
- package/dist/types-DqfcYkcY.d.cts +741 -0
- package/dist/types-DqfcYkcY.d.ts +741 -0
- package/package.json +163 -0
|
@@ -0,0 +1,1321 @@
|
|
|
1
|
+
import { resolveIndustrialTheme } from './chunk-IX554O5K.js';
|
|
2
|
+
import { title, desc, el, defs, text, path, group, svgRoot } from './chunk-KLJEK547.js';
|
|
3
|
+
|
|
4
|
+
// src/diagrams/sld/parser.ts
|
|
5
|
+
var SLDParseError = class extends Error {
|
|
6
|
+
constructor(message) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.name = "SLDParseError";
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
var NODE_TYPES = /* @__PURE__ */ new Set([
|
|
12
|
+
"utility",
|
|
13
|
+
"generator",
|
|
14
|
+
"solar",
|
|
15
|
+
"wind",
|
|
16
|
+
"ups",
|
|
17
|
+
"transformer",
|
|
18
|
+
"transformer_dy",
|
|
19
|
+
"transformer_yd",
|
|
20
|
+
"transformer_yy",
|
|
21
|
+
"transformer_dd",
|
|
22
|
+
"autotransformer",
|
|
23
|
+
"transformer_3winding",
|
|
24
|
+
"bus",
|
|
25
|
+
"bus_tie",
|
|
26
|
+
"hub",
|
|
27
|
+
"breaker",
|
|
28
|
+
"breaker_vacuum",
|
|
29
|
+
"switch",
|
|
30
|
+
"switch_load",
|
|
31
|
+
"ground_switch",
|
|
32
|
+
"ats",
|
|
33
|
+
"recloser",
|
|
34
|
+
"sectionalizer",
|
|
35
|
+
"fuse",
|
|
36
|
+
"fuse_cl",
|
|
37
|
+
"ct",
|
|
38
|
+
"pt",
|
|
39
|
+
"relay",
|
|
40
|
+
"surge_arrester",
|
|
41
|
+
"ground_fault",
|
|
42
|
+
"motor",
|
|
43
|
+
"load",
|
|
44
|
+
"capacitor_bank",
|
|
45
|
+
"harmonic_filter",
|
|
46
|
+
"vfd",
|
|
47
|
+
"watthour_meter",
|
|
48
|
+
"demand_meter"
|
|
49
|
+
]);
|
|
50
|
+
function stripComment(s) {
|
|
51
|
+
let out = "";
|
|
52
|
+
let inQuote = false;
|
|
53
|
+
for (const ch of s) {
|
|
54
|
+
if (ch === '"') inQuote = !inQuote;
|
|
55
|
+
if (ch === "#" && !inQuote) break;
|
|
56
|
+
out += ch;
|
|
57
|
+
}
|
|
58
|
+
return out;
|
|
59
|
+
}
|
|
60
|
+
function stripQuotes(v) {
|
|
61
|
+
const t = v.trim();
|
|
62
|
+
if (t.length >= 2 && t.startsWith('"') && t.endsWith('"')) {
|
|
63
|
+
return t.slice(1, -1);
|
|
64
|
+
}
|
|
65
|
+
return t;
|
|
66
|
+
}
|
|
67
|
+
function splitAttrs(inside) {
|
|
68
|
+
const parts = [];
|
|
69
|
+
let cur = "";
|
|
70
|
+
let inQuote = false;
|
|
71
|
+
for (const ch of inside) {
|
|
72
|
+
if (ch === '"') inQuote = !inQuote;
|
|
73
|
+
if (ch === "," && !inQuote) {
|
|
74
|
+
parts.push(cur);
|
|
75
|
+
cur = "";
|
|
76
|
+
} else {
|
|
77
|
+
cur += ch;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (cur.trim()) parts.push(cur);
|
|
81
|
+
const out = [];
|
|
82
|
+
for (const p of parts) {
|
|
83
|
+
const s = p.trim();
|
|
84
|
+
if (!s) continue;
|
|
85
|
+
const colon = s.indexOf(":");
|
|
86
|
+
if (colon < 0) {
|
|
87
|
+
throw new SLDParseError(`Invalid attribute "${s}" (missing ":")`);
|
|
88
|
+
}
|
|
89
|
+
const k = s.slice(0, colon).trim();
|
|
90
|
+
const v = stripQuotes(s.slice(colon + 1));
|
|
91
|
+
out.push([k, v]);
|
|
92
|
+
}
|
|
93
|
+
return out;
|
|
94
|
+
}
|
|
95
|
+
function applyAttrs(node, attrs) {
|
|
96
|
+
for (const [k, v] of attrs) {
|
|
97
|
+
const key = k.toLowerCase();
|
|
98
|
+
if (key === "label") node.label = v;
|
|
99
|
+
else if (key === "voltage") node.voltage = v;
|
|
100
|
+
else if (key === "rating") node.rating = v;
|
|
101
|
+
else if (key === "device") node.deviceNumber = v;
|
|
102
|
+
else {
|
|
103
|
+
if (!node.nameplate) node.nameplate = {};
|
|
104
|
+
node.nameplate[k] = v;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
function joinBrackets(lines) {
|
|
109
|
+
const out = [];
|
|
110
|
+
let buf = "";
|
|
111
|
+
let depth = 0;
|
|
112
|
+
for (const raw of lines) {
|
|
113
|
+
const line = stripComment(raw);
|
|
114
|
+
if (!line.trim() && depth === 0) {
|
|
115
|
+
if (buf) {
|
|
116
|
+
out.push(buf);
|
|
117
|
+
buf = "";
|
|
118
|
+
}
|
|
119
|
+
out.push("");
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
for (const ch of line) {
|
|
123
|
+
if (ch === "[") depth++;
|
|
124
|
+
else if (ch === "]") depth = Math.max(0, depth - 1);
|
|
125
|
+
}
|
|
126
|
+
buf = buf ? buf + " " + line.trim() : line;
|
|
127
|
+
if (depth === 0) {
|
|
128
|
+
out.push(buf);
|
|
129
|
+
buf = "";
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
if (buf) out.push(buf);
|
|
133
|
+
return out;
|
|
134
|
+
}
|
|
135
|
+
function parseSLDDSL(text2) {
|
|
136
|
+
const rawLines = text2.split("\n").map((l) => l.replace(/\r$/, ""));
|
|
137
|
+
const lines = joinBrackets(rawLines);
|
|
138
|
+
let title2;
|
|
139
|
+
const nodes = [];
|
|
140
|
+
const nodeMap = /* @__PURE__ */ new Map();
|
|
141
|
+
const connections = [];
|
|
142
|
+
for (let i = 0; i < lines.length; i++) {
|
|
143
|
+
const raw = lines[i];
|
|
144
|
+
const line = raw.trim();
|
|
145
|
+
if (!line) continue;
|
|
146
|
+
if (/^sld\b/i.test(line)) {
|
|
147
|
+
const m = line.match(/"([^"]*)"/);
|
|
148
|
+
if (m) title2 = m[1];
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
const connMatch = line.match(
|
|
152
|
+
/^([A-Za-z][A-Za-z0-9_\-]*)\s*->\s*([A-Za-z][A-Za-z0-9_\-]*)(?:\s*\[([^\]]*)\])?\s*$/
|
|
153
|
+
);
|
|
154
|
+
if (connMatch) {
|
|
155
|
+
const from = connMatch[1];
|
|
156
|
+
const to = connMatch[2];
|
|
157
|
+
const c = { from, to };
|
|
158
|
+
if (connMatch[3]) {
|
|
159
|
+
for (const [k, v] of splitAttrs(connMatch[3])) {
|
|
160
|
+
const key = k.toLowerCase();
|
|
161
|
+
if (key === "cable") c.cable = v;
|
|
162
|
+
else if (key === "label") c.label = v;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
connections.push(c);
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
const nodeMatch = line.match(
|
|
169
|
+
/^([A-Za-z][A-Za-z0-9_\-]*)\s*=\s*([a-zA-Z_][a-zA-Z0-9_]*)(?:\s*\[([^\]]*)\])?\s*$/
|
|
170
|
+
);
|
|
171
|
+
if (nodeMatch) {
|
|
172
|
+
const id = nodeMatch[1];
|
|
173
|
+
const nodeType = nodeMatch[2];
|
|
174
|
+
if (!NODE_TYPES.has(nodeType)) {
|
|
175
|
+
throw new SLDParseError(
|
|
176
|
+
`Unknown node type "${nodeType}" for "${id}" (line: ${line})`
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
if (nodeMap.has(id)) {
|
|
180
|
+
throw new SLDParseError(`Duplicate node id "${id}"`);
|
|
181
|
+
}
|
|
182
|
+
const node = { id, nodeType };
|
|
183
|
+
if (nodeMatch[3]) {
|
|
184
|
+
applyAttrs(node, splitAttrs(nodeMatch[3]));
|
|
185
|
+
}
|
|
186
|
+
nodes.push(node);
|
|
187
|
+
nodeMap.set(id, node);
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
throw new SLDParseError(`Cannot parse line: ${line}`);
|
|
191
|
+
}
|
|
192
|
+
for (const c of connections) {
|
|
193
|
+
if (!nodeMap.has(c.from)) {
|
|
194
|
+
throw new SLDParseError(`Connection references unknown node "${c.from}"`);
|
|
195
|
+
}
|
|
196
|
+
if (!nodeMap.has(c.to)) {
|
|
197
|
+
throw new SLDParseError(`Connection references unknown node "${c.to}"`);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
if (nodes.length === 0) {
|
|
201
|
+
throw new SLDParseError("SLD diagram has no nodes");
|
|
202
|
+
}
|
|
203
|
+
return { type: "sld", title: title2, nodes, connections };
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// src/diagrams/sld/symbols.ts
|
|
207
|
+
var DEFAULT_GEOMETRY = {
|
|
208
|
+
halfWidth: 20,
|
|
209
|
+
topY: -20,
|
|
210
|
+
bottomY: 20
|
|
211
|
+
};
|
|
212
|
+
function geometryFor(type) {
|
|
213
|
+
switch (type) {
|
|
214
|
+
case "utility":
|
|
215
|
+
case "generator":
|
|
216
|
+
case "solar":
|
|
217
|
+
case "wind":
|
|
218
|
+
return { halfWidth: 18, topY: -24, bottomY: 18 };
|
|
219
|
+
case "transformer":
|
|
220
|
+
case "transformer_dy":
|
|
221
|
+
case "transformer_yd":
|
|
222
|
+
case "transformer_yy":
|
|
223
|
+
case "transformer_dd":
|
|
224
|
+
case "autotransformer":
|
|
225
|
+
case "transformer_3winding":
|
|
226
|
+
return { halfWidth: 22, topY: -24, bottomY: 24 };
|
|
227
|
+
case "breaker":
|
|
228
|
+
case "breaker_vacuum":
|
|
229
|
+
case "recloser":
|
|
230
|
+
case "switch":
|
|
231
|
+
case "switch_load":
|
|
232
|
+
case "ground_switch":
|
|
233
|
+
case "sectionalizer":
|
|
234
|
+
return { halfWidth: 18, topY: -18, bottomY: 18 };
|
|
235
|
+
case "fuse":
|
|
236
|
+
case "fuse_cl":
|
|
237
|
+
return { halfWidth: 14, topY: -18, bottomY: 18 };
|
|
238
|
+
case "motor":
|
|
239
|
+
return { halfWidth: 16, topY: -16, bottomY: 22 };
|
|
240
|
+
case "load":
|
|
241
|
+
case "capacitor_bank":
|
|
242
|
+
case "harmonic_filter":
|
|
243
|
+
return { halfWidth: 20, topY: -14, bottomY: 14 };
|
|
244
|
+
case "vfd":
|
|
245
|
+
case "ups":
|
|
246
|
+
return { halfWidth: 24, topY: -18, bottomY: 18 };
|
|
247
|
+
case "ats":
|
|
248
|
+
return { halfWidth: 22, topY: -18, bottomY: 18 };
|
|
249
|
+
case "ct":
|
|
250
|
+
case "pt":
|
|
251
|
+
return { halfWidth: 10, topY: -16, bottomY: 16 };
|
|
252
|
+
case "relay":
|
|
253
|
+
return { halfWidth: 12, topY: -12, bottomY: 12 };
|
|
254
|
+
case "surge_arrester":
|
|
255
|
+
return { halfWidth: 12, topY: -16, bottomY: 26 };
|
|
256
|
+
case "watthour_meter":
|
|
257
|
+
case "demand_meter":
|
|
258
|
+
case "ground_fault":
|
|
259
|
+
return { halfWidth: 14, topY: -14, bottomY: 14 };
|
|
260
|
+
case "bus":
|
|
261
|
+
return DEFAULT_GEOMETRY;
|
|
262
|
+
case "hub":
|
|
263
|
+
return { halfWidth: 52, topY: -20, bottomY: 20 };
|
|
264
|
+
case "bus_tie":
|
|
265
|
+
return { halfWidth: 16, topY: -10, bottomY: 10 };
|
|
266
|
+
default:
|
|
267
|
+
return DEFAULT_GEOMETRY;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
function lineEl(x1, y1, x2, y2, cls = "lt-sld-stroke") {
|
|
271
|
+
return el("line", { x1, y1, x2, y2, class: cls });
|
|
272
|
+
}
|
|
273
|
+
function utilitySymbol() {
|
|
274
|
+
return group({}, [
|
|
275
|
+
el("circle", { cx: 0, cy: 0, r: 16, class: "lt-sld-fill" }),
|
|
276
|
+
path({ d: "M -8 0 Q -4 -8 0 0 Q 4 8 8 0", class: "lt-sld-stroke", fill: "none" }),
|
|
277
|
+
// lead wires in/out
|
|
278
|
+
lineEl(0, -24, 0, -16),
|
|
279
|
+
lineEl(0, 16, 0, 18)
|
|
280
|
+
]);
|
|
281
|
+
}
|
|
282
|
+
function generatorSymbol() {
|
|
283
|
+
return group({}, [
|
|
284
|
+
el("circle", { cx: 0, cy: 0, r: 16, class: "lt-sld-fill" }),
|
|
285
|
+
text({ x: 0, y: -2, class: "lt-sld-symbol-text", "text-anchor": "middle", "font-weight": "bold", "font-size": "14" }, "G"),
|
|
286
|
+
path({ d: "M -6 6 Q -3 1 0 6 Q 3 11 6 6", class: "lt-sld-stroke", fill: "none" }),
|
|
287
|
+
lineEl(0, -24, 0, -16),
|
|
288
|
+
lineEl(0, 16, 0, 18)
|
|
289
|
+
]);
|
|
290
|
+
}
|
|
291
|
+
function solarSymbol() {
|
|
292
|
+
return group({}, [
|
|
293
|
+
el("rect", { x: -18, y: -12, width: 36, height: 24, class: "lt-sld-fill" }),
|
|
294
|
+
lineEl(-18, -4, 18, -4),
|
|
295
|
+
lineEl(-18, 4, 18, 4),
|
|
296
|
+
lineEl(-6, -12, -6, 12),
|
|
297
|
+
lineEl(6, -12, 6, 12),
|
|
298
|
+
lineEl(0, 12, 0, 18)
|
|
299
|
+
]);
|
|
300
|
+
}
|
|
301
|
+
function windSymbol() {
|
|
302
|
+
return group({}, [
|
|
303
|
+
el("circle", { cx: 0, cy: 0, r: 6, class: "lt-sld-fill" }),
|
|
304
|
+
lineEl(0, -6, 0, -22),
|
|
305
|
+
path({ d: "M 0 -6 L 14 -2 L 0 0 Z", class: "lt-sld-fill-dark" }),
|
|
306
|
+
path({ d: "M 0 -6 L -10 8 L 0 2 Z", class: "lt-sld-fill-dark" }),
|
|
307
|
+
path({ d: "M 0 -6 L -6 -18 L 2 -6 Z", class: "lt-sld-fill-dark" }),
|
|
308
|
+
lineEl(0, 6, 0, 18)
|
|
309
|
+
]);
|
|
310
|
+
}
|
|
311
|
+
function upsSymbol() {
|
|
312
|
+
return group({}, [
|
|
313
|
+
el("rect", { x: -22, y: -16, width: 44, height: 32, class: "lt-sld-fill" }),
|
|
314
|
+
text({ x: 0, y: 4, class: "lt-sld-symbol-text", "text-anchor": "middle", "font-weight": "bold", "font-size": "11" }, "UPS")
|
|
315
|
+
]);
|
|
316
|
+
}
|
|
317
|
+
function transformerSymbol(type) {
|
|
318
|
+
const pieces = [];
|
|
319
|
+
pieces.push(
|
|
320
|
+
path({
|
|
321
|
+
d: "M -12 -18 A 4 4 0 0 1 -4 -18 A 4 4 0 0 1 4 -18 A 4 4 0 0 1 12 -18",
|
|
322
|
+
class: "lt-sld-stroke",
|
|
323
|
+
fill: "none"
|
|
324
|
+
})
|
|
325
|
+
);
|
|
326
|
+
pieces.push(lineEl(-14, -8, 14, -8));
|
|
327
|
+
pieces.push(lineEl(-14, -4, 14, -4));
|
|
328
|
+
pieces.push(
|
|
329
|
+
path({
|
|
330
|
+
d: "M -12 18 A 4 4 0 0 0 -4 18 A 4 4 0 0 0 4 18 A 4 4 0 0 0 12 18",
|
|
331
|
+
class: "lt-sld-stroke",
|
|
332
|
+
fill: "none"
|
|
333
|
+
})
|
|
334
|
+
);
|
|
335
|
+
pieces.push(el("circle", { cx: -10, cy: -14, r: 2, class: "lt-sld-dot" }));
|
|
336
|
+
pieces.push(el("circle", { cx: 10, cy: 14, r: 2, class: "lt-sld-dot" }));
|
|
337
|
+
pieces.push(lineEl(0, -24, 0, -22));
|
|
338
|
+
pieces.push(lineEl(0, 22, 0, 24));
|
|
339
|
+
const { primary, secondary } = windingGlyphs(type);
|
|
340
|
+
if (primary) pieces.push(text({ x: 20, y: -14, class: "lt-sld-wdg", "text-anchor": "start" }, primary));
|
|
341
|
+
if (secondary) pieces.push(text({ x: 20, y: 18, class: "lt-sld-wdg", "text-anchor": "start" }, secondary));
|
|
342
|
+
return group({}, pieces);
|
|
343
|
+
}
|
|
344
|
+
function windingGlyphs(type) {
|
|
345
|
+
switch (type) {
|
|
346
|
+
case "transformer_dy":
|
|
347
|
+
return { primary: "\u0394", secondary: "Y" };
|
|
348
|
+
case "transformer_yd":
|
|
349
|
+
return { primary: "Y", secondary: "\u0394" };
|
|
350
|
+
case "transformer_yy":
|
|
351
|
+
return { primary: "Y", secondary: "Y" };
|
|
352
|
+
case "transformer_dd":
|
|
353
|
+
return { primary: "\u0394", secondary: "\u0394" };
|
|
354
|
+
default:
|
|
355
|
+
return {};
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
function autotransformerSymbol() {
|
|
359
|
+
return group({}, [
|
|
360
|
+
path({
|
|
361
|
+
d: "M 0 -20 A 6 6 0 0 1 0 -10 A 6 6 0 0 1 0 0 A 6 6 0 0 1 0 10 A 6 6 0 0 1 0 20",
|
|
362
|
+
class: "lt-sld-stroke",
|
|
363
|
+
fill: "none"
|
|
364
|
+
}),
|
|
365
|
+
lineEl(6, 0, 14, 0),
|
|
366
|
+
lineEl(0, -24, 0, -20),
|
|
367
|
+
lineEl(0, 20, 0, 24)
|
|
368
|
+
]);
|
|
369
|
+
}
|
|
370
|
+
function threeWindingSymbol() {
|
|
371
|
+
return group({}, [
|
|
372
|
+
// top coil
|
|
373
|
+
path({ d: "M -10 -18 A 3 3 0 0 1 -4 -18 A 3 3 0 0 1 2 -18 A 3 3 0 0 1 8 -18", class: "lt-sld-stroke", fill: "none" }),
|
|
374
|
+
// left-bottom coil
|
|
375
|
+
path({ d: "M -18 6 A 3 3 0 0 1 -12 6 A 3 3 0 0 1 -6 6 A 3 3 0 0 1 0 6", class: "lt-sld-stroke", fill: "none" }),
|
|
376
|
+
// right-bottom coil
|
|
377
|
+
path({ d: "M 0 6 A 3 3 0 0 1 6 6 A 3 3 0 0 1 12 6 A 3 3 0 0 1 18 6", class: "lt-sld-stroke", fill: "none" }),
|
|
378
|
+
lineEl(-14, -8, 14, -8),
|
|
379
|
+
lineEl(0, -24, 0, -18),
|
|
380
|
+
lineEl(-9, 10, -9, 24),
|
|
381
|
+
lineEl(9, 10, 9, 24)
|
|
382
|
+
]);
|
|
383
|
+
}
|
|
384
|
+
function breakerSymbol() {
|
|
385
|
+
return group({}, [
|
|
386
|
+
lineEl(0, -14, 0, -10, "lt-sld-stroke"),
|
|
387
|
+
lineEl(0, 10, 0, 14, "lt-sld-stroke"),
|
|
388
|
+
el("line", { x1: -6, y1: 10, x2: 8, y2: -10, class: "lt-sld-stroke-thick" }),
|
|
389
|
+
path({ d: "M 8 -10 Q 14 -12 12 -18", class: "lt-sld-stroke", fill: "none" }),
|
|
390
|
+
lineEl(0, -18, 0, -14),
|
|
391
|
+
lineEl(0, 14, 0, 18)
|
|
392
|
+
]);
|
|
393
|
+
}
|
|
394
|
+
function vacuumBreakerSymbol() {
|
|
395
|
+
return group({}, [
|
|
396
|
+
el("ellipse", { cx: 0, cy: 0, rx: 10, ry: 14, class: "lt-sld-fill" }),
|
|
397
|
+
el("line", { x1: -6, y1: 10, x2: 8, y2: -10, class: "lt-sld-stroke-thick" }),
|
|
398
|
+
text({ x: -2, y: -4, class: "lt-sld-symbol-text", "text-anchor": "middle", "font-size": "8" }, "V"),
|
|
399
|
+
lineEl(0, -18, 0, -14),
|
|
400
|
+
lineEl(0, 14, 0, 18)
|
|
401
|
+
]);
|
|
402
|
+
}
|
|
403
|
+
function recloserSymbol() {
|
|
404
|
+
return group({}, [
|
|
405
|
+
el("line", { x1: -6, y1: 10, x2: 8, y2: -10, class: "lt-sld-stroke-thick" }),
|
|
406
|
+
path({ d: "M 8 -10 Q 14 -12 12 -18", class: "lt-sld-stroke", fill: "none" }),
|
|
407
|
+
path({ d: "M 14 -6 A 5 5 0 1 1 18 -4", class: "lt-sld-stroke", fill: "none" }),
|
|
408
|
+
el("polygon", { points: "18,-4 20,-8 15,-7", class: "lt-sld-dot" }),
|
|
409
|
+
lineEl(0, -18, 0, -14),
|
|
410
|
+
lineEl(0, 14, 0, 18)
|
|
411
|
+
]);
|
|
412
|
+
}
|
|
413
|
+
function switchSymbol(open = false) {
|
|
414
|
+
const pieces = [];
|
|
415
|
+
if (open) {
|
|
416
|
+
pieces.push(el("line", { x1: -6, y1: 10, x2: 10, y2: -8, class: "lt-sld-stroke-thick" }));
|
|
417
|
+
pieces.push(el("circle", { cx: 10, cy: -8, r: 2, class: "lt-sld-fill" }));
|
|
418
|
+
} else {
|
|
419
|
+
pieces.push(el("line", { x1: -6, y1: 10, x2: 8, y2: -10, class: "lt-sld-stroke-thick" }));
|
|
420
|
+
}
|
|
421
|
+
pieces.push(lineEl(0, -18, 0, -10));
|
|
422
|
+
pieces.push(lineEl(0, 10, 0, 18));
|
|
423
|
+
return group({}, pieces);
|
|
424
|
+
}
|
|
425
|
+
function loadSwitchSymbol() {
|
|
426
|
+
return group({}, [
|
|
427
|
+
el("line", { x1: -6, y1: 10, x2: 8, y2: -10, class: "lt-sld-stroke-thick" }),
|
|
428
|
+
el("rect", { x: 6, y: -14, width: 6, height: 6, class: "lt-sld-fill" }),
|
|
429
|
+
lineEl(0, -18, 0, -10),
|
|
430
|
+
lineEl(0, 10, 0, 18)
|
|
431
|
+
]);
|
|
432
|
+
}
|
|
433
|
+
function groundSwitchSymbol() {
|
|
434
|
+
return group({}, [
|
|
435
|
+
el("line", { x1: -6, y1: 0, x2: 8, y2: -14, class: "lt-sld-stroke-thick" }),
|
|
436
|
+
lineEl(0, -18, 0, -4),
|
|
437
|
+
// ground symbol
|
|
438
|
+
lineEl(-8, 6, 8, 6),
|
|
439
|
+
lineEl(-5, 10, 5, 10),
|
|
440
|
+
lineEl(-2, 14, 2, 14),
|
|
441
|
+
lineEl(0, 0, 0, 6)
|
|
442
|
+
]);
|
|
443
|
+
}
|
|
444
|
+
function sectionalizerSymbol() {
|
|
445
|
+
return group({}, [
|
|
446
|
+
el("line", { x1: -6, y1: 10, x2: 10, y2: -8, class: "lt-sld-stroke-thick" }),
|
|
447
|
+
el("circle", { cx: 10, cy: -8, r: 2, class: "lt-sld-fill" }),
|
|
448
|
+
text({ x: 14, y: -4, class: "lt-sld-wdg", "text-anchor": "start" }, "S"),
|
|
449
|
+
lineEl(0, -18, 0, -10),
|
|
450
|
+
lineEl(0, 10, 0, 18)
|
|
451
|
+
]);
|
|
452
|
+
}
|
|
453
|
+
function fuseSymbol() {
|
|
454
|
+
return group({}, [
|
|
455
|
+
el("rect", { x: -5, y: -10, width: 10, height: 20, class: "lt-sld-fill" }),
|
|
456
|
+
lineEl(0, -18, 0, -10),
|
|
457
|
+
lineEl(0, 10, 0, 18)
|
|
458
|
+
]);
|
|
459
|
+
}
|
|
460
|
+
function fuseCLSymbol() {
|
|
461
|
+
return group({}, [
|
|
462
|
+
el("rect", { x: -6, y: -12, width: 12, height: 24, class: "lt-sld-fill" }),
|
|
463
|
+
lineEl(-6, 0, 6, 0),
|
|
464
|
+
lineEl(0, -18, 0, -12),
|
|
465
|
+
lineEl(0, 12, 0, 18)
|
|
466
|
+
]);
|
|
467
|
+
}
|
|
468
|
+
function motorSymbol() {
|
|
469
|
+
return group({}, [
|
|
470
|
+
el("circle", { cx: 0, cy: 0, r: 14, class: "lt-sld-fill" }),
|
|
471
|
+
text({ x: 0, y: 5, class: "lt-sld-symbol-text", "text-anchor": "middle", "font-weight": "bold", "font-size": "13" }, "M"),
|
|
472
|
+
lineEl(0, -16, 0, -14),
|
|
473
|
+
// 3-phase dots at bottom
|
|
474
|
+
el("circle", { cx: -6, cy: 12, r: 1.5, class: "lt-sld-dot" }),
|
|
475
|
+
el("circle", { cx: 0, cy: 14, r: 1.5, class: "lt-sld-dot" }),
|
|
476
|
+
el("circle", { cx: 6, cy: 12, r: 1.5, class: "lt-sld-dot" })
|
|
477
|
+
]);
|
|
478
|
+
}
|
|
479
|
+
function loadSymbol() {
|
|
480
|
+
return group({}, [
|
|
481
|
+
el("rect", { x: -16, y: -12, width: 32, height: 24, class: "lt-sld-fill" })
|
|
482
|
+
]);
|
|
483
|
+
}
|
|
484
|
+
function capacitorBankSymbol() {
|
|
485
|
+
return group({}, [
|
|
486
|
+
lineEl(-10, -6, 10, -6, "lt-sld-stroke-thick"),
|
|
487
|
+
lineEl(-10, -2, 10, -2, "lt-sld-stroke-thick"),
|
|
488
|
+
lineEl(-10, 4, 10, 4, "lt-sld-stroke-thick"),
|
|
489
|
+
lineEl(-10, 8, 10, 8, "lt-sld-stroke-thick"),
|
|
490
|
+
lineEl(0, -14, 0, -6),
|
|
491
|
+
lineEl(0, 8, 0, 14)
|
|
492
|
+
]);
|
|
493
|
+
}
|
|
494
|
+
function harmonicFilterSymbol() {
|
|
495
|
+
return group({}, [
|
|
496
|
+
// L + C chained
|
|
497
|
+
path({ d: "M -14 -4 A 3 3 0 0 1 -8 -4 A 3 3 0 0 1 -2 -4 A 3 3 0 0 1 4 -4", class: "lt-sld-stroke", fill: "none" }),
|
|
498
|
+
lineEl(4, -8, 14, -8),
|
|
499
|
+
lineEl(4, 0, 14, 0),
|
|
500
|
+
lineEl(0, -14, 0, -4),
|
|
501
|
+
lineEl(0, 4, 0, 14)
|
|
502
|
+
]);
|
|
503
|
+
}
|
|
504
|
+
function vfdSymbol() {
|
|
505
|
+
return group({}, [
|
|
506
|
+
el("rect", { x: -22, y: -16, width: 44, height: 32, class: "lt-sld-fill" }),
|
|
507
|
+
text({ x: 0, y: -2, class: "lt-sld-symbol-text", "text-anchor": "middle", "font-weight": "bold", "font-size": "11" }, "VFD"),
|
|
508
|
+
path({ d: "M -10 8 Q -5 2 0 8 Q 5 14 10 8", class: "lt-sld-stroke", fill: "none" }),
|
|
509
|
+
lineEl(0, -18, 0, -16),
|
|
510
|
+
lineEl(0, 16, 0, 18)
|
|
511
|
+
]);
|
|
512
|
+
}
|
|
513
|
+
function atsSymbol() {
|
|
514
|
+
return group({}, [
|
|
515
|
+
el("rect", { x: -22, y: -16, width: 44, height: 32, class: "lt-sld-fill" }),
|
|
516
|
+
el("line", { x1: -14, y1: -8, x2: -2, y2: 6, class: "lt-sld-stroke-thick" }),
|
|
517
|
+
el("line", { x1: 14, y1: -8, x2: 2, y2: 6, class: "lt-sld-stroke-thick" }),
|
|
518
|
+
text({ x: 0, y: 14, class: "lt-sld-symbol-text", "text-anchor": "middle", "font-weight": "bold", "font-size": "9" }, "ATS"),
|
|
519
|
+
lineEl(-12, -18, -12, -16),
|
|
520
|
+
lineEl(12, -18, 12, -16),
|
|
521
|
+
lineEl(0, 16, 0, 18)
|
|
522
|
+
]);
|
|
523
|
+
}
|
|
524
|
+
function ctSymbol() {
|
|
525
|
+
return group({}, [
|
|
526
|
+
el("circle", { cx: 0, cy: 0, r: 7, class: "lt-sld-fill" }),
|
|
527
|
+
text({ x: 0, y: 3, class: "lt-sld-wdg", "text-anchor": "middle", "font-size": "7" }, "CT"),
|
|
528
|
+
lineEl(0, -16, 0, -7),
|
|
529
|
+
lineEl(0, 7, 0, 16)
|
|
530
|
+
]);
|
|
531
|
+
}
|
|
532
|
+
function ptSymbol() {
|
|
533
|
+
return group({}, [
|
|
534
|
+
el("circle", { cx: 0, cy: 0, r: 7, class: "lt-sld-fill" }),
|
|
535
|
+
text({ x: 0, y: 3, class: "lt-sld-wdg", "text-anchor": "middle", "font-size": "7" }, "PT"),
|
|
536
|
+
lineEl(0, -16, 0, -7),
|
|
537
|
+
lineEl(0, 7, 0, 16)
|
|
538
|
+
]);
|
|
539
|
+
}
|
|
540
|
+
function relaySymbol(deviceNumber) {
|
|
541
|
+
return group({}, [
|
|
542
|
+
el("circle", { cx: 0, cy: 0, r: 11, class: "lt-sld-fill" }),
|
|
543
|
+
text({ x: 0, y: 4, class: "lt-sld-wdg", "text-anchor": "middle", "font-size": "10" }, deviceNumber ?? "R")
|
|
544
|
+
]);
|
|
545
|
+
}
|
|
546
|
+
function surgeArresterSymbol() {
|
|
547
|
+
return group({}, [
|
|
548
|
+
el("rect", { x: -7, y: -6, width: 14, height: 14, class: "lt-sld-fill" }),
|
|
549
|
+
path({ d: "M -4 2 Q 0 -4 4 2", class: "lt-sld-stroke", fill: "none" }),
|
|
550
|
+
lineEl(0, -16, 0, -6),
|
|
551
|
+
lineEl(0, 8, 0, 14),
|
|
552
|
+
lineEl(-8, 14, 8, 14),
|
|
553
|
+
lineEl(-5, 18, 5, 18),
|
|
554
|
+
lineEl(-2, 22, 2, 22)
|
|
555
|
+
]);
|
|
556
|
+
}
|
|
557
|
+
function groundFaultSymbol() {
|
|
558
|
+
return group({}, [
|
|
559
|
+
el("circle", { cx: 0, cy: 0, r: 12, class: "lt-sld-fill" }),
|
|
560
|
+
text({ x: 0, y: 4, class: "lt-sld-wdg", "text-anchor": "middle", "font-size": "9" }, "GFI"),
|
|
561
|
+
lineEl(0, -14, 0, -12),
|
|
562
|
+
lineEl(0, 12, 0, 14)
|
|
563
|
+
]);
|
|
564
|
+
}
|
|
565
|
+
function hubSymbol(label) {
|
|
566
|
+
return group({}, [
|
|
567
|
+
el("rect", {
|
|
568
|
+
x: -50,
|
|
569
|
+
y: -18,
|
|
570
|
+
width: 100,
|
|
571
|
+
height: 36,
|
|
572
|
+
rx: 4,
|
|
573
|
+
ry: 4,
|
|
574
|
+
class: "lt-sld-fill",
|
|
575
|
+
"stroke-width": 2
|
|
576
|
+
}),
|
|
577
|
+
text(
|
|
578
|
+
{ x: 0, y: 4, class: "lt-sld-wdg", "text-anchor": "middle", "font-size": "11" },
|
|
579
|
+
label ?? "HUB"
|
|
580
|
+
),
|
|
581
|
+
lineEl(0, -20, 0, -18),
|
|
582
|
+
lineEl(0, 18, 0, 20),
|
|
583
|
+
// left/right lead stubs for lateral ports
|
|
584
|
+
lineEl(-50, 0, -54, 0),
|
|
585
|
+
lineEl(50, 0, 54, 0)
|
|
586
|
+
]);
|
|
587
|
+
}
|
|
588
|
+
function busTieSymbol() {
|
|
589
|
+
return group({}, [
|
|
590
|
+
lineEl(-16, 0, -4, 0),
|
|
591
|
+
lineEl(4, 0, 16, 0),
|
|
592
|
+
path({ d: "M -4 0 L 4 -6", class: "lt-sld-stroke-thick" }),
|
|
593
|
+
path({ d: "M -4 -6 Q 0 -10 4 -6", class: "lt-sld-stroke", fill: "none" })
|
|
594
|
+
]);
|
|
595
|
+
}
|
|
596
|
+
function meterSymbol(label) {
|
|
597
|
+
return group({}, [
|
|
598
|
+
el("circle", { cx: 0, cy: 0, r: 12, class: "lt-sld-fill" }),
|
|
599
|
+
text({ x: 0, y: 4, class: "lt-sld-wdg", "text-anchor": "middle", "font-size": "9" }, label),
|
|
600
|
+
lineEl(0, -14, 0, -12),
|
|
601
|
+
lineEl(0, 12, 0, 14)
|
|
602
|
+
]);
|
|
603
|
+
}
|
|
604
|
+
function renderSymbol(type, detail) {
|
|
605
|
+
switch (type) {
|
|
606
|
+
case "utility":
|
|
607
|
+
return utilitySymbol();
|
|
608
|
+
case "generator":
|
|
609
|
+
return generatorSymbol();
|
|
610
|
+
case "solar":
|
|
611
|
+
return solarSymbol();
|
|
612
|
+
case "wind":
|
|
613
|
+
return windSymbol();
|
|
614
|
+
case "ups":
|
|
615
|
+
return upsSymbol();
|
|
616
|
+
case "transformer":
|
|
617
|
+
case "transformer_dy":
|
|
618
|
+
case "transformer_yd":
|
|
619
|
+
case "transformer_yy":
|
|
620
|
+
case "transformer_dd":
|
|
621
|
+
return transformerSymbol(type);
|
|
622
|
+
case "autotransformer":
|
|
623
|
+
return autotransformerSymbol();
|
|
624
|
+
case "transformer_3winding":
|
|
625
|
+
return threeWindingSymbol();
|
|
626
|
+
case "breaker":
|
|
627
|
+
return breakerSymbol();
|
|
628
|
+
case "breaker_vacuum":
|
|
629
|
+
return vacuumBreakerSymbol();
|
|
630
|
+
case "recloser":
|
|
631
|
+
return recloserSymbol();
|
|
632
|
+
case "switch":
|
|
633
|
+
return switchSymbol(true);
|
|
634
|
+
case "switch_load":
|
|
635
|
+
return loadSwitchSymbol();
|
|
636
|
+
case "ground_switch":
|
|
637
|
+
return groundSwitchSymbol();
|
|
638
|
+
case "sectionalizer":
|
|
639
|
+
return sectionalizerSymbol();
|
|
640
|
+
case "fuse":
|
|
641
|
+
return fuseSymbol();
|
|
642
|
+
case "fuse_cl":
|
|
643
|
+
return fuseCLSymbol();
|
|
644
|
+
case "motor":
|
|
645
|
+
return motorSymbol();
|
|
646
|
+
case "load":
|
|
647
|
+
return loadSymbol();
|
|
648
|
+
case "capacitor_bank":
|
|
649
|
+
return capacitorBankSymbol();
|
|
650
|
+
case "harmonic_filter":
|
|
651
|
+
return harmonicFilterSymbol();
|
|
652
|
+
case "vfd":
|
|
653
|
+
return vfdSymbol();
|
|
654
|
+
case "ats":
|
|
655
|
+
return atsSymbol();
|
|
656
|
+
case "ct":
|
|
657
|
+
return ctSymbol();
|
|
658
|
+
case "pt":
|
|
659
|
+
return ptSymbol();
|
|
660
|
+
case "relay":
|
|
661
|
+
return relaySymbol(detail);
|
|
662
|
+
case "surge_arrester":
|
|
663
|
+
return surgeArresterSymbol();
|
|
664
|
+
case "ground_fault":
|
|
665
|
+
return groundFaultSymbol();
|
|
666
|
+
case "watthour_meter":
|
|
667
|
+
return meterSymbol("Wh");
|
|
668
|
+
case "demand_meter":
|
|
669
|
+
return meterSymbol("D");
|
|
670
|
+
case "bus":
|
|
671
|
+
return "";
|
|
672
|
+
case "hub":
|
|
673
|
+
return hubSymbol(detail);
|
|
674
|
+
case "bus_tie":
|
|
675
|
+
return busTieSymbol();
|
|
676
|
+
default:
|
|
677
|
+
return loadSymbol();
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
// src/diagrams/sld/layout.ts
|
|
682
|
+
var LEVEL_SPACING = 100;
|
|
683
|
+
var H_SPACING = 90;
|
|
684
|
+
var LEFT_PADDING = 80;
|
|
685
|
+
var TOP_PADDING = 40;
|
|
686
|
+
var BUS_OVERHANG = 20;
|
|
687
|
+
function computeLevels(ast) {
|
|
688
|
+
const levels = /* @__PURE__ */ new Map();
|
|
689
|
+
const inEdges = /* @__PURE__ */ new Map();
|
|
690
|
+
const outEdges = /* @__PURE__ */ new Map();
|
|
691
|
+
for (const n of ast.nodes) {
|
|
692
|
+
inEdges.set(n.id, []);
|
|
693
|
+
outEdges.set(n.id, []);
|
|
694
|
+
}
|
|
695
|
+
for (const c of ast.connections) {
|
|
696
|
+
inEdges.get(c.to)?.push(c);
|
|
697
|
+
outEdges.get(c.from)?.push(c);
|
|
698
|
+
}
|
|
699
|
+
const roots = ast.nodes.filter((n) => (inEdges.get(n.id) ?? []).length === 0);
|
|
700
|
+
for (const r of roots) levels.set(r.id, 0);
|
|
701
|
+
const typeById = /* @__PURE__ */ new Map();
|
|
702
|
+
for (const n of ast.nodes) typeById.set(n.id, n.nodeType);
|
|
703
|
+
const isTieEdge = (c) => typeById.get(c.from) === "bus_tie" || typeById.get(c.to) === "bus_tie";
|
|
704
|
+
const maxIter = ast.nodes.length + 2;
|
|
705
|
+
for (let iter = 0; iter < maxIter; iter++) {
|
|
706
|
+
let changed = false;
|
|
707
|
+
for (const c of ast.connections) {
|
|
708
|
+
if (isTieEdge(c)) continue;
|
|
709
|
+
const fromLvl = levels.get(c.from);
|
|
710
|
+
if (fromLvl === void 0) continue;
|
|
711
|
+
const want = fromLvl + 1;
|
|
712
|
+
const curr = levels.get(c.to);
|
|
713
|
+
if (curr === void 0 || want > curr) {
|
|
714
|
+
levels.set(c.to, want);
|
|
715
|
+
changed = true;
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
if (!changed) break;
|
|
719
|
+
}
|
|
720
|
+
for (let iter = 0; iter < maxIter; iter++) {
|
|
721
|
+
let changed = false;
|
|
722
|
+
for (const c of ast.connections) {
|
|
723
|
+
if (!isTieEdge(c)) continue;
|
|
724
|
+
const fromLvl = levels.get(c.from);
|
|
725
|
+
const toLvl = levels.get(c.to);
|
|
726
|
+
const shared = fromLvl ?? toLvl;
|
|
727
|
+
if (shared === void 0) continue;
|
|
728
|
+
if (fromLvl === void 0 || fromLvl !== shared) {
|
|
729
|
+
levels.set(c.from, shared);
|
|
730
|
+
changed = true;
|
|
731
|
+
}
|
|
732
|
+
if (toLvl === void 0 || toLvl !== shared) {
|
|
733
|
+
levels.set(c.to, shared);
|
|
734
|
+
changed = true;
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
if (!changed) break;
|
|
738
|
+
}
|
|
739
|
+
for (const n of ast.nodes) {
|
|
740
|
+
if (!levels.has(n.id)) levels.set(n.id, 0);
|
|
741
|
+
}
|
|
742
|
+
return levels;
|
|
743
|
+
}
|
|
744
|
+
function orderWithinLevel(ast, levels) {
|
|
745
|
+
const byLevel = /* @__PURE__ */ new Map();
|
|
746
|
+
for (const n of ast.nodes) {
|
|
747
|
+
const lvl = levels.get(n.id) ?? 0;
|
|
748
|
+
if (!byLevel.has(lvl)) byLevel.set(lvl, []);
|
|
749
|
+
byLevel.get(lvl).push(n.id);
|
|
750
|
+
}
|
|
751
|
+
const visited = /* @__PURE__ */ new Set();
|
|
752
|
+
const order = /* @__PURE__ */ new Map();
|
|
753
|
+
let idx = 0;
|
|
754
|
+
const adj = /* @__PURE__ */ new Map();
|
|
755
|
+
for (const n of ast.nodes) adj.set(n.id, []);
|
|
756
|
+
for (const c of ast.connections) adj.get(c.from)?.push(c.to);
|
|
757
|
+
function dfs(id) {
|
|
758
|
+
if (visited.has(id)) return;
|
|
759
|
+
visited.add(id);
|
|
760
|
+
order.set(id, idx++);
|
|
761
|
+
for (const child of adj.get(id) ?? []) dfs(child);
|
|
762
|
+
}
|
|
763
|
+
const inEdgeCount = /* @__PURE__ */ new Map();
|
|
764
|
+
for (const n of ast.nodes) inEdgeCount.set(n.id, 0);
|
|
765
|
+
for (const c of ast.connections) {
|
|
766
|
+
inEdgeCount.set(c.to, (inEdgeCount.get(c.to) ?? 0) + 1);
|
|
767
|
+
}
|
|
768
|
+
for (const n of ast.nodes) {
|
|
769
|
+
if ((inEdgeCount.get(n.id) ?? 0) === 0) dfs(n.id);
|
|
770
|
+
}
|
|
771
|
+
for (const n of ast.nodes) dfs(n.id);
|
|
772
|
+
for (const [lvl, ids] of byLevel.entries()) {
|
|
773
|
+
ids.sort((a, b) => (order.get(a) ?? 0) - (order.get(b) ?? 0));
|
|
774
|
+
byLevel.set(lvl, ids);
|
|
775
|
+
}
|
|
776
|
+
return byLevel;
|
|
777
|
+
}
|
|
778
|
+
function layoutSLD(ast) {
|
|
779
|
+
const levels = computeLevels(ast);
|
|
780
|
+
const byLevel = orderWithinLevel(ast, levels);
|
|
781
|
+
const nodeMap = /* @__PURE__ */ new Map();
|
|
782
|
+
for (const n of ast.nodes) nodeMap.set(n.id, n);
|
|
783
|
+
const layoutNodes = [];
|
|
784
|
+
const byIdLayout = /* @__PURE__ */ new Map();
|
|
785
|
+
const parents = /* @__PURE__ */ new Map();
|
|
786
|
+
const children = /* @__PURE__ */ new Map();
|
|
787
|
+
for (const n of ast.nodes) {
|
|
788
|
+
parents.set(n.id, []);
|
|
789
|
+
children.set(n.id, []);
|
|
790
|
+
}
|
|
791
|
+
for (const c of ast.connections) {
|
|
792
|
+
parents.get(c.to)?.push(c.from);
|
|
793
|
+
children.get(c.from)?.push(c.to);
|
|
794
|
+
}
|
|
795
|
+
const sortedLevels = Array.from(byLevel.keys()).sort((a, b) => a - b);
|
|
796
|
+
const maxLevel = sortedLevels.length ? sortedLevels[sortedLevels.length - 1] : 0;
|
|
797
|
+
let nextX = LEFT_PADDING;
|
|
798
|
+
function placeNode(id) {
|
|
799
|
+
const existing = byIdLayout.get(id);
|
|
800
|
+
if (existing) return existing;
|
|
801
|
+
const node = nodeMap.get(id);
|
|
802
|
+
const lvl = levels.get(id) ?? 0;
|
|
803
|
+
const geom = geometryFor(node.nodeType);
|
|
804
|
+
const y = TOP_PADDING + lvl * LEVEL_SPACING;
|
|
805
|
+
const ln = {
|
|
806
|
+
node,
|
|
807
|
+
nodeType: node.nodeType,
|
|
808
|
+
x: 0,
|
|
809
|
+
y,
|
|
810
|
+
topY: y + geom.topY,
|
|
811
|
+
bottomY: y + geom.bottomY,
|
|
812
|
+
level: lvl,
|
|
813
|
+
halfWidth: geom.halfWidth
|
|
814
|
+
};
|
|
815
|
+
byIdLayout.set(id, ln);
|
|
816
|
+
layoutNodes.push(ln);
|
|
817
|
+
return ln;
|
|
818
|
+
}
|
|
819
|
+
for (const lvl of sortedLevels) {
|
|
820
|
+
for (const id of byLevel.get(lvl)) {
|
|
821
|
+
const ln = placeNode(id);
|
|
822
|
+
if (ln.nodeType === "bus") {
|
|
823
|
+
ln.x = nextX;
|
|
824
|
+
} else {
|
|
825
|
+
ln.x = nextX;
|
|
826
|
+
nextX += H_SPACING;
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
for (let iter = 0; iter < 4; iter++) {
|
|
831
|
+
for (const lvl of sortedLevels) {
|
|
832
|
+
for (const id of byLevel.get(lvl)) {
|
|
833
|
+
const ln = byIdLayout.get(id);
|
|
834
|
+
if (ln.nodeType !== "bus") continue;
|
|
835
|
+
const childrenIds = children.get(id) ?? [];
|
|
836
|
+
const parentIds = parents.get(id) ?? [];
|
|
837
|
+
const relatedXs = [];
|
|
838
|
+
for (const cid of childrenIds) {
|
|
839
|
+
const c = byIdLayout.get(cid);
|
|
840
|
+
if (c && c.nodeType !== "bus_tie") relatedXs.push(c.x);
|
|
841
|
+
}
|
|
842
|
+
if (relatedXs.length === 0) {
|
|
843
|
+
for (const pid of parentIds) {
|
|
844
|
+
const p = byIdLayout.get(pid);
|
|
845
|
+
if (p && p.nodeType !== "bus_tie") relatedXs.push(p.x);
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
if (relatedXs.length > 0) {
|
|
849
|
+
const minX = Math.min(...relatedXs);
|
|
850
|
+
const maxX2 = Math.max(...relatedXs);
|
|
851
|
+
ln.x = (minX + maxX2) / 2;
|
|
852
|
+
ln.busLeft = minX - BUS_OVERHANG;
|
|
853
|
+
ln.busRight = maxX2 + BUS_OVERHANG;
|
|
854
|
+
} else {
|
|
855
|
+
ln.busLeft = ln.x - 40;
|
|
856
|
+
ln.busRight = ln.x + 40;
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
const CONVERGENCE_SPREAD = Math.max(H_SPACING, 110);
|
|
862
|
+
for (let iter = 0; iter < 4; iter++) {
|
|
863
|
+
for (const lvl of [...sortedLevels].reverse()) {
|
|
864
|
+
for (const id of byLevel.get(lvl)) {
|
|
865
|
+
const ln = byIdLayout.get(id);
|
|
866
|
+
if (ln.nodeType === "bus" || ln.nodeType === "bus_tie") continue;
|
|
867
|
+
const childIds = children.get(id) ?? [];
|
|
868
|
+
if (childIds.length === 1) {
|
|
869
|
+
const child = byIdLayout.get(childIds[0]);
|
|
870
|
+
if (!child) continue;
|
|
871
|
+
const siblingParents = (parents.get(child.node.id) ?? []).map((pid) => byIdLayout.get(pid)).filter((p) => !!p && p.level === lvl && p.nodeType !== "bus");
|
|
872
|
+
if (siblingParents.length > 1) {
|
|
873
|
+
siblingParents.sort((a, b) => a.x - b.x);
|
|
874
|
+
const n = siblingParents.length;
|
|
875
|
+
const spread = Math.max(
|
|
876
|
+
CONVERGENCE_SPREAD,
|
|
877
|
+
(child.halfWidth * 2 + 40) / Math.max(1, n - 1)
|
|
878
|
+
);
|
|
879
|
+
const idx = siblingParents.indexOf(ln);
|
|
880
|
+
ln.x = child.x + (idx - (n - 1) / 2) * spread;
|
|
881
|
+
} else {
|
|
882
|
+
ln.x = child.x;
|
|
883
|
+
}
|
|
884
|
+
} else if (childIds.length > 1) {
|
|
885
|
+
const xs = childIds.map((c) => byIdLayout.get(c)?.x).filter((v) => v !== void 0);
|
|
886
|
+
if (xs.length > 0) {
|
|
887
|
+
ln.x = (Math.min(...xs) + Math.max(...xs)) / 2;
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
for (const ln of layoutNodes) {
|
|
894
|
+
if (ln.nodeType !== "bus_tie") continue;
|
|
895
|
+
const inIds = parents.get(ln.node.id) ?? [];
|
|
896
|
+
const outIds = children.get(ln.node.id) ?? [];
|
|
897
|
+
const busA = inIds.map((id) => byIdLayout.get(id)).find((n) => n?.nodeType === "bus");
|
|
898
|
+
const busB = outIds.map((id) => byIdLayout.get(id)).find((n) => n?.nodeType === "bus");
|
|
899
|
+
if (!busA || !busB) continue;
|
|
900
|
+
const busAChildren = (children.get(busA.node.id) ?? []).map((id) => byIdLayout.get(id)).filter((c) => !!c && c.nodeType !== "bus_tie");
|
|
901
|
+
const busAMaxX = busAChildren.length ? Math.max(...busAChildren.map((c) => c.x)) : busA.x;
|
|
902
|
+
ln.y = busA.y;
|
|
903
|
+
ln.x = busAMaxX + 60;
|
|
904
|
+
const cluster = /* @__PURE__ */ new Set([busB.node.id]);
|
|
905
|
+
const queue = [busB.node.id];
|
|
906
|
+
const excluded = /* @__PURE__ */ new Set([busA.node.id, ln.node.id]);
|
|
907
|
+
while (queue.length) {
|
|
908
|
+
const cur = queue.shift();
|
|
909
|
+
const neighbors = [...children.get(cur) ?? [], ...parents.get(cur) ?? []];
|
|
910
|
+
for (const nb of neighbors) {
|
|
911
|
+
if (cluster.has(nb) || excluded.has(nb)) continue;
|
|
912
|
+
cluster.add(nb);
|
|
913
|
+
queue.push(nb);
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
let minClusterX = Infinity;
|
|
917
|
+
for (const id of cluster) {
|
|
918
|
+
const n = byIdLayout.get(id);
|
|
919
|
+
if (!n) continue;
|
|
920
|
+
const left = n.nodeType === "bus" ? n.busLeft ?? n.x : n.x - n.halfWidth;
|
|
921
|
+
if (left < minClusterX) minClusterX = left;
|
|
922
|
+
}
|
|
923
|
+
const desiredLeft = ln.x + 30;
|
|
924
|
+
const shift = desiredLeft - minClusterX;
|
|
925
|
+
if (shift > 0) {
|
|
926
|
+
for (const id of cluster) {
|
|
927
|
+
const n = byIdLayout.get(id);
|
|
928
|
+
if (!n) continue;
|
|
929
|
+
n.x += shift;
|
|
930
|
+
if (n.busLeft !== void 0) n.busLeft += shift;
|
|
931
|
+
if (n.busRight !== void 0) n.busRight += shift;
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
const labelHalfWidth = (ln) => {
|
|
936
|
+
if (ln.nodeType === "bus" || ln.nodeType === "bus_tie") return 0;
|
|
937
|
+
const node = ln.node;
|
|
938
|
+
const txtParts = [node.label ?? node.id];
|
|
939
|
+
if (node.rating) txtParts.push(node.rating);
|
|
940
|
+
const longest = txtParts.reduce((m, s) => Math.max(m, s.length), 0);
|
|
941
|
+
return longest * 6.2 / 2 + 4;
|
|
942
|
+
};
|
|
943
|
+
for (const lvl of sortedLevels) {
|
|
944
|
+
const ids = byLevel.get(lvl);
|
|
945
|
+
const sorted = ids.map((id) => byIdLayout.get(id)).sort((a, b) => a.x - b.x);
|
|
946
|
+
for (let i = 1; i < sorted.length; i++) {
|
|
947
|
+
const prev = sorted[i - 1];
|
|
948
|
+
const cur = sorted[i];
|
|
949
|
+
if (prev.nodeType === "bus" && cur.nodeType !== "bus") continue;
|
|
950
|
+
if (cur.nodeType === "bus" && prev.nodeType !== "bus") continue;
|
|
951
|
+
const symGap = (prev.nodeType === "bus" ? 0 : prev.halfWidth) + (cur.nodeType === "bus" ? 0 : cur.halfWidth) + 16;
|
|
952
|
+
const labelGap = labelHalfWidth(prev) + labelHalfWidth(cur) + 8;
|
|
953
|
+
const minGap = Math.max(symGap, labelGap);
|
|
954
|
+
if (cur.x - prev.x < minGap) {
|
|
955
|
+
cur.x = prev.x + minGap;
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
for (const ln of layoutNodes) {
|
|
960
|
+
if (ln.nodeType !== "bus") continue;
|
|
961
|
+
const childrenIds = children.get(ln.node.id) ?? [];
|
|
962
|
+
const parentIds = parents.get(ln.node.id) ?? [];
|
|
963
|
+
const xs = [];
|
|
964
|
+
for (const cid of [...childrenIds, ...parentIds]) {
|
|
965
|
+
const rel = byIdLayout.get(cid);
|
|
966
|
+
if (rel && rel.nodeType !== "bus_tie") xs.push(rel.x);
|
|
967
|
+
}
|
|
968
|
+
const tieXs = [];
|
|
969
|
+
for (const cid of [...childrenIds, ...parentIds]) {
|
|
970
|
+
const rel = byIdLayout.get(cid);
|
|
971
|
+
if (rel && rel.nodeType === "bus_tie") tieXs.push(rel.x);
|
|
972
|
+
}
|
|
973
|
+
if (xs.length > 0) {
|
|
974
|
+
let left = Math.min(...xs) - BUS_OVERHANG;
|
|
975
|
+
let right = Math.max(...xs) + BUS_OVERHANG;
|
|
976
|
+
for (const tx of tieXs) {
|
|
977
|
+
if (tx < left) left = tx;
|
|
978
|
+
if (tx > right) right = tx;
|
|
979
|
+
}
|
|
980
|
+
ln.busLeft = left;
|
|
981
|
+
ln.busRight = right;
|
|
982
|
+
ln.x = (Math.min(...xs) + Math.max(...xs)) / 2;
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
for (const ln of layoutNodes) {
|
|
986
|
+
const geom = geometryFor(ln.nodeType);
|
|
987
|
+
ln.topY = ln.y + geom.topY;
|
|
988
|
+
ln.bottomY = ln.y + geom.bottomY;
|
|
989
|
+
}
|
|
990
|
+
const edges = [];
|
|
991
|
+
for (const c of ast.connections) {
|
|
992
|
+
const from = byIdLayout.get(c.from);
|
|
993
|
+
const to = byIdLayout.get(c.to);
|
|
994
|
+
if (!from || !to) continue;
|
|
995
|
+
const fx = from.x;
|
|
996
|
+
const tx = to.x;
|
|
997
|
+
const lateralTie = from.nodeType === "bus_tie" || to.nodeType === "bus_tie" || from.level === to.level && (from.nodeType === "bus" || to.nodeType === "bus");
|
|
998
|
+
let startY;
|
|
999
|
+
let endY;
|
|
1000
|
+
if (lateralTie) {
|
|
1001
|
+
startY = from.y;
|
|
1002
|
+
endY = to.y;
|
|
1003
|
+
} else {
|
|
1004
|
+
startY = from.nodeType === "bus" ? from.y : from.bottomY;
|
|
1005
|
+
endY = to.nodeType === "bus" ? to.y : to.topY;
|
|
1006
|
+
}
|
|
1007
|
+
let pathD;
|
|
1008
|
+
if (lateralTie) {
|
|
1009
|
+
pathD = `M ${fx} ${startY} L ${tx} ${endY}`;
|
|
1010
|
+
} else if (Math.abs(fx - tx) < 0.5) {
|
|
1011
|
+
pathD = `M ${fx} ${startY} L ${tx} ${endY}`;
|
|
1012
|
+
} else {
|
|
1013
|
+
const midY = (startY + endY) / 2;
|
|
1014
|
+
pathD = `M ${fx} ${startY} L ${fx} ${midY} L ${tx} ${midY} L ${tx} ${endY}`;
|
|
1015
|
+
}
|
|
1016
|
+
edges.push({
|
|
1017
|
+
from: c.from,
|
|
1018
|
+
to: c.to,
|
|
1019
|
+
path: pathD,
|
|
1020
|
+
cable: c.cable,
|
|
1021
|
+
label: c.label,
|
|
1022
|
+
midX: (fx + tx) / 2,
|
|
1023
|
+
midY: (startY + endY) / 2
|
|
1024
|
+
});
|
|
1025
|
+
}
|
|
1026
|
+
const bands = [];
|
|
1027
|
+
for (const lvl of sortedLevels) {
|
|
1028
|
+
let voltage;
|
|
1029
|
+
for (const id of byLevel.get(lvl)) {
|
|
1030
|
+
const n = nodeMap.get(id);
|
|
1031
|
+
if (n.voltage) {
|
|
1032
|
+
voltage = n.voltage;
|
|
1033
|
+
break;
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
bands.push({
|
|
1037
|
+
level: lvl,
|
|
1038
|
+
voltage,
|
|
1039
|
+
y: TOP_PADDING + lvl * LEVEL_SPACING - LEVEL_SPACING / 2 + 10,
|
|
1040
|
+
height: LEVEL_SPACING
|
|
1041
|
+
});
|
|
1042
|
+
}
|
|
1043
|
+
let contentMinX = Infinity;
|
|
1044
|
+
for (const ln of layoutNodes) {
|
|
1045
|
+
const left = ln.nodeType === "bus" ? ln.busLeft ?? ln.x : ln.x - ln.halfWidth;
|
|
1046
|
+
if (left < contentMinX) contentMinX = left;
|
|
1047
|
+
}
|
|
1048
|
+
if (!Number.isFinite(contentMinX)) contentMinX = 0;
|
|
1049
|
+
const xShift = LEFT_PADDING - contentMinX;
|
|
1050
|
+
if (Math.abs(xShift) > 0.5) {
|
|
1051
|
+
for (const ln of layoutNodes) {
|
|
1052
|
+
ln.x += xShift;
|
|
1053
|
+
if (ln.busLeft !== void 0) ln.busLeft += xShift;
|
|
1054
|
+
if (ln.busRight !== void 0) ln.busRight += xShift;
|
|
1055
|
+
}
|
|
1056
|
+
for (const e of edges) {
|
|
1057
|
+
e.midX += xShift;
|
|
1058
|
+
e.path = e.path.replace(
|
|
1059
|
+
/([ML])\s+(-?[\d.]+)\s+(-?[\d.]+)/g,
|
|
1060
|
+
(_m, cmd, x, y) => `${cmd} ${Number(x) + xShift} ${y}`
|
|
1061
|
+
);
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
let maxX = 0;
|
|
1065
|
+
for (const ln of layoutNodes) {
|
|
1066
|
+
const right = (ln.busRight ?? ln.x + ln.halfWidth) + 60;
|
|
1067
|
+
if (right > maxX) maxX = right;
|
|
1068
|
+
}
|
|
1069
|
+
const width = Math.max(400, maxX + 40);
|
|
1070
|
+
const height = TOP_PADDING + maxLevel * LEVEL_SPACING + 120;
|
|
1071
|
+
return {
|
|
1072
|
+
width,
|
|
1073
|
+
height,
|
|
1074
|
+
nodes: layoutNodes,
|
|
1075
|
+
edges,
|
|
1076
|
+
bands,
|
|
1077
|
+
nodeById: byIdLayout
|
|
1078
|
+
};
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
// src/diagrams/sld/renderer.ts
|
|
1082
|
+
var BAND_ODD_LIGHT = "#f7f7f7";
|
|
1083
|
+
var BAND_EVEN_LIGHT = "#fbfbfb";
|
|
1084
|
+
var BAND_ODD_DARK = "#2a2b3c";
|
|
1085
|
+
var BAND_EVEN_DARK = "#313244";
|
|
1086
|
+
function buildCss(t) {
|
|
1087
|
+
const isDark = t.bg !== "#ffffff";
|
|
1088
|
+
const bandOdd = isDark ? BAND_ODD_DARK : BAND_ODD_LIGHT;
|
|
1089
|
+
const bandEven = isDark ? BAND_EVEN_DARK : BAND_EVEN_LIGHT;
|
|
1090
|
+
return `
|
|
1091
|
+
.lt-sld { background: ${t.bg}; font-family: system-ui, -apple-system, sans-serif; }
|
|
1092
|
+
.lt-sld-stroke { stroke: ${t.stroke}; stroke-width: 1.8; fill: none; }
|
|
1093
|
+
.lt-sld-stroke-thick { stroke: ${t.stroke}; stroke-width: 2.4; fill: none; stroke-linecap: round; }
|
|
1094
|
+
.lt-sld-fill { fill: ${t.bg}; stroke: ${t.stroke}; stroke-width: 2; }
|
|
1095
|
+
.lt-sld-fill-dark { fill: ${t.stroke}; stroke: ${t.stroke}; stroke-width: 1; }
|
|
1096
|
+
.lt-sld-dot { fill: ${t.stroke}; stroke: none; }
|
|
1097
|
+
.lt-sld-wire { stroke: ${t.stroke}; stroke-width: 2; fill: none; }
|
|
1098
|
+
.lt-sld-bus { stroke: ${t.strokeHeavy}; stroke-width: 6; stroke-linecap: square; }
|
|
1099
|
+
.lt-sld-band-odd { fill: ${bandOdd}; stroke: none; }
|
|
1100
|
+
.lt-sld-band-even { fill: ${bandEven}; stroke: none; }
|
|
1101
|
+
.lt-sld-band-label { font: bold 11px sans-serif; fill: ${t.textMuted}; }
|
|
1102
|
+
.lt-sld-title { font: bold 16px sans-serif; fill: ${t.text}; }
|
|
1103
|
+
.lt-sld-id { font: bold 11px sans-serif; fill: ${t.text}; text-anchor: middle; }
|
|
1104
|
+
.lt-sld-rating { font: 9px sans-serif; fill: ${t.textMuted}; text-anchor: middle; }
|
|
1105
|
+
.lt-sld-voltage { font: bold 10px sans-serif; fill: ${t.textMuted}; }
|
|
1106
|
+
.lt-sld-nameplate { font: 9px sans-serif; fill: ${t.textMuted}; }
|
|
1107
|
+
.lt-sld-cable { font: 9px ui-monospace, SFMono-Regular, Menlo, monospace; fill: ${t.textMuted}; }
|
|
1108
|
+
.lt-sld-symbol-text { font: 11px sans-serif; fill: ${t.text}; dominant-baseline: middle; }
|
|
1109
|
+
.lt-sld-wdg { font: bold 10px sans-serif; fill: ${t.stroke}; dominant-baseline: middle; }
|
|
1110
|
+
.lt-sld-bus-label { font: bold 11px sans-serif; fill: ${t.accent}; }
|
|
1111
|
+
`.trim();
|
|
1112
|
+
}
|
|
1113
|
+
function renderLabels(ln) {
|
|
1114
|
+
const pieces = [];
|
|
1115
|
+
const { node } = ln;
|
|
1116
|
+
if (ln.nodeType === "bus") {
|
|
1117
|
+
const label = node.label ?? node.id;
|
|
1118
|
+
pieces.push(
|
|
1119
|
+
text(
|
|
1120
|
+
{ x: (ln.busLeft ?? ln.x - 40) + 4, y: ln.y - 8, class: "lt-sld-bus-label" },
|
|
1121
|
+
node.voltage ? `${node.voltage} \xB7 ${label}` : label
|
|
1122
|
+
)
|
|
1123
|
+
);
|
|
1124
|
+
return pieces;
|
|
1125
|
+
}
|
|
1126
|
+
if (ln.nodeType === "hub") {
|
|
1127
|
+
if (node.rating || node.voltage) {
|
|
1128
|
+
const lines2 = [];
|
|
1129
|
+
if (node.rating) lines2.push(node.rating);
|
|
1130
|
+
if (node.voltage) lines2.push(node.voltage);
|
|
1131
|
+
lines2.forEach((l, i) => {
|
|
1132
|
+
pieces.push(
|
|
1133
|
+
text(
|
|
1134
|
+
{ x: ln.x, y: ln.bottomY + 14 + i * 11, class: "lt-sld-rating" },
|
|
1135
|
+
l
|
|
1136
|
+
)
|
|
1137
|
+
);
|
|
1138
|
+
});
|
|
1139
|
+
}
|
|
1140
|
+
return pieces;
|
|
1141
|
+
}
|
|
1142
|
+
if (ln.nodeType === "bus_tie") {
|
|
1143
|
+
pieces.push(
|
|
1144
|
+
text(
|
|
1145
|
+
{ x: ln.x, y: ln.topY - 6, class: "lt-sld-rating" },
|
|
1146
|
+
node.label ?? node.id
|
|
1147
|
+
)
|
|
1148
|
+
);
|
|
1149
|
+
return pieces;
|
|
1150
|
+
}
|
|
1151
|
+
const idY = ln.topY - 22;
|
|
1152
|
+
pieces.push(
|
|
1153
|
+
text({ x: ln.x, y: idY, class: "lt-sld-id" }, node.label ?? node.id)
|
|
1154
|
+
);
|
|
1155
|
+
const lines = [];
|
|
1156
|
+
if (node.rating) lines.push(node.rating);
|
|
1157
|
+
if (node.voltage) lines.push(node.voltage);
|
|
1158
|
+
if (node.deviceNumber && ln.nodeType === "relay") ;
|
|
1159
|
+
lines.forEach((l, i) => {
|
|
1160
|
+
pieces.push(
|
|
1161
|
+
text(
|
|
1162
|
+
{ x: ln.x, y: ln.bottomY + 14 + i * 11, class: "lt-sld-rating" },
|
|
1163
|
+
l
|
|
1164
|
+
)
|
|
1165
|
+
);
|
|
1166
|
+
});
|
|
1167
|
+
if ((ln.nodeType === "transformer" || ln.nodeType === "transformer_dy" || ln.nodeType === "transformer_yd" || ln.nodeType === "transformer_yy" || ln.nodeType === "transformer_dd" || ln.nodeType === "autotransformer" || ln.nodeType === "transformer_3winding") && node.nameplate) {
|
|
1168
|
+
const np = node.nameplate;
|
|
1169
|
+
const keys = Object.keys(np);
|
|
1170
|
+
let offset = -12;
|
|
1171
|
+
const x = ln.x + ln.halfWidth + 28;
|
|
1172
|
+
for (const k of keys) {
|
|
1173
|
+
pieces.push(
|
|
1174
|
+
text(
|
|
1175
|
+
{ x, y: ln.y + offset, class: "lt-sld-nameplate" },
|
|
1176
|
+
`${k}: ${np[k]}`
|
|
1177
|
+
)
|
|
1178
|
+
);
|
|
1179
|
+
offset += 11;
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
return pieces;
|
|
1183
|
+
}
|
|
1184
|
+
function renderSLD(ast, config) {
|
|
1185
|
+
const layout = layoutSLD(ast);
|
|
1186
|
+
const t = resolveIndustrialTheme(config?.theme ?? "default");
|
|
1187
|
+
const titleOffset = ast.title ? 34 : 12;
|
|
1188
|
+
const width = Math.ceil(layout.width);
|
|
1189
|
+
const height = Math.ceil(layout.height + titleOffset);
|
|
1190
|
+
const children = [];
|
|
1191
|
+
children.push(title(ast.title ?? "Single-Line Diagram"));
|
|
1192
|
+
children.push(
|
|
1193
|
+
desc(
|
|
1194
|
+
`Single-line diagram with ${ast.nodes.length} nodes and ${ast.connections.length} connections`
|
|
1195
|
+
)
|
|
1196
|
+
);
|
|
1197
|
+
children.push(el("style", {}, buildCss(t)));
|
|
1198
|
+
children.push(
|
|
1199
|
+
defs([
|
|
1200
|
+
el(
|
|
1201
|
+
"marker",
|
|
1202
|
+
{
|
|
1203
|
+
id: "lt-sld-arrow",
|
|
1204
|
+
markerWidth: 8,
|
|
1205
|
+
markerHeight: 8,
|
|
1206
|
+
refX: 6,
|
|
1207
|
+
refY: 3,
|
|
1208
|
+
orient: "auto",
|
|
1209
|
+
markerUnits: "strokeWidth"
|
|
1210
|
+
},
|
|
1211
|
+
[el("path", { d: "M 0 0 L 6 3 L 0 6 z", fill: t.textMuted })]
|
|
1212
|
+
)
|
|
1213
|
+
])
|
|
1214
|
+
);
|
|
1215
|
+
if (ast.title) {
|
|
1216
|
+
children.push(
|
|
1217
|
+
text({ x: 20, y: 22, class: "lt-sld-title" }, ast.title)
|
|
1218
|
+
);
|
|
1219
|
+
}
|
|
1220
|
+
const inner = [];
|
|
1221
|
+
layout.bands.forEach((b, i) => {
|
|
1222
|
+
inner.push(
|
|
1223
|
+
el("rect", {
|
|
1224
|
+
x: 0,
|
|
1225
|
+
y: b.y,
|
|
1226
|
+
width: layout.width,
|
|
1227
|
+
height: b.height,
|
|
1228
|
+
class: i % 2 === 0 ? "lt-sld-band-odd" : "lt-sld-band-even"
|
|
1229
|
+
})
|
|
1230
|
+
);
|
|
1231
|
+
if (b.voltage) {
|
|
1232
|
+
inner.push(
|
|
1233
|
+
text(
|
|
1234
|
+
{ x: 14, y: b.y + 18, class: "lt-sld-band-label" },
|
|
1235
|
+
b.voltage
|
|
1236
|
+
)
|
|
1237
|
+
);
|
|
1238
|
+
}
|
|
1239
|
+
});
|
|
1240
|
+
for (const e of layout.edges) {
|
|
1241
|
+
inner.push(path({ d: e.path, class: "lt-sld-wire" }));
|
|
1242
|
+
if (e.cable) {
|
|
1243
|
+
inner.push(
|
|
1244
|
+
text(
|
|
1245
|
+
{ x: e.midX + 6, y: e.midY - 2, class: "lt-sld-cable" },
|
|
1246
|
+
e.cable
|
|
1247
|
+
)
|
|
1248
|
+
);
|
|
1249
|
+
}
|
|
1250
|
+
if (e.label) {
|
|
1251
|
+
inner.push(
|
|
1252
|
+
text(
|
|
1253
|
+
{ x: e.midX + 6, y: e.midY + 10, class: "lt-sld-cable" },
|
|
1254
|
+
e.label
|
|
1255
|
+
)
|
|
1256
|
+
);
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
for (const ln of layout.nodes) {
|
|
1260
|
+
if (ln.nodeType === "bus") {
|
|
1261
|
+
const left = ln.busLeft ?? ln.x - 40;
|
|
1262
|
+
const right = ln.busRight ?? ln.x + 40;
|
|
1263
|
+
inner.push(
|
|
1264
|
+
el("line", {
|
|
1265
|
+
x1: left,
|
|
1266
|
+
y1: ln.y,
|
|
1267
|
+
x2: right,
|
|
1268
|
+
y2: ln.y,
|
|
1269
|
+
class: "lt-sld-bus",
|
|
1270
|
+
"data-id": ln.node.id
|
|
1271
|
+
})
|
|
1272
|
+
);
|
|
1273
|
+
for (const piece of renderLabels(ln)) inner.push(piece);
|
|
1274
|
+
continue;
|
|
1275
|
+
}
|
|
1276
|
+
const attrs = {
|
|
1277
|
+
transform: `translate(${ln.x}, ${ln.y})`,
|
|
1278
|
+
"data-type": ln.nodeType,
|
|
1279
|
+
"data-id": ln.node.id
|
|
1280
|
+
};
|
|
1281
|
+
inner.push(
|
|
1282
|
+
group(attrs, [
|
|
1283
|
+
renderSymbol(
|
|
1284
|
+
ln.nodeType,
|
|
1285
|
+
ln.nodeType === "hub" ? ln.node.label ?? ln.node.id : ln.node.deviceNumber
|
|
1286
|
+
)
|
|
1287
|
+
])
|
|
1288
|
+
);
|
|
1289
|
+
for (const piece of renderLabels(ln)) inner.push(piece);
|
|
1290
|
+
}
|
|
1291
|
+
const wrap = group({ transform: `translate(0, ${titleOffset})` }, inner);
|
|
1292
|
+
children.push(wrap);
|
|
1293
|
+
return svgRoot(
|
|
1294
|
+
{
|
|
1295
|
+
class: "lt-sld",
|
|
1296
|
+
role: "img",
|
|
1297
|
+
"aria-labelledby": "lt-sld-title lt-sld-desc",
|
|
1298
|
+
width,
|
|
1299
|
+
height,
|
|
1300
|
+
viewBox: `0 0 ${width} ${height}`
|
|
1301
|
+
},
|
|
1302
|
+
children
|
|
1303
|
+
);
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1306
|
+
// src/diagrams/sld/index.ts
|
|
1307
|
+
var sld = {
|
|
1308
|
+
type: "sld",
|
|
1309
|
+
detect(text2) {
|
|
1310
|
+
const first = text2.trim().split("\n")[0]?.trim().toLowerCase() ?? "";
|
|
1311
|
+
return first.startsWith("sld");
|
|
1312
|
+
},
|
|
1313
|
+
render(text2, config) {
|
|
1314
|
+
const ast = parseSLDDSL(text2);
|
|
1315
|
+
return renderSLD(ast, config);
|
|
1316
|
+
}
|
|
1317
|
+
};
|
|
1318
|
+
|
|
1319
|
+
export { layoutSLD, parseSLDDSL, renderSLD, sld };
|
|
1320
|
+
//# sourceMappingURL=chunk-5C7DPDHQ.js.map
|
|
1321
|
+
//# sourceMappingURL=chunk-5C7DPDHQ.js.map
|