schematex 0.9.6 → 0.9.8
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 +43 -3
- package/dist/ai/ai-sdk.cjs +23 -23
- package/dist/ai/ai-sdk.d.cts +3 -3
- package/dist/ai/ai-sdk.d.ts +3 -3
- package/dist/ai/ai-sdk.js +18 -18
- package/dist/ai/index.cjs +32 -32
- package/dist/ai/index.d.cts +4 -4
- package/dist/ai/index.d.ts +4 -4
- package/dist/ai/index.js +19 -19
- package/dist/{api-BOJJlNb1.d.ts → api-D_d-JklT.d.ts} +1 -1
- package/dist/{api-v9t1T1v6.d.cts → api-DnTyW-6F.d.cts} +1 -1
- package/dist/browser.cjs +24 -24
- package/dist/browser.d.cts +3 -3
- package/dist/browser.d.ts +3 -3
- package/dist/browser.js +18 -18
- package/dist/{chunk-6QZQTASC.cjs → chunk-246OJILS.cjs} +12 -12
- package/dist/{chunk-6QZQTASC.cjs.map → chunk-246OJILS.cjs.map} +1 -1
- package/dist/{chunk-JEMAOC2D.js → chunk-2IRYXK4M.js} +3 -3
- package/dist/{chunk-JEMAOC2D.js.map → chunk-2IRYXK4M.js.map} +1 -1
- package/dist/{chunk-HX64QWB6.cjs → chunk-2LVU75P3.cjs} +175 -11
- package/dist/chunk-2LVU75P3.cjs.map +1 -0
- package/dist/{chunk-CVTHUOAM.js → chunk-33BFUEYU.js} +173 -9
- package/dist/chunk-33BFUEYU.js.map +1 -0
- package/dist/{chunk-ITI3STJ6.cjs → chunk-3JN4762U.cjs} +4 -4
- package/dist/{chunk-ITI3STJ6.cjs.map → chunk-3JN4762U.cjs.map} +1 -1
- package/dist/{chunk-GAQ36VFD.cjs → chunk-4MANMKQ4.cjs} +4 -4
- package/dist/{chunk-GAQ36VFD.cjs.map → chunk-4MANMKQ4.cjs.map} +1 -1
- package/dist/{chunk-4W75FGWO.js → chunk-4QLIFOKH.js} +1877 -568
- package/dist/chunk-4QLIFOKH.js.map +1 -0
- package/dist/{chunk-64LABNTF.js → chunk-7NO5LYLL.js} +3 -3
- package/dist/{chunk-64LABNTF.js.map → chunk-7NO5LYLL.js.map} +1 -1
- package/dist/{chunk-ENUM7GMZ.cjs → chunk-7OOUU6BL.cjs} +147 -2
- package/dist/chunk-7OOUU6BL.cjs.map +1 -0
- package/dist/{chunk-M26ORU4P.js → chunk-AETIGJXP.js} +3 -3
- package/dist/{chunk-M26ORU4P.js.map → chunk-AETIGJXP.js.map} +1 -1
- package/dist/{chunk-KH5GRKUM.cjs → chunk-BEPVTFXK.cjs} +2080 -770
- package/dist/chunk-BEPVTFXK.cjs.map +1 -0
- package/dist/{chunk-OJ3P4IC4.cjs → chunk-DLXDR2E7.cjs} +4 -4
- package/dist/{chunk-OJ3P4IC4.cjs.map → chunk-DLXDR2E7.cjs.map} +1 -1
- package/dist/{chunk-3J4DZPZC.js → chunk-EB7T5SEO.js} +3 -3
- package/dist/{chunk-3J4DZPZC.js.map → chunk-EB7T5SEO.js.map} +1 -1
- package/dist/{chunk-VY6UZYYL.cjs → chunk-F5RYWDWO.cjs} +15 -15
- package/dist/{chunk-VY6UZYYL.cjs.map → chunk-F5RYWDWO.cjs.map} +1 -1
- package/dist/{chunk-INVLJYAE.cjs → chunk-GTCGATOL.cjs} +4 -4
- package/dist/{chunk-INVLJYAE.cjs.map → chunk-GTCGATOL.cjs.map} +1 -1
- package/dist/{chunk-ZCHGIWJK.js → chunk-HIWJMJJB.js} +3 -3
- package/dist/{chunk-ZCHGIWJK.js.map → chunk-HIWJMJJB.js.map} +1 -1
- package/dist/{chunk-RDYACU2G.js → chunk-IHX6J4HF.js} +3 -3
- package/dist/{chunk-RDYACU2G.js.map → chunk-IHX6J4HF.js.map} +1 -1
- package/dist/{chunk-4MRVJI7G.js → chunk-JVNV2T2T.js} +147 -3
- package/dist/chunk-JVNV2T2T.js.map +1 -0
- package/dist/{chunk-SXOAAQNY.js → chunk-KUSW5I2P.js} +3 -3
- package/dist/{chunk-SXOAAQNY.js.map → chunk-KUSW5I2P.js.map} +1 -1
- package/dist/{chunk-35NGXDT2.cjs → chunk-KYE7CRED.cjs} +12 -12
- package/dist/{chunk-35NGXDT2.cjs.map → chunk-KYE7CRED.cjs.map} +1 -1
- package/dist/{chunk-II4GLKGF.js → chunk-MVTYPWHO.js} +3 -3
- package/dist/chunk-MVTYPWHO.js.map +1 -0
- package/dist/{chunk-N3HU635X.cjs → chunk-MXV3XJFH.cjs} +4 -4
- package/dist/chunk-MXV3XJFH.cjs.map +1 -0
- package/dist/{chunk-XCCXG6RR.js → chunk-NB7MFQCZ.js} +3 -3
- package/dist/{chunk-XCCXG6RR.js.map → chunk-NB7MFQCZ.js.map} +1 -1
- package/dist/{chunk-GYYYULBL.js → chunk-NP7N3DZG.js} +3 -3
- package/dist/{chunk-GYYYULBL.js.map → chunk-NP7N3DZG.js.map} +1 -1
- package/dist/{chunk-3PH2MQGN.js → chunk-P4U565XH.js} +3 -3
- package/dist/{chunk-3PH2MQGN.js.map → chunk-P4U565XH.js.map} +1 -1
- package/dist/{chunk-VYQXB2RC.cjs → chunk-QC2RICQ4.cjs} +12 -12
- package/dist/{chunk-VYQXB2RC.cjs.map → chunk-QC2RICQ4.cjs.map} +1 -1
- package/dist/{chunk-3WX24RCH.js → chunk-QMJHLDGY.js} +3 -3
- package/dist/{chunk-3WX24RCH.js.map → chunk-QMJHLDGY.js.map} +1 -1
- package/dist/{chunk-C4Y24X3U.cjs → chunk-T55OQILI.cjs} +4 -4
- package/dist/{chunk-C4Y24X3U.cjs.map → chunk-T55OQILI.cjs.map} +1 -1
- package/dist/{chunk-6ZD7TCWO.cjs → chunk-TFUVNQNA.cjs} +15 -15
- package/dist/{chunk-6ZD7TCWO.cjs.map → chunk-TFUVNQNA.cjs.map} +1 -1
- package/dist/{chunk-4AC6I7KJ.cjs → chunk-TXWVJAMR.cjs} +4 -4
- package/dist/{chunk-4AC6I7KJ.cjs.map → chunk-TXWVJAMR.cjs.map} +1 -1
- package/dist/{chunk-4OC3CTGE.cjs → chunk-UHRNFBWY.cjs} +4 -4
- package/dist/{chunk-4OC3CTGE.cjs.map → chunk-UHRNFBWY.cjs.map} +1 -1
- package/dist/{chunk-B4CMWA6Y.js → chunk-W4UVDMUC.js} +3 -3
- package/dist/{chunk-B4CMWA6Y.js.map → chunk-W4UVDMUC.js.map} +1 -1
- package/dist/{chunk-5ZQRHDMQ.cjs → chunk-YDEQZSPQ.cjs} +4 -4
- package/dist/{chunk-5ZQRHDMQ.cjs.map → chunk-YDEQZSPQ.cjs.map} +1 -1
- package/dist/{chunk-627GHE2N.cjs → chunk-YFPDZVB7.cjs} +5 -5
- package/dist/{chunk-627GHE2N.cjs.map → chunk-YFPDZVB7.cjs.map} +1 -1
- package/dist/{chunk-NKYR4PAS.js → chunk-YXEPF3SL.js} +3 -3
- package/dist/{chunk-NKYR4PAS.js.map → chunk-YXEPF3SL.js.map} +1 -1
- package/dist/{chunk-AXMBXAEA.js → chunk-ZRFKIERV.js} +3 -3
- package/dist/{chunk-AXMBXAEA.js.map → chunk-ZRFKIERV.js.map} +1 -1
- package/dist/{diagnostics-5bVLlGNj.d.cts → diagnostics-D2qkBfFx.d.cts} +1 -1
- package/dist/{diagnostics-5bVLlGNj.d.ts → diagnostics-D2qkBfFx.d.ts} +1 -1
- package/dist/diagrams/blockdiagram/index.cjs +6 -6
- package/dist/diagrams/blockdiagram/index.d.cts +1 -1
- package/dist/diagrams/blockdiagram/index.d.ts +1 -1
- package/dist/diagrams/blockdiagram/index.js +2 -2
- package/dist/diagrams/circuit/index.cjs +9 -9
- package/dist/diagrams/circuit/index.d.cts +1 -1
- package/dist/diagrams/circuit/index.d.ts +1 -1
- package/dist/diagrams/circuit/index.js +2 -2
- package/dist/diagrams/ecomap/index.cjs +7 -7
- package/dist/diagrams/ecomap/index.d.cts +1 -1
- package/dist/diagrams/ecomap/index.d.ts +1 -1
- package/dist/diagrams/ecomap/index.js +2 -2
- package/dist/diagrams/entity/index.cjs +6 -6
- package/dist/diagrams/entity/index.d.cts +1 -1
- package/dist/diagrams/entity/index.d.ts +1 -1
- package/dist/diagrams/entity/index.js +2 -2
- package/dist/diagrams/fishbone/index.cjs +8 -8
- package/dist/diagrams/fishbone/index.d.cts +1 -1
- package/dist/diagrams/fishbone/index.d.ts +1 -1
- package/dist/diagrams/fishbone/index.js +2 -2
- package/dist/diagrams/flowchart/index.cjs +8 -8
- package/dist/diagrams/flowchart/index.d.cts +2 -2
- package/dist/diagrams/flowchart/index.d.ts +2 -2
- package/dist/diagrams/flowchart/index.js +2 -2
- package/dist/diagrams/genogram/index.cjs +9 -9
- package/dist/diagrams/genogram/index.d.cts +1 -1
- package/dist/diagrams/genogram/index.d.ts +1 -1
- package/dist/diagrams/genogram/index.js +2 -2
- package/dist/diagrams/ladder/index.cjs +6 -6
- package/dist/diagrams/ladder/index.d.cts +1 -1
- package/dist/diagrams/ladder/index.d.ts +1 -1
- package/dist/diagrams/ladder/index.js +2 -2
- package/dist/diagrams/logic/index.cjs +8 -8
- package/dist/diagrams/logic/index.d.cts +1 -1
- package/dist/diagrams/logic/index.d.ts +1 -1
- package/dist/diagrams/logic/index.js +2 -2
- package/dist/diagrams/orgchart/index.cjs +8 -8
- package/dist/diagrams/orgchart/index.d.cts +1 -1
- package/dist/diagrams/orgchart/index.d.ts +1 -1
- package/dist/diagrams/orgchart/index.js +2 -2
- package/dist/diagrams/pedigree/index.cjs +7 -7
- package/dist/diagrams/pedigree/index.d.cts +1 -1
- package/dist/diagrams/pedigree/index.d.ts +1 -1
- package/dist/diagrams/pedigree/index.js +2 -2
- package/dist/diagrams/phylo/index.cjs +7 -7
- package/dist/diagrams/phylo/index.d.cts +1 -1
- package/dist/diagrams/phylo/index.d.ts +1 -1
- package/dist/diagrams/phylo/index.js +2 -2
- package/dist/diagrams/sld/index.cjs +8 -8
- package/dist/diagrams/sld/index.d.cts +1 -1
- package/dist/diagrams/sld/index.d.ts +1 -1
- package/dist/diagrams/sld/index.js +2 -2
- package/dist/diagrams/sociogram/index.cjs +6 -6
- package/dist/diagrams/sociogram/index.d.cts +1 -1
- package/dist/diagrams/sociogram/index.d.ts +1 -1
- package/dist/diagrams/sociogram/index.js +2 -2
- package/dist/diagrams/timing/index.d.cts +1 -1
- package/dist/diagrams/timing/index.d.ts +1 -1
- package/dist/diagrams/venn/index.cjs +9 -9
- package/dist/diagrams/venn/index.d.cts +1 -1
- package/dist/diagrams/venn/index.d.ts +1 -1
- package/dist/diagrams/venn/index.js +2 -2
- package/dist/{index-syc0E5Ss.d.ts → index-D9u0YRxL.d.ts} +1 -1
- package/dist/{index-Cmf4Rcve.d.cts → index-JZlLiE6K.d.cts} +1 -1
- package/dist/index.cjs +91 -87
- package/dist/index.d.cts +7 -5
- package/dist/index.d.ts +7 -5
- package/dist/index.js +22 -22
- package/dist/react.cjs +18 -18
- package/dist/react.d.cts +2 -2
- package/dist/react.d.ts +2 -2
- package/dist/react.js +17 -17
- package/dist/{tools-B98iarLm.d.cts → tools-DAKYNcPv.d.cts} +2 -2
- package/dist/{tools-CCZ1IcIN.d.ts → tools-DM0aLCbc.d.ts} +2 -2
- package/package.json +3 -1
- package/dist/chunk-4MRVJI7G.js.map +0 -1
- package/dist/chunk-4W75FGWO.js.map +0 -1
- package/dist/chunk-CVTHUOAM.js.map +0 -1
- package/dist/chunk-ENUM7GMZ.cjs.map +0 -1
- package/dist/chunk-HX64QWB6.cjs.map +0 -1
- package/dist/chunk-II4GLKGF.js.map +0 -1
- package/dist/chunk-KH5GRKUM.cjs.map +0 -1
- package/dist/chunk-N3HU635X.cjs.map +0 -1
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import { orgchart } from './chunk-
|
|
2
|
-
import { circuit } from './chunk-
|
|
3
|
-
import { blockdiagram } from './chunk-
|
|
4
|
-
import { ladder } from './chunk-
|
|
5
|
-
import { sld } from './chunk-
|
|
6
|
-
import { entity } from './chunk-
|
|
7
|
-
import { fishbone } from './chunk-
|
|
8
|
-
import { venn } from './chunk-
|
|
9
|
-
import { flowchart, layoutFlowchart } from './chunk-
|
|
10
|
-
import { genogram } from './chunk-
|
|
11
|
-
import { ecomap, estimateTextWidth } from './chunk-
|
|
12
|
-
import { pedigree } from './chunk-
|
|
1
|
+
import { orgchart } from './chunk-EB7T5SEO.js';
|
|
2
|
+
import { circuit } from './chunk-IHX6J4HF.js';
|
|
3
|
+
import { blockdiagram } from './chunk-P4U565XH.js';
|
|
4
|
+
import { ladder } from './chunk-W4UVDMUC.js';
|
|
5
|
+
import { sld } from './chunk-MVTYPWHO.js';
|
|
6
|
+
import { entity } from './chunk-2IRYXK4M.js';
|
|
7
|
+
import { fishbone } from './chunk-NP7N3DZG.js';
|
|
8
|
+
import { venn } from './chunk-KUSW5I2P.js';
|
|
9
|
+
import { flowchart, layoutFlowchart } from './chunk-ZRFKIERV.js';
|
|
10
|
+
import { genogram } from './chunk-AETIGJXP.js';
|
|
11
|
+
import { ecomap, estimateTextWidth } from './chunk-NB7MFQCZ.js';
|
|
12
|
+
import { pedigree } from './chunk-HIWJMJJB.js';
|
|
13
13
|
import { parseFrontmatter } from './chunk-2KTQ75LN.js';
|
|
14
|
-
import { phylo } from './chunk-
|
|
15
|
-
import { sociogram } from './chunk-
|
|
14
|
+
import { phylo } from './chunk-QMJHLDGY.js';
|
|
15
|
+
import { sociogram } from './chunk-7NO5LYLL.js';
|
|
16
16
|
import { timing } from './chunk-MTIZIHWE.js';
|
|
17
|
-
import { logic } from './chunk-
|
|
18
|
-
import { resolveBaseTheme, resolveTimelineTheme, resolveStateTheme, cssCustomProperties, resolvePetriTheme, resolveNetworkTheme, resolveUmlClassTheme, DEFAULT_FONT_FAMILY, FONT_SIZE, resolveReliabilityTheme, STROKE_WIDTH, resolveBowtieTheme, resolveMindmapTheme, resolveMatrixTheme, resolveBpmnTheme, resolveFloorplanTheme,
|
|
17
|
+
import { logic } from './chunk-YXEPF3SL.js';
|
|
18
|
+
import { resolveBaseTheme, resolveTimelineTheme, resolveStateTheme, cssCustomProperties, resolvePetriTheme, resolveNetworkTheme, resolveUmlClassTheme, DEFAULT_FONT_FAMILY, FONT_SIZE, resolveReliabilityTheme, STROKE_WIDTH, resolveBowtieTheme, resolveComparisonTheme, TITLE, resolveMindmapTheme, resolveMatrixTheme, resolveBpmnTheme, resolveFloorplanTheme, resolvePlaybookTheme } from './chunk-JVNV2T2T.js';
|
|
19
19
|
import { QUOTE_PAIRS, stripQuotes, isOpenQuote, extractQuotedString, matchQuotedTitle } from './chunk-TO6PNBT3.js';
|
|
20
20
|
import { el, escapeXml, group, rect, text, line, path, circle, polygon, title, desc, svgRoot, defs, multilineText } from './chunk-SYYBKDL7.js';
|
|
21
21
|
|
|
@@ -1613,8 +1613,8 @@ function renderDecisionTree(ast, config) {
|
|
|
1613
1613
|
lx += nx * perpOffset * flip;
|
|
1614
1614
|
ly += ny * perpOffset * flip;
|
|
1615
1615
|
}
|
|
1616
|
-
const
|
|
1617
|
-
const w = Math.max(e.label.length *
|
|
1616
|
+
const charW2 = isProb ? 5.5 : 6.2;
|
|
1617
|
+
const w = Math.max(e.label.length * charW2 + 10, 18);
|
|
1618
1618
|
const h = 14;
|
|
1619
1619
|
inner.push(rect({
|
|
1620
1620
|
x: lx - w / 2,
|
|
@@ -7603,8 +7603,8 @@ function renderBox(box2) {
|
|
|
7603
7603
|
);
|
|
7604
7604
|
}
|
|
7605
7605
|
function approxLineWidth(line2) {
|
|
7606
|
-
const
|
|
7607
|
-
return line2.text.length *
|
|
7606
|
+
const charW2 = line2.style === "label" || line2.style === "count" ? 7.4 : 6.4;
|
|
7607
|
+
return line2.text.length * charW2;
|
|
7608
7608
|
}
|
|
7609
7609
|
function renderPrismaLayout(layout, config) {
|
|
7610
7610
|
const t = resolveBaseTheme(config?.theme ?? "default");
|
|
@@ -8271,35 +8271,35 @@ function ellipsePerimeterPoint(cx, cy, rx, ry, tx, ty) {
|
|
|
8271
8271
|
function isWideGlyph(cp) {
|
|
8272
8272
|
return cp >= 12288 && cp <= 40959 || cp >= 44032 && cp <= 55203 || cp >= 65280 && cp <= 65519;
|
|
8273
8273
|
}
|
|
8274
|
-
function estimateTextWidth2(s,
|
|
8274
|
+
function estimateTextWidth2(s, charW2) {
|
|
8275
8275
|
let w = 0;
|
|
8276
8276
|
for (const ch of s) {
|
|
8277
|
-
w += isWideGlyph(ch.codePointAt(0) ?? 0) ?
|
|
8277
|
+
w += isWideGlyph(ch.codePointAt(0) ?? 0) ? charW2 * 1.7 : charW2;
|
|
8278
8278
|
}
|
|
8279
8279
|
return w;
|
|
8280
8280
|
}
|
|
8281
8281
|
function sizeEllipse(uc) {
|
|
8282
|
-
const
|
|
8283
|
-
const nameW = estimateTextWidth2(uc.name,
|
|
8282
|
+
const C3 = USECASE_CONST;
|
|
8283
|
+
const nameW = estimateTextWidth2(uc.name, C3.CHAR_W_NAME);
|
|
8284
8284
|
let widest = nameW;
|
|
8285
8285
|
if (uc.stereotype) {
|
|
8286
|
-
widest = Math.max(widest, estimateTextWidth2(`\xAB${uc.stereotype}\xBB`,
|
|
8286
|
+
widest = Math.max(widest, estimateTextWidth2(`\xAB${uc.stereotype}\xBB`, C3.CHAR_W_EXT));
|
|
8287
8287
|
}
|
|
8288
8288
|
let stack = 0;
|
|
8289
|
-
if (uc.stereotype) stack +=
|
|
8290
|
-
stack +=
|
|
8289
|
+
if (uc.stereotype) stack += C3.STEREO_LH;
|
|
8290
|
+
stack += C3.NAME_LH;
|
|
8291
8291
|
const hasExt = uc.extensionPoints.length > 0;
|
|
8292
8292
|
if (hasExt) {
|
|
8293
8293
|
stack += 8;
|
|
8294
|
-
stack +=
|
|
8295
|
-
stack += uc.extensionPoints.length *
|
|
8296
|
-
widest = Math.max(widest, estimateTextWidth2(
|
|
8294
|
+
stack += C3.EXTPOINT_LH;
|
|
8295
|
+
stack += uc.extensionPoints.length * C3.EXTPOINT_LH;
|
|
8296
|
+
widest = Math.max(widest, estimateTextWidth2(C3.EXT_HEADER, C3.CHAR_W_EXT));
|
|
8297
8297
|
for (const ep of uc.extensionPoints) {
|
|
8298
|
-
widest = Math.max(widest, estimateTextWidth2(ep,
|
|
8298
|
+
widest = Math.max(widest, estimateTextWidth2(ep, C3.CHAR_W_EXT) + 16);
|
|
8299
8299
|
}
|
|
8300
8300
|
}
|
|
8301
|
-
const rx = Math.max(
|
|
8302
|
-
const ry = Math.max(
|
|
8301
|
+
const rx = Math.max(C3.MIN_RX, widest / 2 * Math.SQRT2 + C3.ELLIPSE_PAD_X);
|
|
8302
|
+
const ry = Math.max(C3.MIN_RY, stack / 2 * Math.SQRT2 + C3.ELLIPSE_PAD_Y);
|
|
8303
8303
|
const result = {
|
|
8304
8304
|
rx: Math.round(rx),
|
|
8305
8305
|
ry: Math.round(ry)
|
|
@@ -8384,7 +8384,7 @@ function classifyActorSides(ast) {
|
|
|
8384
8384
|
return sides;
|
|
8385
8385
|
}
|
|
8386
8386
|
function layoutUsecase(ast) {
|
|
8387
|
-
const
|
|
8387
|
+
const C3 = USECASE_CONST;
|
|
8388
8388
|
const ucIds = new Set(ast.usecases.map((u) => u.id));
|
|
8389
8389
|
const actorById = new Map(ast.actors.map((a) => [a.id, a]));
|
|
8390
8390
|
const sizes = /* @__PURE__ */ new Map();
|
|
@@ -8447,18 +8447,18 @@ function layoutUsecase(ast) {
|
|
|
8447
8447
|
}
|
|
8448
8448
|
}
|
|
8449
8449
|
const colMaxRx = columns.map(
|
|
8450
|
-
(col) => col.reduce((m, u) => Math.max(m, sizes.get(u.id).rx),
|
|
8450
|
+
(col) => col.reduce((m, u) => Math.max(m, sizes.get(u.id).rx), C3.MIN_RX)
|
|
8451
8451
|
);
|
|
8452
8452
|
const colCenterX = [];
|
|
8453
8453
|
let cursorX = 0;
|
|
8454
8454
|
for (let d = 0; d <= maxDepth; d++) {
|
|
8455
8455
|
cursorX += colMaxRx[d];
|
|
8456
8456
|
colCenterX[d] = cursorX;
|
|
8457
|
-
cursorX += colMaxRx[d] +
|
|
8457
|
+
cursorX += colMaxRx[d] + C3.COL_GAP;
|
|
8458
8458
|
}
|
|
8459
|
-
let maxRy =
|
|
8459
|
+
let maxRy = C3.MIN_RY;
|
|
8460
8460
|
for (const s of sizes.values()) maxRy = Math.max(maxRy, s.ry);
|
|
8461
|
-
const rowPitch = Math.max(
|
|
8461
|
+
const rowPitch = Math.max(C3.ROW_PITCH, 2 * maxRy + C3.ROW_GAP_MIN);
|
|
8462
8462
|
const ellipses = [];
|
|
8463
8463
|
const ellById = /* @__PURE__ */ new Map();
|
|
8464
8464
|
for (let d = 0; d <= maxDepth; d++) {
|
|
@@ -8481,7 +8481,7 @@ function layoutUsecase(ast) {
|
|
|
8481
8481
|
for (let i = 1; i < colE.length; i++) {
|
|
8482
8482
|
const prev = colE[i - 1];
|
|
8483
8483
|
const cur = colE[i];
|
|
8484
|
-
const minGap = prev.ry + cur.ry +
|
|
8484
|
+
const minGap = prev.ry + cur.ry + C3.ROW_GAP_MIN;
|
|
8485
8485
|
if (cur.cy - prev.cy < minGap) {
|
|
8486
8486
|
cur.cy = prev.cy + minGap;
|
|
8487
8487
|
if (cur.dividerY !== void 0) cur.dividerY = cur.cy + 6;
|
|
@@ -8502,10 +8502,10 @@ function layoutUsecase(ast) {
|
|
|
8502
8502
|
ucMaxY = 100;
|
|
8503
8503
|
}
|
|
8504
8504
|
const hasSubject = !!ast.system;
|
|
8505
|
-
const subjLeft = ucMinX -
|
|
8506
|
-
const subjRight = ucMaxX +
|
|
8507
|
-
const subjTop = ucMinY -
|
|
8508
|
-
const subjBottom = ucMaxY +
|
|
8505
|
+
const subjLeft = ucMinX - C3.SUBJECT_PAD;
|
|
8506
|
+
const subjRight = ucMaxX + C3.SUBJECT_PAD;
|
|
8507
|
+
const subjTop = ucMinY - C3.SUBJECT_TOP_PAD;
|
|
8508
|
+
const subjBottom = ucMaxY + C3.SUBJECT_BOTTOM_PAD;
|
|
8509
8509
|
const leftActors = ast.actors.filter((a) => sides.get(a.id) === "left");
|
|
8510
8510
|
const rightActors = ast.actors.filter((a) => sides.get(a.id) === "right");
|
|
8511
8511
|
const actorBoxes = [];
|
|
@@ -8513,17 +8513,17 @@ function layoutUsecase(ast) {
|
|
|
8513
8513
|
const subjCenterY = (subjTop + subjBottom) / 2;
|
|
8514
8514
|
function placeStack(actors, side) {
|
|
8515
8515
|
if (actors.length === 0) return;
|
|
8516
|
-
const totalH = (actors.length - 1) *
|
|
8516
|
+
const totalH = (actors.length - 1) * C3.ACTOR_PITCH;
|
|
8517
8517
|
let cy = subjCenterY - totalH / 2;
|
|
8518
8518
|
for (const a of actors) {
|
|
8519
8519
|
const isRect = a.kind === "external" || a.kind === "system";
|
|
8520
|
-
const w = isRect ?
|
|
8521
|
-
const h = isRect ?
|
|
8520
|
+
const w = isRect ? C3.EXTERNAL_W : C3.ACTOR_W;
|
|
8521
|
+
const h = isRect ? C3.EXTERNAL_H : C3.ACTOR_H;
|
|
8522
8522
|
let x;
|
|
8523
8523
|
if (side === "left") {
|
|
8524
|
-
x = subjLeft -
|
|
8524
|
+
x = subjLeft - C3.ACTOR_GAP - w;
|
|
8525
8525
|
} else {
|
|
8526
|
-
x = subjRight +
|
|
8526
|
+
x = subjRight + C3.ACTOR_GAP;
|
|
8527
8527
|
}
|
|
8528
8528
|
const y = cy - h / 2;
|
|
8529
8529
|
const anchorX = side === "left" ? x + w : x;
|
|
@@ -8540,7 +8540,7 @@ function layoutUsecase(ast) {
|
|
|
8540
8540
|
};
|
|
8541
8541
|
actorBoxes.push(box2);
|
|
8542
8542
|
actorById2.set(a.id, box2);
|
|
8543
|
-
cy +=
|
|
8543
|
+
cy += C3.ACTOR_PITCH;
|
|
8544
8544
|
}
|
|
8545
8545
|
}
|
|
8546
8546
|
placeStack(leftActors, "left");
|
|
@@ -8559,11 +8559,11 @@ function layoutUsecase(ast) {
|
|
|
8559
8559
|
minX = Math.min(minX, left);
|
|
8560
8560
|
maxX = Math.max(maxX, right);
|
|
8561
8561
|
minY = Math.min(minY, b.y);
|
|
8562
|
-
maxY = Math.max(maxY, b.y + b.height +
|
|
8562
|
+
maxY = Math.max(maxY, b.y + b.height + C3.ACTOR_LABEL_H);
|
|
8563
8563
|
}
|
|
8564
|
-
const titleSpace = ast.title ?
|
|
8565
|
-
const offsetX =
|
|
8566
|
-
const offsetY =
|
|
8564
|
+
const titleSpace = ast.title ? C3.TITLE_H : 0;
|
|
8565
|
+
const offsetX = C3.MARGIN - minX;
|
|
8566
|
+
const offsetY = C3.MARGIN + titleSpace - minY;
|
|
8567
8567
|
const translate = (px, py) => ({ x: px + offsetX, y: py + offsetY });
|
|
8568
8568
|
for (const e of ellipses) {
|
|
8569
8569
|
const p = translate(e.cx, e.cy);
|
|
@@ -8584,8 +8584,8 @@ function layoutUsecase(ast) {
|
|
|
8584
8584
|
height: subjBottom - subjTop
|
|
8585
8585
|
} : void 0;
|
|
8586
8586
|
if (subject && ast.system) subject.name = ast.system;
|
|
8587
|
-
const width = maxX - minX + 2 *
|
|
8588
|
-
const height = maxY - minY + 2 *
|
|
8587
|
+
const width = maxX - minX + 2 * C3.MARGIN;
|
|
8588
|
+
const height = maxY - minY + 2 * C3.MARGIN + titleSpace;
|
|
8589
8589
|
const edges = [];
|
|
8590
8590
|
const trees = [];
|
|
8591
8591
|
const genByParent = /* @__PURE__ */ new Map();
|
|
@@ -8625,7 +8625,7 @@ function layoutUsecase(ast) {
|
|
|
8625
8625
|
return { x, y };
|
|
8626
8626
|
}
|
|
8627
8627
|
for (const [parentId, rels] of genByParent) {
|
|
8628
|
-
const useTree = ast.generalizationTree && rels.length >=
|
|
8628
|
+
const useTree = ast.generalizationTree && rels.length >= C3.GEN_TREE_THRESHOLD;
|
|
8629
8629
|
const allActors = actorById2.has(parentId) && rels.every((r7) => actorById2.has(r7.source));
|
|
8630
8630
|
if (allActors) {
|
|
8631
8631
|
const side = sides.get(parentId) ?? "left";
|
|
@@ -8677,8 +8677,8 @@ function layoutUsecase(ast) {
|
|
|
8677
8677
|
const dirX = avgX - parent.cx;
|
|
8678
8678
|
const dirY = avgY - parent.cy;
|
|
8679
8679
|
const len = Math.hypot(dirX, dirY) || 1;
|
|
8680
|
-
const jx = pPt.x + dirX / len *
|
|
8681
|
-
const jy = pPt.y + dirY / len *
|
|
8680
|
+
const jx = pPt.x + dirX / len * C3.GEN_JUNCTION_OFFSET;
|
|
8681
|
+
const jy = pPt.y + dirY / len * C3.GEN_JUNCTION_OFFSET;
|
|
8682
8682
|
const legPaths = [];
|
|
8683
8683
|
for (const r7 of rels) {
|
|
8684
8684
|
const cPt = perimeter(r7.source, jx, jy);
|
|
@@ -10113,7 +10113,7 @@ function routeEdge2(s, t, direction) {
|
|
|
10113
10113
|
return { d, labelX: mid, labelY: (sy + ty) / 2 };
|
|
10114
10114
|
}
|
|
10115
10115
|
function layoutNetwork(ast, schedule) {
|
|
10116
|
-
const
|
|
10116
|
+
const C3 = PERT_CONST;
|
|
10117
10117
|
const { rank, maxRank } = assignRanks(ast);
|
|
10118
10118
|
const layers = orderLayers(ast, schedule, rank, maxRank);
|
|
10119
10119
|
const dir = ast.direction;
|
|
@@ -10122,16 +10122,16 @@ function layoutNetwork(ast, schedule) {
|
|
|
10122
10122
|
const colExtent = layers.map((layer) => {
|
|
10123
10123
|
const n = layer.length;
|
|
10124
10124
|
if (n === 0) return 0;
|
|
10125
|
-
const unit = dir === "TB" ?
|
|
10126
|
-
const gap = dir === "TB" ?
|
|
10125
|
+
const unit = dir === "TB" ? C3.BOX_W : C3.BOX_H;
|
|
10126
|
+
const gap = dir === "TB" ? C3.H_GAP : C3.V_GAP;
|
|
10127
10127
|
return n * unit + (n - 1) * gap;
|
|
10128
10128
|
});
|
|
10129
10129
|
const maxExtent = Math.max(0, ...colExtent);
|
|
10130
10130
|
const hasSentinels = ast.showSentinels;
|
|
10131
|
-
const sentLead = hasSentinels ?
|
|
10132
|
-
const titleH = ast.title ?
|
|
10133
|
-
const originPrimary = dir === "TB" ?
|
|
10134
|
-
const originCross = dir === "TB" ?
|
|
10131
|
+
const sentLead = hasSentinels ? C3.SENT_R * 2 + C3.H_GAP : 0;
|
|
10132
|
+
const titleH = ast.title ? C3.TITLE_H : 0;
|
|
10133
|
+
const originPrimary = dir === "TB" ? C3.PAD + titleH + sentLead : C3.PAD + sentLead;
|
|
10134
|
+
const originCross = dir === "TB" ? C3.PAD : C3.PAD + titleH;
|
|
10135
10135
|
const boxes = [];
|
|
10136
10136
|
const boxById = /* @__PURE__ */ new Map();
|
|
10137
10137
|
for (let r7 = 0; r7 <= maxRank; r7++) {
|
|
@@ -10142,20 +10142,20 @@ function layoutNetwork(ast, schedule) {
|
|
|
10142
10142
|
for (const id of layer) {
|
|
10143
10143
|
const t = byId.get(id);
|
|
10144
10144
|
const computed = schedule.computed.get(id);
|
|
10145
|
-
const w = t.milestone ?
|
|
10146
|
-
const h =
|
|
10145
|
+
const w = t.milestone ? C3.MS_W : C3.BOX_W;
|
|
10146
|
+
const h = C3.BOX_H;
|
|
10147
10147
|
let x;
|
|
10148
10148
|
let y;
|
|
10149
10149
|
if (dir === "TB") {
|
|
10150
|
-
const rankPos = originPrimary + r7 * (
|
|
10151
|
-
x = cursor + (
|
|
10150
|
+
const rankPos = originPrimary + r7 * (C3.BOX_H + C3.H_GAP);
|
|
10151
|
+
x = cursor + (C3.BOX_W - w) / 2;
|
|
10152
10152
|
y = rankPos;
|
|
10153
|
-
cursor +=
|
|
10153
|
+
cursor += C3.BOX_W + C3.H_GAP;
|
|
10154
10154
|
} else {
|
|
10155
|
-
const rankPos = originPrimary + r7 * (
|
|
10156
|
-
x = rankPos + (
|
|
10155
|
+
const rankPos = originPrimary + r7 * (C3.BOX_W + C3.H_GAP);
|
|
10156
|
+
x = rankPos + (C3.BOX_W - w) / 2;
|
|
10157
10157
|
y = cursor;
|
|
10158
|
-
cursor +=
|
|
10158
|
+
cursor += C3.BOX_H + C3.V_GAP;
|
|
10159
10159
|
}
|
|
10160
10160
|
const box2 = {
|
|
10161
10161
|
id,
|
|
@@ -10202,11 +10202,11 @@ function layoutNetwork(ast, schedule) {
|
|
|
10202
10202
|
const sentinels = [];
|
|
10203
10203
|
if (hasSentinels) {
|
|
10204
10204
|
const contentMidCross = originCross + maxExtent / 2;
|
|
10205
|
-
const startPrimary =
|
|
10206
|
-
const finishPrimary = maxPrimary +
|
|
10205
|
+
const startPrimary = C3.PAD + C3.SENT_R;
|
|
10206
|
+
const finishPrimary = maxPrimary + C3.H_GAP + C3.SENT_R;
|
|
10207
10207
|
const place = (primary) => dir === "TB" ? { cx: contentMidCross, cy: primary } : { cx: primary, cy: contentMidCross };
|
|
10208
|
-
sentinels.push({ id: "__start__", label: "Start", r:
|
|
10209
|
-
sentinels.push({ id: "__finish__", label: "Finish", r:
|
|
10208
|
+
sentinels.push({ id: "__start__", label: "Start", r: C3.SENT_R, ...place(startPrimary) });
|
|
10209
|
+
sentinels.push({ id: "__finish__", label: "Finish", r: C3.SENT_R, ...place(finishPrimary) });
|
|
10210
10210
|
const usedAsPred = /* @__PURE__ */ new Set();
|
|
10211
10211
|
for (const t of ast.tasks) for (const dep of t.deps) usedAsPred.add(dep.pred);
|
|
10212
10212
|
const startSent = sentinels[0];
|
|
@@ -10220,19 +10220,19 @@ function layoutNetwork(ast, schedule) {
|
|
|
10220
10220
|
edges.push(sentinelEdge(finishSent, b, dir, false, schedule.computed.get(t.id)));
|
|
10221
10221
|
}
|
|
10222
10222
|
}
|
|
10223
|
-
maxPrimary = finishPrimary +
|
|
10223
|
+
maxPrimary = finishPrimary + C3.SENT_R;
|
|
10224
10224
|
}
|
|
10225
10225
|
const crossEnd = Math.max(maxCross, originCross + maxExtent);
|
|
10226
10226
|
let width;
|
|
10227
10227
|
let footerY;
|
|
10228
10228
|
if (dir === "TB") {
|
|
10229
|
-
width = crossEnd +
|
|
10229
|
+
width = crossEnd + C3.PAD;
|
|
10230
10230
|
footerY = maxPrimary + 14;
|
|
10231
10231
|
} else {
|
|
10232
|
-
width = maxPrimary +
|
|
10232
|
+
width = maxPrimary + C3.PAD;
|
|
10233
10233
|
footerY = crossEnd + 14;
|
|
10234
10234
|
}
|
|
10235
|
-
const height = footerY +
|
|
10235
|
+
const height = footerY + C3.FOOTER_H;
|
|
10236
10236
|
return {
|
|
10237
10237
|
width: Math.ceil(width),
|
|
10238
10238
|
height: Math.ceil(height),
|
|
@@ -10310,7 +10310,7 @@ function buildDependencyEdges(ast, schedule, boxById, dir) {
|
|
|
10310
10310
|
return edges;
|
|
10311
10311
|
}
|
|
10312
10312
|
function layoutSwimlane2(ast, schedule) {
|
|
10313
|
-
const
|
|
10313
|
+
const C3 = PERT_CONST;
|
|
10314
10314
|
const { rank, maxRank } = assignRanks(ast);
|
|
10315
10315
|
const byId = /* @__PURE__ */ new Map();
|
|
10316
10316
|
for (const t of ast.tasks) byId.set(t.id, t);
|
|
@@ -10341,9 +10341,9 @@ function layoutSwimlane2(ast, schedule) {
|
|
|
10341
10341
|
return declIndex.get(a) - declIndex.get(b);
|
|
10342
10342
|
});
|
|
10343
10343
|
}
|
|
10344
|
-
const titleH = ast.title ?
|
|
10345
|
-
const topY =
|
|
10346
|
-
const colX = (r7) =>
|
|
10344
|
+
const titleH = ast.title ? C3.TITLE_H : 0;
|
|
10345
|
+
const topY = C3.PAD + titleH;
|
|
10346
|
+
const colX = (r7) => C3.LANE_LABEL_W + C3.PAD + r7 * (C3.BOX_W + C3.H_GAP);
|
|
10347
10347
|
const lanes = [];
|
|
10348
10348
|
const laneY = /* @__PURE__ */ new Map();
|
|
10349
10349
|
const laneH = /* @__PURE__ */ new Map();
|
|
@@ -10354,7 +10354,7 @@ function layoutSwimlane2(ast, schedule) {
|
|
|
10354
10354
|
const arr = cell.get(key(lane, r7));
|
|
10355
10355
|
if (arr) stack = Math.max(stack, arr.length);
|
|
10356
10356
|
}
|
|
10357
|
-
const bandH = stack *
|
|
10357
|
+
const bandH = stack * C3.BOX_H + (stack - 1) * C3.V_GAP + 2 * C3.LANE_PAD;
|
|
10358
10358
|
laneY.set(lane, cursor);
|
|
10359
10359
|
laneH.set(lane, bandH);
|
|
10360
10360
|
lanes.push({ name: lane, y: cursor, height: bandH, alt: i % 2 === 1 });
|
|
@@ -10369,13 +10369,13 @@ function layoutSwimlane2(ast, schedule) {
|
|
|
10369
10369
|
for (let r7 = 0; r7 <= maxRank; r7++) {
|
|
10370
10370
|
const arr = cell.get(key(lane, r7));
|
|
10371
10371
|
if (!arr) continue;
|
|
10372
|
-
const colInnerH = arr.length *
|
|
10372
|
+
const colInnerH = arr.length * C3.BOX_H + (arr.length - 1) * C3.V_GAP;
|
|
10373
10373
|
const y0 = bandTop + (bandH - colInnerH) / 2;
|
|
10374
10374
|
arr.forEach((id, idx) => {
|
|
10375
10375
|
const t = byId.get(id);
|
|
10376
|
-
const w = t.milestone ?
|
|
10377
|
-
const x = colX(r7) + (
|
|
10378
|
-
const y = y0 + idx * (
|
|
10376
|
+
const w = t.milestone ? C3.MS_W : C3.BOX_W;
|
|
10377
|
+
const x = colX(r7) + (C3.BOX_W - w) / 2;
|
|
10378
|
+
const y = y0 + idx * (C3.BOX_H + C3.V_GAP);
|
|
10379
10379
|
const box2 = {
|
|
10380
10380
|
id,
|
|
10381
10381
|
task: t,
|
|
@@ -10383,7 +10383,7 @@ function layoutSwimlane2(ast, schedule) {
|
|
|
10383
10383
|
x,
|
|
10384
10384
|
y,
|
|
10385
10385
|
width: w,
|
|
10386
|
-
height:
|
|
10386
|
+
height: C3.BOX_H,
|
|
10387
10387
|
milestone: t.milestone,
|
|
10388
10388
|
rank: r7
|
|
10389
10389
|
};
|
|
@@ -10393,9 +10393,9 @@ function layoutSwimlane2(ast, schedule) {
|
|
|
10393
10393
|
}
|
|
10394
10394
|
}
|
|
10395
10395
|
const edges = buildDependencyEdges(ast, schedule, boxById, "LR");
|
|
10396
|
-
const width = colX(maxRank) +
|
|
10396
|
+
const width = colX(maxRank) + C3.BOX_W + C3.PAD;
|
|
10397
10397
|
const footerY = contentBottom + 14;
|
|
10398
|
-
const height = footerY +
|
|
10398
|
+
const height = footerY + C3.FOOTER_H;
|
|
10399
10399
|
return {
|
|
10400
10400
|
width: Math.ceil(width),
|
|
10401
10401
|
height: Math.ceil(height),
|
|
@@ -10413,20 +10413,20 @@ function layoutSwimlane2(ast, schedule) {
|
|
|
10413
10413
|
};
|
|
10414
10414
|
}
|
|
10415
10415
|
function layoutTimescaled(ast, schedule) {
|
|
10416
|
-
const
|
|
10416
|
+
const C3 = PERT_CONST;
|
|
10417
10417
|
const T = schedule.projectDuration || 1;
|
|
10418
10418
|
const pxPerUnit = Math.min(56, Math.max(16, 1300 / T));
|
|
10419
|
-
const titleH = ast.title ?
|
|
10420
|
-
const leftPad =
|
|
10421
|
-
const topPad =
|
|
10419
|
+
const titleH = ast.title ? C3.TITLE_H : 0;
|
|
10420
|
+
const leftPad = C3.PAD;
|
|
10421
|
+
const topPad = C3.PAD + titleH + 14;
|
|
10422
10422
|
const intervals = ast.tasks.map((t) => {
|
|
10423
10423
|
const c = schedule.computed.get(t.id);
|
|
10424
10424
|
if (t.milestone) {
|
|
10425
10425
|
const cx = leftPad + c.es * pxPerUnit;
|
|
10426
|
-
return { id: t.id, x: cx -
|
|
10426
|
+
return { id: t.id, x: cx - C3.TS_MS_W / 2, w: C3.TS_MS_W };
|
|
10427
10427
|
}
|
|
10428
10428
|
const x = leftPad + c.es * pxPerUnit;
|
|
10429
|
-
const w = Math.max(
|
|
10429
|
+
const w = Math.max(C3.TS_MIN_W, t.duration * pxPerUnit);
|
|
10430
10430
|
return { id: t.id, x, w };
|
|
10431
10431
|
});
|
|
10432
10432
|
intervals.sort((a, b) => a.x - b.x || a.w - b.w);
|
|
@@ -10435,7 +10435,7 @@ function layoutTimescaled(ast, schedule) {
|
|
|
10435
10435
|
for (const iv of intervals) {
|
|
10436
10436
|
let placed = -1;
|
|
10437
10437
|
for (let l = 0; l < laneRight.length; l++) {
|
|
10438
|
-
if (iv.x >= laneRight[l] +
|
|
10438
|
+
if (iv.x >= laneRight[l] + C3.TS_GAP) {
|
|
10439
10439
|
placed = l;
|
|
10440
10440
|
break;
|
|
10441
10441
|
}
|
|
@@ -10457,7 +10457,7 @@ function layoutTimescaled(ast, schedule) {
|
|
|
10457
10457
|
for (const t of ast.tasks) {
|
|
10458
10458
|
const iv = intervalById.get(t.id);
|
|
10459
10459
|
const lane = laneOf.get(t.id);
|
|
10460
|
-
const y = topPad + lane * (
|
|
10460
|
+
const y = topPad + lane * (C3.TS_BOX_H + C3.TS_LANE_GAP);
|
|
10461
10461
|
const box2 = {
|
|
10462
10462
|
id: t.id,
|
|
10463
10463
|
task: t,
|
|
@@ -10465,7 +10465,7 @@ function layoutTimescaled(ast, schedule) {
|
|
|
10465
10465
|
x: iv.x,
|
|
10466
10466
|
y,
|
|
10467
10467
|
width: iv.w,
|
|
10468
|
-
height:
|
|
10468
|
+
height: C3.TS_BOX_H,
|
|
10469
10469
|
milestone: t.milestone,
|
|
10470
10470
|
rank: 0
|
|
10471
10471
|
};
|
|
@@ -10493,7 +10493,7 @@ function layoutTimescaled(ast, schedule) {
|
|
|
10493
10493
|
edges.push(edge);
|
|
10494
10494
|
}
|
|
10495
10495
|
}
|
|
10496
|
-
const contentBottom = topPad + laneCount *
|
|
10496
|
+
const contentBottom = topPad + laneCount * C3.TS_BOX_H + (laneCount - 1) * C3.TS_LANE_GAP;
|
|
10497
10497
|
const axisBaseline = contentBottom + 22;
|
|
10498
10498
|
const timeEnd = leftPad + T * pxPerUnit;
|
|
10499
10499
|
let maxRight = timeEnd;
|
|
@@ -10509,8 +10509,8 @@ function layoutTimescaled(ast, schedule) {
|
|
|
10509
10509
|
major: Math.abs(rounded % majorStep) < 1e-9
|
|
10510
10510
|
});
|
|
10511
10511
|
}
|
|
10512
|
-
const width = Math.ceil(Math.max(maxRight, timeEnd) +
|
|
10513
|
-
const height = Math.ceil(axisBaseline +
|
|
10512
|
+
const width = Math.ceil(Math.max(maxRight, timeEnd) + C3.PAD);
|
|
10513
|
+
const height = Math.ceil(axisBaseline + C3.AXIS_H + C3.FOOTER_H);
|
|
10514
10514
|
return {
|
|
10515
10515
|
width,
|
|
10516
10516
|
height,
|
|
@@ -12163,7 +12163,7 @@ var SequenceLayout = class {
|
|
|
12163
12163
|
left = mid - 20;
|
|
12164
12164
|
right = mid + 20;
|
|
12165
12165
|
}
|
|
12166
|
-
const
|
|
12166
|
+
const frame2 = {
|
|
12167
12167
|
op,
|
|
12168
12168
|
x: left,
|
|
12169
12169
|
y: frameTop,
|
|
@@ -12171,8 +12171,8 @@ var SequenceLayout = class {
|
|
|
12171
12171
|
height: frameBottom - frameTop,
|
|
12172
12172
|
operands: operandGeom
|
|
12173
12173
|
};
|
|
12174
|
-
if (messageSet && messageSet.length)
|
|
12175
|
-
this.fragments.push(
|
|
12174
|
+
if (messageSet && messageSet.length) frame2.messageSet = messageSet;
|
|
12175
|
+
this.fragments.push(frame2);
|
|
12176
12176
|
this.noteRight(left, right - left);
|
|
12177
12177
|
this.y = frameBottom;
|
|
12178
12178
|
}
|
|
@@ -12840,7 +12840,7 @@ var PETRI_CONST = {
|
|
|
12840
12840
|
CHAR_W: 6.2
|
|
12841
12841
|
};
|
|
12842
12842
|
function layoutPetri(ast) {
|
|
12843
|
-
const
|
|
12843
|
+
const C3 = PETRI_CONST;
|
|
12844
12844
|
const dir = ast.direction;
|
|
12845
12845
|
const warnings = [...ast.warnings];
|
|
12846
12846
|
const kindOf = /* @__PURE__ */ new Map();
|
|
@@ -12924,10 +12924,10 @@ function layoutPetri(ast) {
|
|
|
12924
12924
|
}
|
|
12925
12925
|
}
|
|
12926
12926
|
const sizeOf5 = (id) => {
|
|
12927
|
-
if (kindOf.get(id) === "place") return { halfW:
|
|
12927
|
+
if (kindOf.get(id) === "place") return { halfW: C3.PLACE_R, halfH: C3.PLACE_R, r: C3.PLACE_R };
|
|
12928
12928
|
const tr = ast.transitions.find((t) => t.id === id);
|
|
12929
|
-
const long = tr.kind === "timed" ?
|
|
12930
|
-
const thin = tr.kind === "timed" ?
|
|
12929
|
+
const long = tr.kind === "timed" ? C3.TRANS_BOX_H : C3.TRANS_BAR_H;
|
|
12930
|
+
const thin = tr.kind === "timed" ? C3.TRANS_BOX_W : C3.TRANS_BAR_W;
|
|
12931
12931
|
const halfW = dir === "lr" ? thin / 2 : long / 2;
|
|
12932
12932
|
const halfH = dir === "lr" ? long / 2 : thin / 2;
|
|
12933
12933
|
return { halfW, halfH, r: 0 };
|
|
@@ -12941,15 +12941,15 @@ function layoutPetri(ast) {
|
|
|
12941
12941
|
return dir === "lr" ? s.halfH : s.halfW;
|
|
12942
12942
|
};
|
|
12943
12943
|
const layerHalf = layers.map((arr) => Math.max(0, ...arr.map(flowHalf)));
|
|
12944
|
-
const slot = Math.max(0, ...ids.map(crossHalf)) * 2 +
|
|
12944
|
+
const slot = Math.max(0, ...ids.map(crossHalf)) * 2 + C3.RANK_GAP;
|
|
12945
12945
|
const maxCount = Math.max(1, ...layers.map((a) => a.length));
|
|
12946
|
-
const crossCenter =
|
|
12946
|
+
const crossCenter = C3.MARGIN + C3.LABEL_LINE_H * 2 + maxCount * slot / 2;
|
|
12947
12947
|
const flowCenter = [];
|
|
12948
|
-
let acc =
|
|
12948
|
+
let acc = C3.MARGIN + C3.LABEL_LINE_H * 2;
|
|
12949
12949
|
for (let L = 0; L < layers.length; L++) {
|
|
12950
12950
|
acc += layerHalf[L];
|
|
12951
12951
|
flowCenter[L] = acc;
|
|
12952
|
-
acc += layerHalf[L] +
|
|
12952
|
+
acc += layerHalf[L] + C3.LAYER_GAP;
|
|
12953
12953
|
}
|
|
12954
12954
|
const geom = /* @__PURE__ */ new Map();
|
|
12955
12955
|
layers.forEach((arr, L) => {
|
|
@@ -13032,12 +13032,12 @@ function layoutPetri(ast) {
|
|
|
13032
13032
|
if (dir === "lr") {
|
|
13033
13033
|
const pA = boundary(A, 0, 1);
|
|
13034
13034
|
const pB = boundary(B, 0, 1);
|
|
13035
|
-
const bowY = bandMaxCross +
|
|
13035
|
+
const bowY = bandMaxCross + C3.BACKEDGE_BOW;
|
|
13036
13036
|
points = [pA, { x: pA.x, y: bowY }, { x: pB.x, y: bowY }, pB];
|
|
13037
13037
|
} else {
|
|
13038
13038
|
const pA = boundary(A, 1, 0);
|
|
13039
13039
|
const pB = boundary(B, 1, 0);
|
|
13040
|
-
const bowX = bandMaxCross +
|
|
13040
|
+
const bowX = bandMaxCross + C3.BACKEDGE_BOW;
|
|
13041
13041
|
points = [pA, { x: bowX, y: pA.y }, { x: bowX, y: pB.y }, pB];
|
|
13042
13042
|
}
|
|
13043
13043
|
}
|
|
@@ -13048,8 +13048,8 @@ function layoutPetri(ast) {
|
|
|
13048
13048
|
const ddx = p1.x - p0.x;
|
|
13049
13049
|
const ddy = p1.y - p0.y;
|
|
13050
13050
|
const dl = Math.hypot(ddx, ddy) || 1;
|
|
13051
|
-
const labelX = mx - ddy / dl *
|
|
13052
|
-
const labelY = my + ddx / dl *
|
|
13051
|
+
const labelX = mx - ddy / dl * C3.ARC_WEIGHT_OFFSET;
|
|
13052
|
+
const labelY = my + ddx / dl * C3.ARC_WEIGHT_OFFSET;
|
|
13053
13053
|
return { arc: a, type: a.type, weight: a.weight, points, reversed, labelX, labelY };
|
|
13054
13054
|
});
|
|
13055
13055
|
const hasIncoming = (pid2) => ast.arcs.some((a) => a.to === pid2);
|
|
@@ -13086,24 +13086,24 @@ function layoutPetri(ast) {
|
|
|
13086
13086
|
bb.maxY = Math.max(bb.maxY, y0, y1);
|
|
13087
13087
|
};
|
|
13088
13088
|
const addPt = (p) => addBox(p.x, p.y, p.x, p.y);
|
|
13089
|
-
const labelW = (s) => s ? s.length *
|
|
13089
|
+
const labelW = (s) => s ? s.length * C3.CHAR_W : 0;
|
|
13090
13090
|
for (const pb of placeBoxes) {
|
|
13091
13091
|
addBox(pb.cx - pb.r, pb.cy - pb.r, pb.cx + pb.r, pb.cy + pb.r);
|
|
13092
13092
|
const lw = Math.max(labelW(pb.place.id), labelW(pb.place.label)) / 2;
|
|
13093
|
-
addBox(pb.cx - lw, pb.cy - pb.r -
|
|
13094
|
-
if (pb.place.capacity !== void 0) addBox(pb.cx, pb.cy + pb.r, pb.cx + 24, pb.cy + pb.r +
|
|
13093
|
+
addBox(pb.cx - lw, pb.cy - pb.r - C3.LABEL_LINE_H * 2, pb.cx + lw, pb.cy);
|
|
13094
|
+
if (pb.place.capacity !== void 0) addBox(pb.cx, pb.cy + pb.r, pb.cx + 24, pb.cy + pb.r + C3.LABEL_LINE_H);
|
|
13095
13095
|
}
|
|
13096
13096
|
for (const tb of transBoxes) {
|
|
13097
13097
|
addBox(tb.cx - tb.w / 2, tb.cy - tb.h / 2, tb.cx + tb.w / 2, tb.cy + tb.h / 2);
|
|
13098
13098
|
const lw = Math.max(labelW(tb.transition.id), labelW(tb.transition.label)) / 2;
|
|
13099
|
-
addBox(tb.cx - lw, tb.cy - tb.h / 2 -
|
|
13099
|
+
addBox(tb.cx - lw, tb.cy - tb.h / 2 - C3.LABEL_LINE_H * 2, tb.cx + lw, tb.cy);
|
|
13100
13100
|
}
|
|
13101
13101
|
for (const ag of arcGeoms) {
|
|
13102
13102
|
ag.points.forEach(addPt);
|
|
13103
13103
|
if (ag.weight > 1) addBox(ag.labelX - 6, ag.labelY - 8, ag.labelX + 6, ag.labelY + 4);
|
|
13104
13104
|
}
|
|
13105
|
-
const dx =
|
|
13106
|
-
const dy =
|
|
13105
|
+
const dx = C3.MARGIN - bb.minX;
|
|
13106
|
+
const dy = C3.MARGIN - bb.minY;
|
|
13107
13107
|
const shift = (p) => ({ x: p.x + dx, y: p.y + dy });
|
|
13108
13108
|
placeBoxes.forEach((pb) => {
|
|
13109
13109
|
pb.cx += dx;
|
|
@@ -13118,8 +13118,8 @@ function layoutPetri(ast) {
|
|
|
13118
13118
|
ag.labelX += dx;
|
|
13119
13119
|
ag.labelY += dy;
|
|
13120
13120
|
});
|
|
13121
|
-
const width = bb.maxX - bb.minX + 2 *
|
|
13122
|
-
const height = bb.maxY - bb.minY + 2 *
|
|
13121
|
+
const width = bb.maxX - bb.minX + 2 * C3.MARGIN;
|
|
13122
|
+
const height = bb.maxY - bb.minY + 2 * C3.MARGIN;
|
|
13123
13123
|
const subclass = detectSubclass(ast);
|
|
13124
13124
|
return {
|
|
13125
13125
|
width: Math.round(width),
|
|
@@ -17464,6 +17464,19 @@ function truncate3(s, n) {
|
|
|
17464
17464
|
return s.length <= n ? s : s.slice(0, n - 1) + "\u2026";
|
|
17465
17465
|
}
|
|
17466
17466
|
|
|
17467
|
+
// src/core/format.ts
|
|
17468
|
+
function formatProbability(n) {
|
|
17469
|
+
if (!Number.isFinite(n)) return String(n);
|
|
17470
|
+
if (n <= 0) return "0";
|
|
17471
|
+
if (n >= 1) return "1";
|
|
17472
|
+
if (n < 1e-3) return n.toExponential(2);
|
|
17473
|
+
for (let p = 3; p <= 9; p++) {
|
|
17474
|
+
const s = parseFloat(n.toPrecision(p));
|
|
17475
|
+
if (s > 0 && s < 1) return String(s);
|
|
17476
|
+
}
|
|
17477
|
+
return String(parseFloat(n.toPrecision(9)));
|
|
17478
|
+
}
|
|
17479
|
+
|
|
17467
17480
|
// src/diagrams/faulttree/analysis.ts
|
|
17468
17481
|
var EXPANSION_CAP = 5e4;
|
|
17469
17482
|
var EXACT_CUTSET_CAP = 20;
|
|
@@ -17714,7 +17727,7 @@ var FAULTTREE_CONST = {
|
|
|
17714
17727
|
TITLE_H: 34
|
|
17715
17728
|
};
|
|
17716
17729
|
function eventBox(label) {
|
|
17717
|
-
const
|
|
17730
|
+
const C3 = FAULTTREE_CONST;
|
|
17718
17731
|
const words = label.split(/\s+/).filter(Boolean);
|
|
17719
17732
|
const lines = [];
|
|
17720
17733
|
let cur = "";
|
|
@@ -17732,11 +17745,11 @@ function eventBox(label) {
|
|
|
17732
17745
|
else if (cur && lines.length === 2) lines[1] = `${lines[1]} ${cur}`;
|
|
17733
17746
|
if (lines.length === 0) lines.push(label);
|
|
17734
17747
|
const longest = Math.max(...lines.map((l) => l.length), 1);
|
|
17735
|
-
const width = Math.min(
|
|
17748
|
+
const width = Math.min(C3.EVENT_MAX_W, Math.max(C3.EVENT_MIN_W, Math.ceil(longest * C3.CHAR_W) + 2 * C3.EVENT_PAD_X));
|
|
17736
17749
|
return { width, lines };
|
|
17737
17750
|
}
|
|
17738
17751
|
function layoutFaultTree(ast) {
|
|
17739
|
-
const
|
|
17752
|
+
const C3 = FAULTTREE_CONST;
|
|
17740
17753
|
const analysis = analyseFaultTree(ast);
|
|
17741
17754
|
const byId = new Map(ast.events.map((e) => [e.id, e]));
|
|
17742
17755
|
const refCount = /* @__PURE__ */ new Map();
|
|
@@ -17752,13 +17765,13 @@ function layoutFaultTree(ast) {
|
|
|
17752
17765
|
case "intermediate":
|
|
17753
17766
|
return eventBox(label).width;
|
|
17754
17767
|
case "basic":
|
|
17755
|
-
return 2 *
|
|
17768
|
+
return 2 * C3.BASIC_R;
|
|
17756
17769
|
case "undeveloped":
|
|
17757
|
-
return
|
|
17770
|
+
return C3.DIAMOND_W;
|
|
17758
17771
|
case "house":
|
|
17759
|
-
return
|
|
17772
|
+
return C3.HOUSE_W;
|
|
17760
17773
|
case "condition":
|
|
17761
|
-
return
|
|
17774
|
+
return C3.COND_W;
|
|
17762
17775
|
}
|
|
17763
17776
|
};
|
|
17764
17777
|
const build = (eventId, depth, onPath) => {
|
|
@@ -17805,9 +17818,9 @@ function layoutFaultTree(ast) {
|
|
|
17805
17818
|
}
|
|
17806
17819
|
let x = originX;
|
|
17807
17820
|
for (const c of n.children) {
|
|
17808
|
-
x += place(c, x) +
|
|
17821
|
+
x += place(c, x) + C3.SIBLING_GAP;
|
|
17809
17822
|
}
|
|
17810
|
-
const childrenWidth = x - originX -
|
|
17823
|
+
const childrenWidth = x - originX - C3.SIBLING_GAP;
|
|
17811
17824
|
if (n.width <= childrenWidth) {
|
|
17812
17825
|
n.cx = (n.children[0].cx + n.children[n.children.length - 1].cx) / 2;
|
|
17813
17826
|
return childrenWidth;
|
|
@@ -17817,24 +17830,24 @@ function layoutFaultTree(ast) {
|
|
|
17817
17830
|
n.cx = originX + n.width / 2;
|
|
17818
17831
|
return n.width;
|
|
17819
17832
|
};
|
|
17820
|
-
const baseY =
|
|
17821
|
-
place(root,
|
|
17822
|
-
const ROW_PITCH =
|
|
17833
|
+
const baseY = C3.CANVAS_PAD + (ast.title ? C3.TITLE_H : 0) + (ast.analysis.probability ? 18 : 0);
|
|
17834
|
+
place(root, C3.CANVAS_PAD);
|
|
17835
|
+
const ROW_PITCH = C3.EVENT_H + C3.GATE_GAP + C3.GATE_H + C3.LEVEL_GAP;
|
|
17823
17836
|
const rowY = (depth) => baseY + depth * ROW_PITCH;
|
|
17824
|
-
const centerY = (n) => n.topY +
|
|
17837
|
+
const centerY = (n) => n.topY + C3.EVENT_H / 2;
|
|
17825
17838
|
const halfH = (role) => {
|
|
17826
17839
|
switch (role) {
|
|
17827
17840
|
case "top":
|
|
17828
17841
|
case "intermediate":
|
|
17829
|
-
return
|
|
17842
|
+
return C3.EVENT_H / 2;
|
|
17830
17843
|
case "basic":
|
|
17831
|
-
return
|
|
17844
|
+
return C3.BASIC_R;
|
|
17832
17845
|
case "undeveloped":
|
|
17833
|
-
return
|
|
17846
|
+
return C3.DIAMOND_W / 2;
|
|
17834
17847
|
case "house":
|
|
17835
|
-
return
|
|
17848
|
+
return C3.HOUSE_H / 2;
|
|
17836
17849
|
case "condition":
|
|
17837
|
-
return
|
|
17850
|
+
return C3.COND_H / 2;
|
|
17838
17851
|
}
|
|
17839
17852
|
};
|
|
17840
17853
|
const topAnchorY = (n) => n.role === "top" || n.role === "intermediate" ? n.topY : centerY(n) - halfH(n.role);
|
|
@@ -17848,7 +17861,7 @@ function layoutFaultTree(ast) {
|
|
|
17848
17861
|
cx: n.cx,
|
|
17849
17862
|
topY: n.topY,
|
|
17850
17863
|
width: n.width,
|
|
17851
|
-
height: n.role === "top" || n.role === "intermediate" ?
|
|
17864
|
+
height: n.role === "top" || n.role === "intermediate" ? C3.EVENT_H : 2 * halfH(n.role),
|
|
17852
17865
|
depth: n.depth,
|
|
17853
17866
|
shared: n.shared
|
|
17854
17867
|
};
|
|
@@ -17856,28 +17869,28 @@ function layoutFaultTree(ast) {
|
|
|
17856
17869
|
(instancesByEvent.get(n.eventId) ?? instancesByEvent.set(n.eventId, []).get(n.eventId)).push(lay);
|
|
17857
17870
|
if (n.gate && n.children.length > 0) {
|
|
17858
17871
|
const gx = n.cx;
|
|
17859
|
-
const gy = n.topY +
|
|
17872
|
+
const gy = n.topY + C3.EVENT_H + C3.GATE_GAP + C3.GATE_H / 2;
|
|
17860
17873
|
const glay = {
|
|
17861
17874
|
gate: n.gate,
|
|
17862
17875
|
ownerInstanceId: n.instanceId,
|
|
17863
17876
|
cx: gx,
|
|
17864
17877
|
cy: gy,
|
|
17865
|
-
width:
|
|
17866
|
-
height:
|
|
17878
|
+
width: C3.GATE_W,
|
|
17879
|
+
height: C3.GATE_H
|
|
17867
17880
|
};
|
|
17868
17881
|
if ((n.gate.kind === "inhibit" || n.gate.kind === "pand") && (n.gate.condition || n.gate.order)) {
|
|
17869
17882
|
const condEv = n.gate.condition ? byId.get(n.gate.condition) : void 0;
|
|
17870
17883
|
const text2 = n.gate.order ? n.gate.order.join(" \u227A ") : condEv?.label ?? n.gate.condition ?? "";
|
|
17871
17884
|
glay.cond = {
|
|
17872
|
-
x: gx +
|
|
17885
|
+
x: gx + C3.GATE_W / 2 + C3.COND_GAP + C3.COND_W / 2,
|
|
17873
17886
|
y: gy,
|
|
17874
|
-
w:
|
|
17875
|
-
h:
|
|
17887
|
+
w: C3.COND_W,
|
|
17888
|
+
h: C3.COND_H,
|
|
17876
17889
|
text: text2
|
|
17877
17890
|
};
|
|
17878
17891
|
}
|
|
17879
17892
|
gates.push(glay);
|
|
17880
|
-
const gateBaseY = gy +
|
|
17893
|
+
const gateBaseY = gy + C3.GATE_H / 2;
|
|
17881
17894
|
for (const c of n.children) {
|
|
17882
17895
|
c.topY = rowY(c.depth);
|
|
17883
17896
|
const childTop = topAnchorY(c);
|
|
@@ -17895,7 +17908,7 @@ function layoutFaultTree(ast) {
|
|
|
17895
17908
|
const cutSetBoxes = [];
|
|
17896
17909
|
let boxIndex = 0;
|
|
17897
17910
|
const visualBounds = (e) => {
|
|
17898
|
-
const cy = e.topY +
|
|
17911
|
+
const cy = e.topY + C3.EVENT_H / 2;
|
|
17899
17912
|
const hw = e.width / 2;
|
|
17900
17913
|
const hh = halfH(e.role);
|
|
17901
17914
|
return { minX: e.cx - hw, maxX: e.cx + hw, minY: cy - hh, maxY: cy + hh };
|
|
@@ -17909,7 +17922,7 @@ function layoutFaultTree(ast) {
|
|
|
17909
17922
|
maxX2 = Math.max(maxX2, b.maxX);
|
|
17910
17923
|
maxY2 = Math.max(maxY2, b.maxY);
|
|
17911
17924
|
}
|
|
17912
|
-
const pad =
|
|
17925
|
+
const pad = C3.CUTSET_PAD + idx % 3 * C3.CUTSET_OFFSET_STEP;
|
|
17913
17926
|
return {
|
|
17914
17927
|
cutSet: cs,
|
|
17915
17928
|
index: idx,
|
|
@@ -17940,7 +17953,7 @@ function layoutFaultTree(ast) {
|
|
|
17940
17953
|
ownerInstanceId: inst.instanceId,
|
|
17941
17954
|
name: tr.name,
|
|
17942
17955
|
x: inst.cx,
|
|
17943
|
-
y: inst.topY +
|
|
17956
|
+
y: inst.topY + C3.EVENT_H + C3.GATE_GAP
|
|
17944
17957
|
});
|
|
17945
17958
|
}
|
|
17946
17959
|
let maxX = 0, maxY = 0;
|
|
@@ -17954,7 +17967,7 @@ function layoutFaultTree(ast) {
|
|
|
17954
17967
|
if (e.role === "basic" || e.role === "undeveloped" || e.role === "house") {
|
|
17955
17968
|
const hasLabel = !!e.event.label && e.event.label !== e.event.id;
|
|
17956
17969
|
const hasProb = ast.analysis.probability && e.event.prob !== void 0;
|
|
17957
|
-
if (hasLabel || hasProb) bump(b.maxX, b.maxY + (hasLabel && hasProb ?
|
|
17970
|
+
if (hasLabel || hasProb) bump(b.maxX, b.maxY + (hasLabel && hasProb ? C3.CAP_GAP + C3.CAP_LINE_H + 8 : C3.CAP_GAP + 6));
|
|
17958
17971
|
}
|
|
17959
17972
|
}
|
|
17960
17973
|
for (const g of gates) {
|
|
@@ -17963,7 +17976,7 @@ function layoutFaultTree(ast) {
|
|
|
17963
17976
|
}
|
|
17964
17977
|
for (const box2 of cutSetBoxes) bump(box2.x + box2.width, box2.y + box2.height);
|
|
17965
17978
|
for (const t of transfers) bump(t.x + 22, t.y + 30);
|
|
17966
|
-
if (ast.title) bump(
|
|
17979
|
+
if (ast.title) bump(C3.CANVAS_PAD + ast.title.length * 8.5, 0);
|
|
17967
17980
|
if (ast.analysis.probability) {
|
|
17968
17981
|
const top = events.find((e) => e.role === "top");
|
|
17969
17982
|
if (top) bump(top.cx + 95, 0);
|
|
@@ -17976,8 +17989,8 @@ function layoutFaultTree(ast) {
|
|
|
17976
17989
|
edges,
|
|
17977
17990
|
cutSetBoxes,
|
|
17978
17991
|
transfers,
|
|
17979
|
-
width: Math.ceil(maxX +
|
|
17980
|
-
height: Math.ceil(maxY +
|
|
17992
|
+
width: Math.ceil(maxX + C3.CANVAS_PAD),
|
|
17993
|
+
height: Math.ceil(maxY + C3.CANVAS_PAD)
|
|
17981
17994
|
};
|
|
17982
17995
|
}
|
|
17983
17996
|
function r(n) {
|
|
@@ -18217,9 +18230,7 @@ function summarise2(layout) {
|
|
|
18217
18230
|
return parts.join(" ");
|
|
18218
18231
|
}
|
|
18219
18232
|
function fmtProb(n) {
|
|
18220
|
-
|
|
18221
|
-
if (n >= 1e-3) return String(parseFloat(n.toPrecision(3)));
|
|
18222
|
-
return n.toExponential(2);
|
|
18233
|
+
return formatProbability(n);
|
|
18223
18234
|
}
|
|
18224
18235
|
function clip2(s, n) {
|
|
18225
18236
|
return s.length <= n ? s : s.slice(0, n - 1) + "\u2026";
|
|
@@ -18505,40 +18516,40 @@ var BOWTIE_CONST = {
|
|
|
18505
18516
|
LEGEND_H: 30
|
|
18506
18517
|
};
|
|
18507
18518
|
function dropBottom(barrier) {
|
|
18508
|
-
const
|
|
18509
|
-
if (barrier.escalations.length === 0) return
|
|
18510
|
-
let cursor =
|
|
18511
|
-
let lastBottom =
|
|
18519
|
+
const C3 = BOWTIE_CONST;
|
|
18520
|
+
if (barrier.escalations.length === 0) return C3.NODE_H / 2;
|
|
18521
|
+
let cursor = C3.EF_DROP;
|
|
18522
|
+
let lastBottom = C3.NODE_H / 2;
|
|
18512
18523
|
for (const esc of barrier.escalations) {
|
|
18513
|
-
lastBottom = cursor +
|
|
18514
|
-
cursor +=
|
|
18524
|
+
lastBottom = cursor + C3.NODE_H / 2;
|
|
18525
|
+
cursor += C3.NODE_H + C3.EF_GAP;
|
|
18515
18526
|
for (const _ef of esc.barriers) {
|
|
18516
|
-
lastBottom = cursor +
|
|
18517
|
-
cursor +=
|
|
18527
|
+
lastBottom = cursor + C3.NODE_H / 2;
|
|
18528
|
+
cursor += C3.NODE_H + C3.EF_GAP;
|
|
18518
18529
|
}
|
|
18519
18530
|
}
|
|
18520
18531
|
return lastBottom;
|
|
18521
18532
|
}
|
|
18522
18533
|
function bandLayout(lines) {
|
|
18523
|
-
const
|
|
18524
|
-
const below = lines.map((l) => Math.max(...l.barriers.map(dropBottom),
|
|
18534
|
+
const C3 = BOWTIE_CONST;
|
|
18535
|
+
const below = lines.map((l) => Math.max(...l.barriers.map(dropBottom), C3.NODE_H / 2));
|
|
18525
18536
|
const rel = [];
|
|
18526
18537
|
for (let k = 0; k < lines.length; k++) {
|
|
18527
18538
|
if (k === 0) {
|
|
18528
18539
|
rel.push(0);
|
|
18529
18540
|
continue;
|
|
18530
18541
|
}
|
|
18531
|
-
const pitch = Math.max(
|
|
18542
|
+
const pitch = Math.max(C3.ROW_BAND_H, below[k - 1] + C3.ROW_GAP + C3.NODE_H / 2);
|
|
18532
18543
|
rel.push(rel[k - 1] + pitch);
|
|
18533
18544
|
}
|
|
18534
18545
|
const last = lines.length - 1;
|
|
18535
18546
|
const blockMid = lines.length ? rel[last] / 2 : 0;
|
|
18536
|
-
const aboveExtent = lines.length ? blockMid +
|
|
18547
|
+
const aboveExtent = lines.length ? blockMid + C3.NODE_H / 2 : 0;
|
|
18537
18548
|
const belowExtent = lines.length ? rel[last] - blockMid + below[last] : 0;
|
|
18538
18549
|
return { rel, below, blockMid, aboveExtent, belowExtent };
|
|
18539
18550
|
}
|
|
18540
18551
|
function layoutBowtie(ast) {
|
|
18541
|
-
const
|
|
18552
|
+
const C3 = BOWTIE_CONST;
|
|
18542
18553
|
const boxes = [];
|
|
18543
18554
|
const lines = [];
|
|
18544
18555
|
const escalationLines = [];
|
|
@@ -18546,42 +18557,42 @@ function layoutBowtie(ast) {
|
|
|
18546
18557
|
const conseqLines = ast.consequences.map((c) => ({ id: c.id, label: c.label, barriers: c.barriers }));
|
|
18547
18558
|
const left = bandLayout(threatLines);
|
|
18548
18559
|
const right = bandLayout(conseqLines);
|
|
18549
|
-
const aboveCy = Math.max(left.aboveExtent, right.aboveExtent,
|
|
18560
|
+
const aboveCy = Math.max(left.aboveExtent, right.aboveExtent, C3.TOPEVENT_R);
|
|
18550
18561
|
const maxLeftChain = Math.max(0, ...threatLines.map((l) => l.barriers.length));
|
|
18551
|
-
const innerOffset =
|
|
18552
|
-
const cx =
|
|
18553
|
-
const titleZone = ast.title ?
|
|
18554
|
-
const hazardReserve = ast.hazard ?
|
|
18555
|
-
const cy =
|
|
18556
|
-
const topEvent = { cx, cy, r:
|
|
18562
|
+
const innerOffset = C3.TOPEVENT_R + C3.CENTER_GUTTER + C3.BARRIER_W / 2;
|
|
18563
|
+
const cx = C3.PAGE_PAD + C3.NODE_W / 2 + maxLeftChain * C3.WING_X_STEP + innerOffset;
|
|
18564
|
+
const titleZone = ast.title ? C3.TITLE_H : 0;
|
|
18565
|
+
const hazardReserve = ast.hazard ? C3.NODE_H + C3.HAZARD_GAP : 0;
|
|
18566
|
+
const cy = C3.PAGE_PAD + titleZone + hazardReserve + aboveCy;
|
|
18567
|
+
const topEvent = { cx, cy, r: C3.TOPEVENT_R, label: ast.topEvent };
|
|
18557
18568
|
let hazardTie;
|
|
18558
18569
|
if (ast.hazard) {
|
|
18559
|
-
const hcy =
|
|
18560
|
-
boxes.push({ id: "hazard", role: "hazard", label: ast.hazard, cx, cy: hcy, width:
|
|
18561
|
-
hazardTie = { x: cx, y1: hcy +
|
|
18570
|
+
const hcy = C3.PAGE_PAD + titleZone + C3.NODE_H / 2;
|
|
18571
|
+
boxes.push({ id: "hazard", role: "hazard", label: ast.hazard, cx, cy: hcy, width: C3.HAZARD_W, height: C3.NODE_H });
|
|
18572
|
+
hazardTie = { x: cx, y1: hcy + C3.NODE_H / 2, y2: cy - C3.TOPEVENT_R };
|
|
18562
18573
|
}
|
|
18563
18574
|
const emitWing = (wing, band, side) => {
|
|
18564
|
-
const innerX = side === "prevent" ? cx -
|
|
18575
|
+
const innerX = side === "prevent" ? cx - C3.TOPEVENT_R - C3.CENTER_GUTTER - C3.BARRIER_W / 2 : cx + C3.TOPEVENT_R + C3.CENTER_GUTTER + C3.BARRIER_W / 2;
|
|
18565
18576
|
wing.forEach((line2, k) => {
|
|
18566
18577
|
const by = cy + (band.rel[k] - band.blockMid);
|
|
18567
18578
|
const n = line2.barriers.length;
|
|
18568
18579
|
const barrierX = line2.barriers.map((_b, j) => {
|
|
18569
18580
|
if (side === "prevent") {
|
|
18570
18581
|
const stepsFromInner = n - 1 - j;
|
|
18571
|
-
return innerX - stepsFromInner *
|
|
18582
|
+
return innerX - stepsFromInner * C3.WING_X_STEP;
|
|
18572
18583
|
}
|
|
18573
|
-
return innerX + j *
|
|
18584
|
+
return innerX + j * C3.WING_X_STEP;
|
|
18574
18585
|
});
|
|
18575
18586
|
const outerBarrierX = side === "prevent" ? Math.min(...barrierX) : Math.max(...barrierX);
|
|
18576
|
-
const headX = side === "prevent" ? outerBarrierX -
|
|
18587
|
+
const headX = side === "prevent" ? outerBarrierX - C3.WING_X_STEP : outerBarrierX + C3.WING_X_STEP;
|
|
18577
18588
|
boxes.push({
|
|
18578
18589
|
id: line2.id,
|
|
18579
18590
|
role: side === "prevent" ? "threat" : "consequence",
|
|
18580
18591
|
label: line2.label,
|
|
18581
18592
|
cx: headX,
|
|
18582
18593
|
cy: by,
|
|
18583
|
-
width:
|
|
18584
|
-
height:
|
|
18594
|
+
width: C3.NODE_W,
|
|
18595
|
+
height: C3.NODE_H
|
|
18585
18596
|
});
|
|
18586
18597
|
line2.barriers.forEach((b, j) => {
|
|
18587
18598
|
const bx = barrierX[j];
|
|
@@ -18591,71 +18602,71 @@ function layoutBowtie(ast) {
|
|
|
18591
18602
|
label: b.label,
|
|
18592
18603
|
cx: bx,
|
|
18593
18604
|
cy: by,
|
|
18594
|
-
width:
|
|
18595
|
-
height:
|
|
18605
|
+
width: C3.BARRIER_W,
|
|
18606
|
+
height: C3.NODE_H,
|
|
18596
18607
|
side,
|
|
18597
18608
|
lineId: line2.id,
|
|
18598
18609
|
order: j
|
|
18599
18610
|
});
|
|
18600
18611
|
if (b.escalations.length) {
|
|
18601
|
-
let cursor =
|
|
18602
|
-
let connectFromY = by +
|
|
18612
|
+
let cursor = C3.EF_DROP;
|
|
18613
|
+
let connectFromY = by + C3.NODE_H / 2;
|
|
18603
18614
|
for (const esc of b.escalations) {
|
|
18604
18615
|
const escCy = by + cursor;
|
|
18605
|
-
escalationLines.push({ x: bx, y1: connectFromY, y2: escCy -
|
|
18616
|
+
escalationLines.push({ x: bx, y1: connectFromY, y2: escCy - C3.NODE_H / 2 });
|
|
18606
18617
|
boxes.push({
|
|
18607
18618
|
id: esc.id,
|
|
18608
18619
|
role: "escalation",
|
|
18609
18620
|
label: esc.label,
|
|
18610
18621
|
cx: bx,
|
|
18611
18622
|
cy: escCy,
|
|
18612
|
-
width:
|
|
18613
|
-
height:
|
|
18623
|
+
width: C3.NODE_W,
|
|
18624
|
+
height: C3.NODE_H,
|
|
18614
18625
|
lineId: line2.id,
|
|
18615
18626
|
barrierId: b.id
|
|
18616
18627
|
});
|
|
18617
|
-
connectFromY = escCy +
|
|
18618
|
-
cursor +=
|
|
18628
|
+
connectFromY = escCy + C3.NODE_H / 2;
|
|
18629
|
+
cursor += C3.NODE_H + C3.EF_GAP;
|
|
18619
18630
|
for (const ef of esc.barriers) {
|
|
18620
18631
|
const efCy = by + cursor;
|
|
18621
|
-
escalationLines.push({ x: bx, y1: connectFromY, y2: efCy -
|
|
18632
|
+
escalationLines.push({ x: bx, y1: connectFromY, y2: efCy - C3.NODE_H / 2 });
|
|
18622
18633
|
boxes.push({
|
|
18623
18634
|
id: ef.id,
|
|
18624
18635
|
role: "ef-barrier",
|
|
18625
18636
|
label: ef.label,
|
|
18626
18637
|
cx: bx,
|
|
18627
18638
|
cy: efCy,
|
|
18628
|
-
width:
|
|
18629
|
-
height:
|
|
18639
|
+
width: C3.BARRIER_W,
|
|
18640
|
+
height: C3.NODE_H,
|
|
18630
18641
|
lineId: line2.id,
|
|
18631
18642
|
escalationId: esc.id
|
|
18632
18643
|
});
|
|
18633
|
-
connectFromY = efCy +
|
|
18634
|
-
cursor +=
|
|
18644
|
+
connectFromY = efCy + C3.NODE_H / 2;
|
|
18645
|
+
cursor += C3.NODE_H + C3.EF_GAP;
|
|
18635
18646
|
}
|
|
18636
18647
|
}
|
|
18637
18648
|
}
|
|
18638
18649
|
});
|
|
18639
18650
|
const dy = by - cy;
|
|
18640
|
-
const clampedDy = Math.max(-48, Math.min(
|
|
18641
|
-
const knotDx = Math.sqrt(Math.max(0,
|
|
18651
|
+
const clampedDy = Math.max(-48, Math.min(C3.TOPEVENT_R - 4, dy));
|
|
18652
|
+
const knotDx = Math.sqrt(Math.max(0, C3.TOPEVENT_R * C3.TOPEVENT_R - clampedDy * clampedDy));
|
|
18642
18653
|
const pts = [];
|
|
18643
18654
|
if (side === "prevent") {
|
|
18644
|
-
pts.push([headX +
|
|
18655
|
+
pts.push([headX + C3.NODE_W / 2, by]);
|
|
18645
18656
|
const ordered = [...line2.barriers].map((_b, j) => barrierX[j]).sort((a, b) => a - b);
|
|
18646
18657
|
for (const bx of ordered) {
|
|
18647
|
-
pts.push([bx -
|
|
18648
|
-
pts.push([bx +
|
|
18658
|
+
pts.push([bx - C3.BARRIER_W / 2, by]);
|
|
18659
|
+
pts.push([bx + C3.BARRIER_W / 2, by]);
|
|
18649
18660
|
}
|
|
18650
18661
|
pts.push([cx - knotDx, cy + clampedDy]);
|
|
18651
18662
|
} else {
|
|
18652
18663
|
pts.push([cx + knotDx, cy + clampedDy]);
|
|
18653
18664
|
const ordered = [...line2.barriers].map((_b, j) => barrierX[j]).sort((a, b) => a - b);
|
|
18654
18665
|
for (const bx of ordered) {
|
|
18655
|
-
pts.push([bx -
|
|
18656
|
-
pts.push([bx +
|
|
18666
|
+
pts.push([bx - C3.BARRIER_W / 2, by]);
|
|
18667
|
+
pts.push([bx + C3.BARRIER_W / 2, by]);
|
|
18657
18668
|
}
|
|
18658
|
-
pts.push([headX -
|
|
18669
|
+
pts.push([headX - C3.NODE_W / 2, by]);
|
|
18659
18670
|
}
|
|
18660
18671
|
const path2 = pts.map((p, idx) => `${idx === 0 ? "M" : "L"} ${r3(p[0])} ${r3(p[1])}`).join(" ");
|
|
18661
18672
|
const ax = side === "prevent" ? cx - knotDx : cx + knotDx;
|
|
@@ -18670,9 +18681,9 @@ function layoutBowtie(ast) {
|
|
|
18670
18681
|
maxY = Math.max(maxY, y);
|
|
18671
18682
|
};
|
|
18672
18683
|
for (const b of boxes) bump(b.cx + b.width / 2, b.cy + b.height / 2);
|
|
18673
|
-
bump(cx +
|
|
18674
|
-
if (ast.title) bump(
|
|
18675
|
-
const legendBand = ast.legend === "off" ? 0 :
|
|
18684
|
+
bump(cx + C3.TOPEVENT_R, cy + C3.TOPEVENT_R);
|
|
18685
|
+
if (ast.title) bump(C3.PAGE_PAD + ast.title.length * 9, 0);
|
|
18686
|
+
const legendBand = ast.legend === "off" ? 0 : C3.LEGEND_H;
|
|
18676
18687
|
return {
|
|
18677
18688
|
ast,
|
|
18678
18689
|
topEvent,
|
|
@@ -18680,8 +18691,8 @@ function layoutBowtie(ast) {
|
|
|
18680
18691
|
lines,
|
|
18681
18692
|
escalationLines,
|
|
18682
18693
|
...hazardTie ? { hazardTie } : {},
|
|
18683
|
-
width: Math.ceil(maxX +
|
|
18684
|
-
height: Math.ceil(maxY +
|
|
18694
|
+
width: Math.ceil(maxX + C3.PAGE_PAD),
|
|
18695
|
+
height: Math.ceil(maxY + C3.PAGE_PAD + legendBand)
|
|
18685
18696
|
};
|
|
18686
18697
|
}
|
|
18687
18698
|
function r3(n) {
|
|
@@ -19172,7 +19183,7 @@ var EVENTTREE_CONST = {
|
|
|
19172
19183
|
LEAF_LINE_H: 14
|
|
19173
19184
|
};
|
|
19174
19185
|
function layoutEventTree(ast) {
|
|
19175
|
-
const
|
|
19186
|
+
const C3 = EVENTTREE_CONST;
|
|
19176
19187
|
const analysis = analyseEventTree(ast);
|
|
19177
19188
|
const seqs = analysis.sequences;
|
|
19178
19189
|
const root = { children: [], y: 0, rowLo: 0, rowHi: 0 };
|
|
@@ -19204,15 +19215,15 @@ function layoutEventTree(ast) {
|
|
|
19204
19215
|
};
|
|
19205
19216
|
assignRows(root);
|
|
19206
19217
|
const rowCount = Math.max(nextRow, 1);
|
|
19207
|
-
const titleH = ast.title ?
|
|
19208
|
-
const headerY =
|
|
19209
|
-
const bodyTopY =
|
|
19210
|
-
const rowY = (row) => bodyTopY +
|
|
19211
|
-
const ieX2 =
|
|
19212
|
-
const gridX = (col) => ieX2 + (col + 1) *
|
|
19218
|
+
const titleH = ast.title ? C3.TITLE_H : 0;
|
|
19219
|
+
const headerY = C3.CANVAS_PAD + titleH + C3.HEADER_H * 0.6;
|
|
19220
|
+
const bodyTopY = C3.CANVAS_PAD + titleH + C3.HEADER_H;
|
|
19221
|
+
const rowY = (row) => bodyTopY + C3.ROW_H / 2 + row * C3.ROW_H;
|
|
19222
|
+
const ieX2 = C3.IE_LEFT + C3.IE_STUB;
|
|
19223
|
+
const gridX = (col) => ieX2 + (col + 1) * C3.COL_W;
|
|
19213
19224
|
const nFns = ast.functions.length;
|
|
19214
19225
|
const lastGridX = nFns > 0 ? gridX(nFns - 1) : ieX2;
|
|
19215
|
-
const outcomeX = lastGridX +
|
|
19226
|
+
const outcomeX = lastGridX + C3.OUTCOME_GAP;
|
|
19216
19227
|
const assignY = (n) => {
|
|
19217
19228
|
for (const c of n.children) assignY(c);
|
|
19218
19229
|
n.y = (rowY(n.rowLo) + rowY(n.rowHi)) / 2;
|
|
@@ -19235,7 +19246,7 @@ function layoutEventTree(ast) {
|
|
|
19235
19246
|
path: path2,
|
|
19236
19247
|
// Label sits above the horizontal run leading into this node.
|
|
19237
19248
|
labelX: (riserX + parentX) / 2,
|
|
19238
|
-
labelY: c.y +
|
|
19249
|
+
labelY: c.y + C3.FORK_LABEL_DY
|
|
19239
19250
|
});
|
|
19240
19251
|
walk(c, x, c.y);
|
|
19241
19252
|
}
|
|
@@ -19269,7 +19280,7 @@ function layoutEventTree(ast) {
|
|
|
19269
19280
|
headers.push({
|
|
19270
19281
|
kind: "initiating",
|
|
19271
19282
|
label: "Initiating Event",
|
|
19272
|
-
cx:
|
|
19283
|
+
cx: C3.IE_LEFT + C3.IE_STUB / 2
|
|
19273
19284
|
});
|
|
19274
19285
|
ast.functions.forEach((fn, col) => {
|
|
19275
19286
|
headers.push({
|
|
@@ -19279,16 +19290,16 @@ function layoutEventTree(ast) {
|
|
|
19279
19290
|
gridX: gridX(col)
|
|
19280
19291
|
});
|
|
19281
19292
|
});
|
|
19282
|
-
headers.push({ kind: "outcome", label: "Outcome", cx: outcomeX +
|
|
19283
|
-
headers.push({ kind: "frequency", label: "Frequency", cx: outcomeX +
|
|
19284
|
-
const gridBottom = rowY(rowCount - 1) +
|
|
19293
|
+
headers.push({ kind: "outcome", label: "Outcome", cx: outcomeX + C3.OUTCOME_W * 0.32 });
|
|
19294
|
+
headers.push({ kind: "frequency", label: "Frequency", cx: outcomeX + C3.OUTCOME_W * 0.82 });
|
|
19295
|
+
const gridBottom = rowY(rowCount - 1) + C3.ROW_H / 2;
|
|
19285
19296
|
const gridLines = ast.functions.map((_, col) => ({
|
|
19286
19297
|
x: gridX(col),
|
|
19287
19298
|
y1: bodyTopY,
|
|
19288
19299
|
y2: gridBottom
|
|
19289
19300
|
}));
|
|
19290
|
-
const width = outcomeX +
|
|
19291
|
-
const height = gridBottom +
|
|
19301
|
+
const width = outcomeX + C3.OUTCOME_W + C3.CANVAS_PAD;
|
|
19302
|
+
const height = gridBottom + C3.CANVAS_PAD;
|
|
19292
19303
|
return {
|
|
19293
19304
|
ast,
|
|
19294
19305
|
analysis,
|
|
@@ -19296,10 +19307,10 @@ function layoutEventTree(ast) {
|
|
|
19296
19307
|
forks,
|
|
19297
19308
|
leaves,
|
|
19298
19309
|
initiating: {
|
|
19299
|
-
x1:
|
|
19310
|
+
x1: C3.IE_LEFT,
|
|
19300
19311
|
x2: ieX2,
|
|
19301
19312
|
y: root.y,
|
|
19302
|
-
labelX:
|
|
19313
|
+
labelX: C3.IE_LEFT,
|
|
19303
19314
|
labelY: root.y - 10,
|
|
19304
19315
|
freqY: root.y + 16
|
|
19305
19316
|
},
|
|
@@ -20050,7 +20061,7 @@ var FMEA_CONST = {
|
|
|
20050
20061
|
AP_COL_W: 46
|
|
20051
20062
|
};
|
|
20052
20063
|
function buildColumnSpecs(hasActions, rank) {
|
|
20053
|
-
const
|
|
20064
|
+
const C3 = FMEA_CONST;
|
|
20054
20065
|
const specs = [
|
|
20055
20066
|
{ key: "no", label: "#", width: 28, align: "middle", numeric: true, field: (r7) => String(r7.index) },
|
|
20056
20067
|
{
|
|
@@ -20071,9 +20082,9 @@ function buildColumnSpecs(hasActions, rank) {
|
|
|
20071
20082
|
numeric: false,
|
|
20072
20083
|
field: (r7) => r7.effects.length > 1 ? r7.effects.join("; ") : r7.effect
|
|
20073
20084
|
},
|
|
20074
|
-
{ key: "sev", label: "S", width:
|
|
20085
|
+
{ key: "sev", label: "S", width: C3.NUM_COL_W, align: "middle", band: "before", numeric: true, field: (r7) => String(r7.sev) },
|
|
20075
20086
|
{ key: "cause", label: "Cause(s)", width: 120, align: "start", numeric: false, field: (r7) => r7.cause },
|
|
20076
|
-
{ key: "occ", label: "O", width:
|
|
20087
|
+
{ key: "occ", label: "O", width: C3.NUM_COL_W, align: "middle", band: "before", numeric: true, field: (r7) => String(r7.occ) },
|
|
20077
20088
|
{
|
|
20078
20089
|
key: "controls",
|
|
20079
20090
|
label: "Current Controls",
|
|
@@ -20082,9 +20093,9 @@ function buildColumnSpecs(hasActions, rank) {
|
|
|
20082
20093
|
numeric: false,
|
|
20083
20094
|
field: (r7) => controlsText(r7)
|
|
20084
20095
|
},
|
|
20085
|
-
{ key: "det", label: "D", width:
|
|
20086
|
-
{ key: "rpn", label: "RPN", width:
|
|
20087
|
-
{ key: "ap", label: "AP", width:
|
|
20096
|
+
{ key: "det", label: "D", width: C3.NUM_COL_W, align: "middle", band: "before", numeric: true, field: (r7) => String(r7.det) },
|
|
20097
|
+
{ key: "rpn", label: "RPN", width: C3.RPN_COL_W, align: "middle", band: "before", numeric: true, field: (r7) => String(r7.rpn) },
|
|
20098
|
+
{ key: "ap", label: "AP", width: C3.AP_COL_W, align: "middle", band: "before", numeric: true, field: (r7) => r7.ap }
|
|
20088
20099
|
];
|
|
20089
20100
|
if (hasActions) {
|
|
20090
20101
|
specs.push(
|
|
@@ -20100,7 +20111,7 @@ function buildColumnSpecs(hasActions, rank) {
|
|
|
20100
20111
|
{
|
|
20101
20112
|
key: "rsev",
|
|
20102
20113
|
label: "S",
|
|
20103
|
-
width:
|
|
20114
|
+
width: C3.NUM_COL_W,
|
|
20104
20115
|
align: "middle",
|
|
20105
20116
|
band: "after",
|
|
20106
20117
|
numeric: true,
|
|
@@ -20110,7 +20121,7 @@ function buildColumnSpecs(hasActions, rank) {
|
|
|
20110
20121
|
{
|
|
20111
20122
|
key: "rocc",
|
|
20112
20123
|
label: "O",
|
|
20113
|
-
width:
|
|
20124
|
+
width: C3.NUM_COL_W,
|
|
20114
20125
|
align: "middle",
|
|
20115
20126
|
band: "after",
|
|
20116
20127
|
numeric: true,
|
|
@@ -20120,7 +20131,7 @@ function buildColumnSpecs(hasActions, rank) {
|
|
|
20120
20131
|
{
|
|
20121
20132
|
key: "rdet",
|
|
20122
20133
|
label: "D",
|
|
20123
|
-
width:
|
|
20134
|
+
width: C3.NUM_COL_W,
|
|
20124
20135
|
align: "middle",
|
|
20125
20136
|
band: "after",
|
|
20126
20137
|
numeric: true,
|
|
@@ -20130,7 +20141,7 @@ function buildColumnSpecs(hasActions, rank) {
|
|
|
20130
20141
|
{
|
|
20131
20142
|
key: "rrpn",
|
|
20132
20143
|
label: "RPN",
|
|
20133
|
-
width:
|
|
20144
|
+
width: C3.RPN_COL_W,
|
|
20134
20145
|
align: "middle",
|
|
20135
20146
|
band: "after",
|
|
20136
20147
|
numeric: true,
|
|
@@ -20140,7 +20151,7 @@ function buildColumnSpecs(hasActions, rank) {
|
|
|
20140
20151
|
{
|
|
20141
20152
|
key: "rap",
|
|
20142
20153
|
label: "AP",
|
|
20143
|
-
width:
|
|
20154
|
+
width: C3.AP_COL_W,
|
|
20144
20155
|
align: "middle",
|
|
20145
20156
|
band: "after",
|
|
20146
20157
|
numeric: true,
|
|
@@ -20212,15 +20223,15 @@ function apRiskClass(ap) {
|
|
|
20212
20223
|
return "ap-low";
|
|
20213
20224
|
}
|
|
20214
20225
|
function layoutFmea(ast, analysisIn) {
|
|
20215
|
-
const
|
|
20226
|
+
const C3 = FMEA_CONST;
|
|
20216
20227
|
const analysis = analysisIn ?? analyseFmea(ast);
|
|
20217
20228
|
const specs = buildColumnSpecs(analysis.hasActions, ast.rank);
|
|
20218
20229
|
const metaKeys = Object.keys(ast.metadata);
|
|
20219
20230
|
const legendLines = (ast.target !== void 0 || ast.acceptable !== void 0 ? 1 : 0) + (ast.flag ? 1 : 0);
|
|
20220
20231
|
const metaRows = Math.ceil(metaKeys.length / 2) + legendLines;
|
|
20221
|
-
const titleH = ast.title ?
|
|
20222
|
-
const metaH = metaRows > 0 ? metaRows *
|
|
20223
|
-
const startX =
|
|
20232
|
+
const titleH = ast.title ? C3.TITLE_H : 0;
|
|
20233
|
+
const metaH = metaRows > 0 ? metaRows * C3.META_LINE_H + 6 : 0;
|
|
20234
|
+
const startX = C3.CANVAS_PAD;
|
|
20224
20235
|
let x = startX;
|
|
20225
20236
|
const columns = [];
|
|
20226
20237
|
const colX = {};
|
|
@@ -20239,15 +20250,15 @@ function layoutFmea(ast, analysisIn) {
|
|
|
20239
20250
|
}
|
|
20240
20251
|
const tableW = x - startX;
|
|
20241
20252
|
const hasBands = analysis.hasActions;
|
|
20242
|
-
const bandH = hasBands ?
|
|
20243
|
-
const topY =
|
|
20253
|
+
const bandH = hasBands ? C3.BAND_H : 0;
|
|
20254
|
+
const topY = C3.CANVAS_PAD + titleH + metaH;
|
|
20244
20255
|
const bandY = topY;
|
|
20245
20256
|
const headerY = topY + bandH;
|
|
20246
|
-
const bodyY = headerY +
|
|
20257
|
+
const bodyY = headerY + C3.HEADER_H;
|
|
20247
20258
|
const cells = [];
|
|
20248
20259
|
const rowHeights = [];
|
|
20249
20260
|
const rowY = [];
|
|
20250
|
-
const innerW = (s) => s.width -
|
|
20261
|
+
const innerW = (s) => s.width - C3.CELL_PAD_X * 2;
|
|
20251
20262
|
const wrapped = analysis.rows.map(
|
|
20252
20263
|
(row) => specs.map((s) => ({ spec: s, row, lines: wrapText3(s.field(row), innerW(s)) }))
|
|
20253
20264
|
);
|
|
@@ -20263,7 +20274,7 @@ function layoutFmea(ast, analysisIn) {
|
|
|
20263
20274
|
return w.lines.length;
|
|
20264
20275
|
});
|
|
20265
20276
|
const maxLines = Math.max(1, ...lineCounts);
|
|
20266
|
-
const h = Math.max(
|
|
20277
|
+
const h = Math.max(C3.ROW_MIN_H, maxLines * C3.LINE_H + C3.CELL_PAD_Y * 2);
|
|
20267
20278
|
rowHeights.push(h);
|
|
20268
20279
|
});
|
|
20269
20280
|
let yCursor = bodyY;
|
|
@@ -20313,14 +20324,14 @@ function layoutFmea(ast, analysisIn) {
|
|
|
20313
20324
|
if (before) bands.push({ label: "BEFORE ACTION", x: before.x, width: before.w, y: bandY, height: bandH });
|
|
20314
20325
|
if (after) bands.push({ label: "AFTER ACTION", x: after.x, width: after.w, y: bandY, height: bandH });
|
|
20315
20326
|
}
|
|
20316
|
-
const totalH = (rowY.length ? rowY[rowY.length - 1] + rowHeights[rowHeights.length - 1] : bodyY) +
|
|
20317
|
-
const width = tableW +
|
|
20327
|
+
const totalH = (rowY.length ? rowY[rowY.length - 1] + rowHeights[rowHeights.length - 1] : bodyY) + C3.CANVAS_PAD;
|
|
20328
|
+
const width = tableW + C3.CANVAS_PAD * 2;
|
|
20318
20329
|
return {
|
|
20319
20330
|
ast,
|
|
20320
20331
|
analysis,
|
|
20321
20332
|
columns,
|
|
20322
20333
|
headerY,
|
|
20323
|
-
headerH:
|
|
20334
|
+
headerH: C3.HEADER_H,
|
|
20324
20335
|
bodyY,
|
|
20325
20336
|
rowHeights,
|
|
20326
20337
|
rowY,
|
|
@@ -20682,6 +20693,7 @@ function parseRbd(text2) {
|
|
|
20682
20693
|
seenIds.add(id);
|
|
20683
20694
|
let label;
|
|
20684
20695
|
let R;
|
|
20696
|
+
let dist;
|
|
20685
20697
|
if (peek()?.t === "string") {
|
|
20686
20698
|
label = tokens[pos++].v;
|
|
20687
20699
|
}
|
|
@@ -20690,10 +20702,16 @@ function parseRbd(text2) {
|
|
|
20690
20702
|
const attr = parseAttr(w);
|
|
20691
20703
|
if (!attr) break;
|
|
20692
20704
|
pos++;
|
|
20693
|
-
if (attr.
|
|
20694
|
-
else R = clamp01(attr.value, w, warnings);
|
|
20705
|
+
if (attr.kind === "dist") dist = attr.dist;
|
|
20706
|
+
else R = clamp01(attr.failure ? 1 - attr.value : attr.value, w, warnings);
|
|
20695
20707
|
}
|
|
20696
|
-
return {
|
|
20708
|
+
return {
|
|
20709
|
+
kind: "block",
|
|
20710
|
+
id,
|
|
20711
|
+
...label !== void 0 ? { label } : {},
|
|
20712
|
+
...R !== void 0 ? { R } : {},
|
|
20713
|
+
...dist !== void 0 ? { dist } : {}
|
|
20714
|
+
};
|
|
20697
20715
|
};
|
|
20698
20716
|
const parseGroup = (kwRaw) => {
|
|
20699
20717
|
const kw = kwRaw.toLowerCase();
|
|
@@ -20767,10 +20785,19 @@ function parseRbd(text2) {
|
|
|
20767
20785
|
} else {
|
|
20768
20786
|
root = { kind: "series", children: top };
|
|
20769
20787
|
}
|
|
20788
|
+
let mission;
|
|
20789
|
+
if (metadata.mission !== void 0) {
|
|
20790
|
+
const v = parseFloat(metadata.mission);
|
|
20791
|
+
if (!Number.isFinite(v) || v < 0) {
|
|
20792
|
+
throw new RbdParseError(`mission time must be a non-negative number (got '${metadata.mission}')`);
|
|
20793
|
+
}
|
|
20794
|
+
mission = v;
|
|
20795
|
+
}
|
|
20770
20796
|
return {
|
|
20771
20797
|
type: "rbd",
|
|
20772
20798
|
...title2 ? { title: title2 } : {},
|
|
20773
20799
|
root,
|
|
20800
|
+
...mission !== void 0 ? { mission } : {},
|
|
20774
20801
|
warnings,
|
|
20775
20802
|
...Object.keys(metadata).length > 0 ? { metadata } : {}
|
|
20776
20803
|
};
|
|
@@ -20823,11 +20850,10 @@ function tokenize6(src) {
|
|
|
20823
20850
|
}
|
|
20824
20851
|
function stripBodyDirectives(body, metadata) {
|
|
20825
20852
|
return body.split("\n").filter((line2) => {
|
|
20826
|
-
const m = line2.match(/^\s*(title|standard|note)\s*:\s*(.+)$/i);
|
|
20853
|
+
const m = line2.match(/^\s*(title|standard|note|mission)\s*:\s*(.+)$/i);
|
|
20827
20854
|
if (m) {
|
|
20828
20855
|
const key = m[1].toLowerCase();
|
|
20829
|
-
|
|
20830
|
-
else metadata.title = m[2].trim();
|
|
20856
|
+
metadata[key] = m[2].trim();
|
|
20831
20857
|
return false;
|
|
20832
20858
|
}
|
|
20833
20859
|
return true;
|
|
@@ -20839,15 +20865,33 @@ function extractQuoted(s) {
|
|
|
20839
20865
|
return s.length > 0 ? s.trim() : void 0;
|
|
20840
20866
|
}
|
|
20841
20867
|
function parseAttr(w) {
|
|
20868
|
+
const wb = w.match(/^weibull\s*[=:]\s*(.+)$/i);
|
|
20869
|
+
if (wb) {
|
|
20870
|
+
const parts = wb[1].split(",").map((s) => parseFloat(s.trim()));
|
|
20871
|
+
if (parts.length === 2 && parts.every((x) => Number.isFinite(x) && x > 0)) {
|
|
20872
|
+
return { kind: "dist", dist: { kind: "weibull", beta: parts[0], eta: parts[1] } };
|
|
20873
|
+
}
|
|
20874
|
+
return null;
|
|
20875
|
+
}
|
|
20876
|
+
const rt = w.match(/^rate\s*[=:]\s*(.+)$/i);
|
|
20877
|
+
if (rt) {
|
|
20878
|
+
const v = parseFloat(rt[1].trim());
|
|
20879
|
+
return Number.isFinite(v) && v >= 0 ? { kind: "dist", dist: { kind: "exp", rate: v } } : null;
|
|
20880
|
+
}
|
|
20881
|
+
const mt = w.match(/^(mtbf|mttf)\s*[=:]\s*(.+)$/i);
|
|
20882
|
+
if (mt) {
|
|
20883
|
+
const v = parseFloat(mt[2].trim());
|
|
20884
|
+
return Number.isFinite(v) && v > 0 ? { kind: "dist", dist: { kind: "exp", rate: 1 / v } } : null;
|
|
20885
|
+
}
|
|
20842
20886
|
const m = w.match(/^(R|r|p|prob|q)\s*[=:]\s*(.+)$/);
|
|
20843
20887
|
if (m) {
|
|
20844
20888
|
const key = m[1].toLowerCase();
|
|
20845
20889
|
const value = parseNum(m[2]);
|
|
20846
20890
|
if (value === void 0) return null;
|
|
20847
|
-
return {
|
|
20891
|
+
return { kind: "R", value, failure: key === "p" || key === "q" };
|
|
20848
20892
|
}
|
|
20849
20893
|
const bare = parseNum(w);
|
|
20850
|
-
if (bare !== void 0) return {
|
|
20894
|
+
if (bare !== void 0) return { kind: "R", value: bare, failure: false };
|
|
20851
20895
|
return null;
|
|
20852
20896
|
}
|
|
20853
20897
|
function parseNum(s) {
|
|
@@ -20876,8 +20920,11 @@ var KOFN_ENUM_CAP = 18;
|
|
|
20876
20920
|
function analyseRbd(ast) {
|
|
20877
20921
|
const notes = [];
|
|
20878
20922
|
const warnings = [...ast.warnings];
|
|
20923
|
+
if (ast.mission !== void 0) {
|
|
20924
|
+
notes.push(`Mission time t = ${ast.mission}; block reliabilities with a rate/MTBF/Weibull are evaluated as R(t).`);
|
|
20925
|
+
}
|
|
20879
20926
|
const blocks = [];
|
|
20880
|
-
collectBlocks(ast.root, blocks);
|
|
20927
|
+
collectBlocks(ast.root, blocks, ast.mission, warnings);
|
|
20881
20928
|
const missing = blocks.filter((b) => b.R === void 0).map((b) => b.id);
|
|
20882
20929
|
const baseEnv = new Map(blocks.map((b) => [b.id, b.R]));
|
|
20883
20930
|
const systemReliability = evalStructure(ast.root, baseEnv, notes);
|
|
@@ -20893,10 +20940,15 @@ function analyseRbd(ast) {
|
|
|
20893
20940
|
const rDown = evalStructure(ast.root, down, notes);
|
|
20894
20941
|
const importance = rUp !== void 0 && rDown !== void 0 ? rUp - rDown : void 0;
|
|
20895
20942
|
const isSpof = rDown === 0;
|
|
20943
|
+
let criticality;
|
|
20944
|
+
if (importance !== void 0 && b.R !== void 0 && systemReliability < 1) {
|
|
20945
|
+
criticality = importance * (1 - b.R) / (1 - systemReliability);
|
|
20946
|
+
}
|
|
20896
20947
|
return {
|
|
20897
20948
|
id: b.id,
|
|
20898
20949
|
...b.R !== void 0 ? { R: b.R } : {},
|
|
20899
20950
|
...importance !== void 0 ? { importance } : {},
|
|
20951
|
+
...criticality !== void 0 ? { criticality } : {},
|
|
20900
20952
|
isSpof
|
|
20901
20953
|
};
|
|
20902
20954
|
});
|
|
@@ -20921,12 +20973,25 @@ function analyseRbd(ast) {
|
|
|
20921
20973
|
notes
|
|
20922
20974
|
};
|
|
20923
20975
|
}
|
|
20924
|
-
function collectBlocks(s, out) {
|
|
20976
|
+
function collectBlocks(s, out, mission, warnings) {
|
|
20925
20977
|
if (s.kind === "block") {
|
|
20926
|
-
|
|
20978
|
+
const R = resolveBlockR(s, mission, warnings);
|
|
20979
|
+
out.push({ id: s.id, ...R !== void 0 ? { R } : {} });
|
|
20927
20980
|
return;
|
|
20928
20981
|
}
|
|
20929
|
-
for (const c of s.children) collectBlocks(c, out);
|
|
20982
|
+
for (const c of s.children) collectBlocks(c, out, mission, warnings);
|
|
20983
|
+
}
|
|
20984
|
+
function resolveBlockR(b, mission, warnings) {
|
|
20985
|
+
if (b.dist) {
|
|
20986
|
+
if (mission === void 0) {
|
|
20987
|
+
warnings.push(`Block "${b.id}" has a failure distribution but no mission time \u2014 add 'mission: <t>' to evaluate R(t)${b.R !== void 0 ? ", falling back to its constant R" : ""}.`);
|
|
20988
|
+
return b.R;
|
|
20989
|
+
}
|
|
20990
|
+
const t = mission;
|
|
20991
|
+
if (b.dist.kind === "exp") return Math.exp(-b.dist.rate * t);
|
|
20992
|
+
return Math.exp(-Math.pow(t / b.dist.eta, b.dist.beta));
|
|
20993
|
+
}
|
|
20994
|
+
return b.R;
|
|
20930
20995
|
}
|
|
20931
20996
|
function evalStructure(s, env, notes) {
|
|
20932
20997
|
if (s.kind === "block") return env.get(s.id);
|
|
@@ -20989,11 +21054,11 @@ var RBD_CONST = {
|
|
|
20989
21054
|
HEADER_H: 26
|
|
20990
21055
|
};
|
|
20991
21056
|
function blockWidth(label) {
|
|
20992
|
-
const
|
|
20993
|
-
return Math.min(
|
|
21057
|
+
const C3 = RBD_CONST;
|
|
21058
|
+
return Math.min(C3.BLOCK_MAX_W, Math.max(C3.BLOCK_MIN_W, Math.ceil(label.length * C3.CHAR_W) + 2 * C3.PAD_X));
|
|
20994
21059
|
}
|
|
20995
21060
|
function layoutRbd(ast) {
|
|
20996
|
-
const
|
|
21061
|
+
const C3 = RBD_CONST;
|
|
20997
21062
|
const analysis = analyseRbd(ast);
|
|
20998
21063
|
const spof = new Set(analysis.blocks.filter((b) => b.isSpof).map((b) => b.id));
|
|
20999
21064
|
const rById = new Map(analysis.blocks.map((b) => [b.id, b.R]));
|
|
@@ -21003,18 +21068,18 @@ function layoutRbd(ast) {
|
|
|
21003
21068
|
const marks = [];
|
|
21004
21069
|
const measure = (s) => {
|
|
21005
21070
|
if (s.kind === "block") {
|
|
21006
|
-
return { s, w: blockWidth(s.label ?? s.id), h:
|
|
21071
|
+
return { s, w: blockWidth(s.label ?? s.id), h: C3.BLOCK_H, children: [] };
|
|
21007
21072
|
}
|
|
21008
21073
|
const children = s.children.map(measure);
|
|
21009
|
-
if (children.length === 0) return { s, w:
|
|
21074
|
+
if (children.length === 0) return { s, w: C3.BLOCK_MIN_W, h: C3.BLOCK_H, children };
|
|
21010
21075
|
if (s.kind === "series") {
|
|
21011
|
-
const w2 = children.reduce((acc, c) => acc + c.w, 0) +
|
|
21076
|
+
const w2 = children.reduce((acc, c) => acc + c.w, 0) + C3.H_GAP * (children.length - 1);
|
|
21012
21077
|
const h2 = Math.max(...children.map((c) => c.h));
|
|
21013
21078
|
return { s, w: w2, h: h2, children };
|
|
21014
21079
|
}
|
|
21015
21080
|
const innerW = Math.max(...children.map((c) => c.w));
|
|
21016
|
-
const w = innerW + 2 *
|
|
21017
|
-
const h = children.reduce((acc, c) => acc + c.h, 0) +
|
|
21081
|
+
const w = innerW + 2 * C3.SPLIT_STUB;
|
|
21082
|
+
const h = children.reduce((acc, c) => acc + c.h, 0) + C3.V_GAP * (children.length - 1);
|
|
21018
21083
|
return { s, w, h, children };
|
|
21019
21084
|
};
|
|
21020
21085
|
const place = (m, x, yc2) => {
|
|
@@ -21024,9 +21089,9 @@ function layoutRbd(ast) {
|
|
|
21024
21089
|
blocks.push({
|
|
21025
21090
|
block: s,
|
|
21026
21091
|
x,
|
|
21027
|
-
y: yc2 -
|
|
21092
|
+
y: yc2 - C3.BLOCK_H / 2,
|
|
21028
21093
|
width: m.w,
|
|
21029
|
-
height:
|
|
21094
|
+
height: C3.BLOCK_H,
|
|
21030
21095
|
...r7 !== void 0 ? { R: r7 } : {},
|
|
21031
21096
|
isSpof: spof.has(s.id),
|
|
21032
21097
|
critical: analysis.criticalBlock === s.id
|
|
@@ -21044,14 +21109,14 @@ function layoutRbd(ast) {
|
|
|
21044
21109
|
if (prevExit !== null) wires.push({ path: `M ${r6(prevExit)} ${r6(yc2)} L ${r6(ep2.entryX)} ${r6(yc2)}` });
|
|
21045
21110
|
prevExit = ep2.exitX;
|
|
21046
21111
|
lastExit = ep2.exitX;
|
|
21047
|
-
cursor = ep2.exitX +
|
|
21112
|
+
cursor = ep2.exitX + C3.H_GAP;
|
|
21048
21113
|
});
|
|
21049
21114
|
return { entryX: firstEntry, exitX: lastExit };
|
|
21050
21115
|
}
|
|
21051
21116
|
const innerW = Math.max(...m.children.map((c) => c.w));
|
|
21052
|
-
const splitX = x +
|
|
21053
|
-
const mergeX = x + m.w -
|
|
21054
|
-
const childBandX = x +
|
|
21117
|
+
const splitX = x + C3.NODE_R;
|
|
21118
|
+
const mergeX = x + m.w - C3.NODE_R;
|
|
21119
|
+
const childBandX = x + C3.SPLIT_STUB;
|
|
21055
21120
|
nodes.push({ kind: "split", x: splitX, y: yc2 });
|
|
21056
21121
|
nodes.push({ kind: "join", x: mergeX, y: yc2 });
|
|
21057
21122
|
let runY = yc2 - m.h / 2;
|
|
@@ -21061,7 +21126,7 @@ function layoutRbd(ast) {
|
|
|
21061
21126
|
const ep2 = place(cm, childStartX, childYc);
|
|
21062
21127
|
wires.push({ path: `M ${r6(splitX)} ${r6(yc2)} L ${r6(splitX)} ${r6(childYc)} L ${r6(ep2.entryX)} ${r6(childYc)}` });
|
|
21063
21128
|
wires.push({ path: `M ${r6(ep2.exitX)} ${r6(childYc)} L ${r6(mergeX)} ${r6(childYc)} L ${r6(mergeX)} ${r6(yc2)}` });
|
|
21064
|
-
runY += cm.h +
|
|
21129
|
+
runY += cm.h + C3.V_GAP;
|
|
21065
21130
|
}
|
|
21066
21131
|
if (s.kind === "kofn") {
|
|
21067
21132
|
marks.push({ x: mergeX + 6, y: yc2 - m.h / 2 - 6, text: `${s.k}/${s.n ?? m.children.length}` });
|
|
@@ -21069,12 +21134,12 @@ function layoutRbd(ast) {
|
|
|
21069
21134
|
return { entryX: splitX, exitX: mergeX };
|
|
21070
21135
|
};
|
|
21071
21136
|
const rootM = measure(ast.root);
|
|
21072
|
-
const headerH = (ast.title ?
|
|
21073
|
-
const yc =
|
|
21074
|
-
const originX =
|
|
21137
|
+
const headerH = (ast.title ? C3.TITLE_H : 0) + C3.HEADER_H;
|
|
21138
|
+
const yc = C3.CANVAS_PAD + headerH + rootM.h / 2;
|
|
21139
|
+
const originX = C3.CANVAS_PAD + C3.TERM_STUB;
|
|
21075
21140
|
const ep = place(rootM, originX, yc);
|
|
21076
|
-
const inX =
|
|
21077
|
-
const outX = ep.exitX +
|
|
21141
|
+
const inX = C3.CANVAS_PAD;
|
|
21142
|
+
const outX = ep.exitX + C3.TERM_STUB;
|
|
21078
21143
|
nodes.push({ kind: "in", x: inX, y: yc });
|
|
21079
21144
|
nodes.push({ kind: "out", x: outX, y: yc });
|
|
21080
21145
|
wires.push({ path: `M ${r6(inX)} ${r6(yc)} L ${r6(ep.entryX)} ${r6(yc)}` });
|
|
@@ -21084,7 +21149,7 @@ function layoutRbd(ast) {
|
|
|
21084
21149
|
for (const b of blocks) {
|
|
21085
21150
|
maxX = Math.max(maxX, b.x + b.width);
|
|
21086
21151
|
const capLines = (b.R !== void 0 ? 1 : 0) + (b.block.label && b.block.label !== b.block.id ? 1 : 0);
|
|
21087
|
-
maxY = Math.max(maxY, b.y + b.height + (capLines > 0 ?
|
|
21152
|
+
maxY = Math.max(maxY, b.y + b.height + (capLines > 0 ? C3.CAP_GAP + capLines * C3.CAP_LINE_H : 0));
|
|
21088
21153
|
}
|
|
21089
21154
|
for (const mk of marks) maxX = Math.max(maxX, mk.x + 24);
|
|
21090
21155
|
return {
|
|
@@ -21094,8 +21159,8 @@ function layoutRbd(ast) {
|
|
|
21094
21159
|
nodes,
|
|
21095
21160
|
wires,
|
|
21096
21161
|
marks,
|
|
21097
|
-
width: Math.ceil(maxX +
|
|
21098
|
-
height: Math.ceil(maxY +
|
|
21162
|
+
width: Math.ceil(maxX + C3.CANVAS_PAD),
|
|
21163
|
+
height: Math.ceil(maxY + C3.CANVAS_PAD)
|
|
21099
21164
|
};
|
|
21100
21165
|
}
|
|
21101
21166
|
function r6(n) {
|
|
@@ -21157,7 +21222,7 @@ function renderRbdLayout(layout, config) {
|
|
|
21157
21222
|
class: "sx-rbd-rsys",
|
|
21158
21223
|
"text-anchor": "middle"
|
|
21159
21224
|
},
|
|
21160
|
-
systemLabel(analysis)
|
|
21225
|
+
systemLabel(analysis, ast.mission)
|
|
21161
21226
|
)
|
|
21162
21227
|
);
|
|
21163
21228
|
for (const w of layout.wires) inner.push(path({ d: w.path, class: "sx-rbd-wire" }));
|
|
@@ -21227,12 +21292,16 @@ function renderBlock(b) {
|
|
|
21227
21292
|
parts
|
|
21228
21293
|
);
|
|
21229
21294
|
}
|
|
21230
|
-
function systemLabel(analysis) {
|
|
21295
|
+
function systemLabel(analysis, mission) {
|
|
21231
21296
|
if (analysis.systemReliability === void 0) {
|
|
21232
21297
|
const miss = analysis.missing.length > 0 ? ` \u2014 missing R on ${analysis.missing.join(", ")}` : "";
|
|
21233
21298
|
return `System reliability: n/a${miss}`;
|
|
21234
21299
|
}
|
|
21235
|
-
|
|
21300
|
+
const arg = mission !== void 0 ? `(t=${fmtVal3(mission)})` : "";
|
|
21301
|
+
return `System reliability R${arg} = ${fmtR(analysis.systemReliability)}`;
|
|
21302
|
+
}
|
|
21303
|
+
function fmtVal3(n) {
|
|
21304
|
+
return String(parseFloat(n.toFixed(2)));
|
|
21236
21305
|
}
|
|
21237
21306
|
function fmtR(n) {
|
|
21238
21307
|
if (n >= 1) return "1";
|
|
@@ -21290,6 +21359,1245 @@ var rbd = {
|
|
|
21290
21359
|
}
|
|
21291
21360
|
};
|
|
21292
21361
|
|
|
21362
|
+
// src/diagrams/comparison/parser.ts
|
|
21363
|
+
var ComparisonParseError = class extends Error {
|
|
21364
|
+
constructor(message, line2) {
|
|
21365
|
+
super(line2 ? `Line ${line2}: ${message}` : message);
|
|
21366
|
+
this.line = line2;
|
|
21367
|
+
this.name = "ComparisonParseError";
|
|
21368
|
+
}
|
|
21369
|
+
line;
|
|
21370
|
+
};
|
|
21371
|
+
var MODES = [
|
|
21372
|
+
"tchart",
|
|
21373
|
+
"pros-cons",
|
|
21374
|
+
"matrix",
|
|
21375
|
+
"decision",
|
|
21376
|
+
"double-bubble"
|
|
21377
|
+
];
|
|
21378
|
+
function parseComparison(text2) {
|
|
21379
|
+
const ast = {
|
|
21380
|
+
type: "comparison",
|
|
21381
|
+
mode: "tchart",
|
|
21382
|
+
columns: [],
|
|
21383
|
+
pros: [],
|
|
21384
|
+
cons: [],
|
|
21385
|
+
options: [],
|
|
21386
|
+
criteria: [],
|
|
21387
|
+
legend: "on",
|
|
21388
|
+
warnings: []
|
|
21389
|
+
};
|
|
21390
|
+
const rawLines = text2.split(/\r?\n/);
|
|
21391
|
+
let i = 0;
|
|
21392
|
+
let explicitMode;
|
|
21393
|
+
while (i < rawLines.length) {
|
|
21394
|
+
const t = stripComment8(rawLines[i] ?? "").trim();
|
|
21395
|
+
if (t === "") {
|
|
21396
|
+
i++;
|
|
21397
|
+
continue;
|
|
21398
|
+
}
|
|
21399
|
+
const h = /^(comparison|compare|vs|tchart|t-chart|pugh|decision-matrix|decisionmatrix)\b(.*)$/i.exec(t);
|
|
21400
|
+
if (h) {
|
|
21401
|
+
const head = h[1].toLowerCase();
|
|
21402
|
+
if (head === "tchart" || head === "t-chart") explicitMode = "tchart";
|
|
21403
|
+
else if (head === "pugh" || head === "decision-matrix" || head === "decisionmatrix")
|
|
21404
|
+
explicitMode = "decision";
|
|
21405
|
+
const q = matchQuoted6(h[2].trim());
|
|
21406
|
+
if (q) ast.title = q.value;
|
|
21407
|
+
i++;
|
|
21408
|
+
}
|
|
21409
|
+
break;
|
|
21410
|
+
}
|
|
21411
|
+
let curColumn = null;
|
|
21412
|
+
let curCriterion = null;
|
|
21413
|
+
let colCount = 0;
|
|
21414
|
+
let optCount = 0;
|
|
21415
|
+
let critCount = 0;
|
|
21416
|
+
const bubble = { left: "", right: "", shared: [], leftOnly: [], rightOnly: [] };
|
|
21417
|
+
for (; i < rawLines.length; i++) {
|
|
21418
|
+
const t = stripComment8(rawLines[i] ?? "").trim();
|
|
21419
|
+
if (t === "") continue;
|
|
21420
|
+
const lineNo = i + 1;
|
|
21421
|
+
if (/^mode\s*:/i.test(t)) {
|
|
21422
|
+
const v = afterColon6(t).toLowerCase().replace(/\s+/g, "-");
|
|
21423
|
+
const m = normaliseMode(v);
|
|
21424
|
+
if (m) explicitMode = m;
|
|
21425
|
+
else ast.warnings.push(`Line ${lineNo}: unknown mode "${afterColon6(t)}" \u2014 using ${explicitMode ?? "inferred"}.`);
|
|
21426
|
+
continue;
|
|
21427
|
+
}
|
|
21428
|
+
if (/^legend\s*:/i.test(t)) {
|
|
21429
|
+
const v = afterColon6(t).toLowerCase();
|
|
21430
|
+
if (v === "on" || v === "off") ast.legend = v;
|
|
21431
|
+
continue;
|
|
21432
|
+
}
|
|
21433
|
+
if (/^baseline\s*:/i.test(t)) {
|
|
21434
|
+
const q = matchQuoted6(afterColon6(t));
|
|
21435
|
+
ast.baseline = q ? q.value : afterColon6(t);
|
|
21436
|
+
continue;
|
|
21437
|
+
}
|
|
21438
|
+
if (/^(title|subject)\s*:/i.test(t)) {
|
|
21439
|
+
const q = matchQuoted6(afterColon6(t));
|
|
21440
|
+
const val = q ? q.value : afterColon6(t);
|
|
21441
|
+
if (/^subject/i.test(t)) ast.subject = val;
|
|
21442
|
+
else if (!ast.title) ast.title = val;
|
|
21443
|
+
continue;
|
|
21444
|
+
}
|
|
21445
|
+
if (/^theme\s*:/i.test(t)) continue;
|
|
21446
|
+
if (curCriterion) {
|
|
21447
|
+
const ref = cellPrefix(t);
|
|
21448
|
+
if (ref !== null) {
|
|
21449
|
+
const valTok = t.slice(t.indexOf(":") + 1).trim();
|
|
21450
|
+
const opt = findOption(ast.options, ref);
|
|
21451
|
+
if (!opt) {
|
|
21452
|
+
ast.warnings.push(
|
|
21453
|
+
`Line ${lineNo}: "${ref}" is not a declared option \u2014 add \`option "${ref}"\` or fix the name.`
|
|
21454
|
+
);
|
|
21455
|
+
} else {
|
|
21456
|
+
curCriterion.cells[opt.id] = parseCellValue(valTok);
|
|
21457
|
+
}
|
|
21458
|
+
continue;
|
|
21459
|
+
}
|
|
21460
|
+
}
|
|
21461
|
+
const kw = /^([a-z][a-z-]*)\b/i.exec(t);
|
|
21462
|
+
const keyword = kw ? kw[1].toLowerCase() : "";
|
|
21463
|
+
const rest = kw ? t.slice(kw[0].length).trim() : t;
|
|
21464
|
+
switch (keyword) {
|
|
21465
|
+
case "column":
|
|
21466
|
+
case "col": {
|
|
21467
|
+
const label = requireLabel2(rest, keyword, lineNo);
|
|
21468
|
+
curColumn = { id: `col${++colCount}`, label, items: [] };
|
|
21469
|
+
ast.columns.push(curColumn);
|
|
21470
|
+
curCriterion = null;
|
|
21471
|
+
break;
|
|
21472
|
+
}
|
|
21473
|
+
case "item": {
|
|
21474
|
+
const label = requireLabel2(rest, keyword, lineNo);
|
|
21475
|
+
if (!curColumn) {
|
|
21476
|
+
ast.warnings.push(`Line ${lineNo}: \`item\` before any \`column\` \u2014 ignored.`);
|
|
21477
|
+
} else curColumn.items.push(label);
|
|
21478
|
+
break;
|
|
21479
|
+
}
|
|
21480
|
+
case "pro": {
|
|
21481
|
+
ast.pros.push(requireLabel2(rest, keyword, lineNo));
|
|
21482
|
+
break;
|
|
21483
|
+
}
|
|
21484
|
+
case "con": {
|
|
21485
|
+
ast.cons.push(requireLabel2(rest, keyword, lineNo));
|
|
21486
|
+
break;
|
|
21487
|
+
}
|
|
21488
|
+
case "option":
|
|
21489
|
+
case "opt": {
|
|
21490
|
+
const label = requireLabel2(rest, keyword, lineNo);
|
|
21491
|
+
ast.options.push({ id: `o${++optCount}`, label });
|
|
21492
|
+
curCriterion = null;
|
|
21493
|
+
break;
|
|
21494
|
+
}
|
|
21495
|
+
case "criterion":
|
|
21496
|
+
case "criteria":
|
|
21497
|
+
case "row": {
|
|
21498
|
+
curCriterion = parseCriterion(rest, `c${++critCount}`, keyword, lineNo, ast.options, ast.warnings, lineNo);
|
|
21499
|
+
ast.criteria.push(curCriterion);
|
|
21500
|
+
curColumn = null;
|
|
21501
|
+
break;
|
|
21502
|
+
}
|
|
21503
|
+
case "left":
|
|
21504
|
+
bubble.left = requireLabel2(rest, keyword, lineNo);
|
|
21505
|
+
break;
|
|
21506
|
+
case "right":
|
|
21507
|
+
bubble.right = requireLabel2(rest, keyword, lineNo);
|
|
21508
|
+
break;
|
|
21509
|
+
case "shared":
|
|
21510
|
+
case "both":
|
|
21511
|
+
bubble.shared.push(requireLabel2(rest, keyword, lineNo));
|
|
21512
|
+
break;
|
|
21513
|
+
case "left-only":
|
|
21514
|
+
case "leftonly":
|
|
21515
|
+
bubble.leftOnly.push(requireLabel2(rest, keyword, lineNo));
|
|
21516
|
+
break;
|
|
21517
|
+
case "right-only":
|
|
21518
|
+
case "rightonly":
|
|
21519
|
+
bubble.rightOnly.push(requireLabel2(rest, keyword, lineNo));
|
|
21520
|
+
break;
|
|
21521
|
+
default: {
|
|
21522
|
+
const bullet = /^[-*•]\s+(.*)$/.exec(t);
|
|
21523
|
+
if (bullet && curColumn) {
|
|
21524
|
+
curColumn.items.push(unquoteLoose(bullet[1].trim()));
|
|
21525
|
+
} else if (bullet) {
|
|
21526
|
+
ast.warnings.push(`Line ${lineNo}: bullet "${truncate7(t, 60)}" before any \`column\` \u2014 ignored.`);
|
|
21527
|
+
} else {
|
|
21528
|
+
ast.warnings.push(`Line ${lineNo}: unrecognised line: "${truncate7(t, 80)}"`);
|
|
21529
|
+
}
|
|
21530
|
+
}
|
|
21531
|
+
}
|
|
21532
|
+
}
|
|
21533
|
+
if (bubble.left || bubble.right || bubble.shared.length) {
|
|
21534
|
+
ast.bubble = bubble;
|
|
21535
|
+
}
|
|
21536
|
+
ast.mode = explicitMode ?? inferMode(ast);
|
|
21537
|
+
validate4(ast);
|
|
21538
|
+
return ast;
|
|
21539
|
+
}
|
|
21540
|
+
function parseCriterion(rest, id, keyword, lineNo, options, warnings, ln) {
|
|
21541
|
+
const pipeIdx = rest.indexOf("|");
|
|
21542
|
+
let head = pipeIdx >= 0 ? rest.slice(0, pipeIdx).trim() : rest;
|
|
21543
|
+
const cells = {};
|
|
21544
|
+
let weight;
|
|
21545
|
+
const wm = /\b(?:weight|w)\s*[:=]\s*(\d+(?:\.\d+)?)/i.exec(head);
|
|
21546
|
+
if (wm) {
|
|
21547
|
+
weight = Number(wm[1]);
|
|
21548
|
+
head = head.slice(0, wm.index).trim() + head.slice(wm.index + wm[0].length).trim();
|
|
21549
|
+
head = head.trim();
|
|
21550
|
+
}
|
|
21551
|
+
const label = requireLabel2(head, keyword, lineNo);
|
|
21552
|
+
if (pipeIdx >= 0) {
|
|
21553
|
+
const parts = rest.slice(pipeIdx + 1).split("|").map((p) => p.trim());
|
|
21554
|
+
parts.forEach((p, k) => {
|
|
21555
|
+
const opt = options[k];
|
|
21556
|
+
if (!opt) {
|
|
21557
|
+
if (p) warnings.push(`Line ${ln}: pipe value "${p}" has no matching option (only ${options.length} declared).`);
|
|
21558
|
+
return;
|
|
21559
|
+
}
|
|
21560
|
+
if (p) cells[opt.id] = parseCellValue(p);
|
|
21561
|
+
});
|
|
21562
|
+
}
|
|
21563
|
+
const crit = { id, label, cells };
|
|
21564
|
+
if (weight !== void 0) crit.weight = weight;
|
|
21565
|
+
return crit;
|
|
21566
|
+
}
|
|
21567
|
+
function parseCellValue(tok) {
|
|
21568
|
+
const raw = tok;
|
|
21569
|
+
const q = matchQuoted6(tok);
|
|
21570
|
+
if (q) return { text: q.value, raw };
|
|
21571
|
+
const low = tok.toLowerCase();
|
|
21572
|
+
if (/^(yes|y|true|✓|✔|check)$/.test(low)) return { glyph: "yes", raw };
|
|
21573
|
+
if (/^(no|n|false|✗|✘|x|cross)$/.test(low)) return { glyph: "no", raw };
|
|
21574
|
+
if (/^(partial|part|~|maybe|some|half)$/.test(low)) return { glyph: "partial", raw };
|
|
21575
|
+
if (/^(na|n\/a|-|—|none)$/.test(low)) return { glyph: "na", raw };
|
|
21576
|
+
const num4 = Number(tok);
|
|
21577
|
+
if (tok !== "" && !Number.isNaN(num4)) return { score: num4, raw };
|
|
21578
|
+
return { text: tok, raw };
|
|
21579
|
+
}
|
|
21580
|
+
function inferMode(ast) {
|
|
21581
|
+
if (ast.bubble) return "double-bubble";
|
|
21582
|
+
if (ast.pros.length || ast.cons.length) return "pros-cons";
|
|
21583
|
+
if (ast.options.length || ast.criteria.length) {
|
|
21584
|
+
const anyScore = ast.criteria.some(
|
|
21585
|
+
(c) => Object.values(c.cells).some((v) => typeof v.score === "number")
|
|
21586
|
+
);
|
|
21587
|
+
const anyWeight = ast.criteria.some((c) => c.weight !== void 0);
|
|
21588
|
+
return anyScore || anyWeight || ast.baseline ? "decision" : "matrix";
|
|
21589
|
+
}
|
|
21590
|
+
return "tchart";
|
|
21591
|
+
}
|
|
21592
|
+
function normaliseMode(v) {
|
|
21593
|
+
if (v === "ychart" || v === "y-chart") return "tchart";
|
|
21594
|
+
if (v === "proscons" || v === "pro-con" || v === "pros-and-cons") return "pros-cons";
|
|
21595
|
+
if (v === "pugh" || v === "decision-matrix") return "decision";
|
|
21596
|
+
if (v === "doublebubble" || v === "double-bubble" || v === "compare-contrast") return "double-bubble";
|
|
21597
|
+
return MODES.includes(v) ? v : void 0;
|
|
21598
|
+
}
|
|
21599
|
+
function validate4(ast) {
|
|
21600
|
+
switch (ast.mode) {
|
|
21601
|
+
case "tchart": {
|
|
21602
|
+
if (ast.columns.length === 0) {
|
|
21603
|
+
throw new ComparisonParseError(
|
|
21604
|
+
`a tchart needs at least one \`column "\u2026"\` \u2014 declare the columns you want to compare.`
|
|
21605
|
+
);
|
|
21606
|
+
}
|
|
21607
|
+
break;
|
|
21608
|
+
}
|
|
21609
|
+
case "pros-cons": {
|
|
21610
|
+
if (ast.pros.length === 0 && ast.cons.length === 0) {
|
|
21611
|
+
throw new ComparisonParseError(
|
|
21612
|
+
`a pros-cons needs at least one \`pro "\u2026"\` or \`con "\u2026"\` line.`
|
|
21613
|
+
);
|
|
21614
|
+
}
|
|
21615
|
+
break;
|
|
21616
|
+
}
|
|
21617
|
+
case "matrix":
|
|
21618
|
+
case "decision": {
|
|
21619
|
+
if (ast.options.length === 0) {
|
|
21620
|
+
throw new ComparisonParseError(
|
|
21621
|
+
`a ${ast.mode} matrix needs at least one \`option "\u2026"\` \u2014 declare the options (columns) you are comparing.`
|
|
21622
|
+
);
|
|
21623
|
+
}
|
|
21624
|
+
if (ast.criteria.length === 0) {
|
|
21625
|
+
throw new ComparisonParseError(
|
|
21626
|
+
`a ${ast.mode} matrix needs at least one \`criterion "\u2026"\` \u2014 declare the criteria (rows) to compare on.`
|
|
21627
|
+
);
|
|
21628
|
+
}
|
|
21629
|
+
if (ast.mode === "decision") {
|
|
21630
|
+
const anyScore = ast.criteria.some(
|
|
21631
|
+
(c) => Object.values(c.cells).some((v) => typeof v.score === "number")
|
|
21632
|
+
);
|
|
21633
|
+
if (!anyScore) {
|
|
21634
|
+
ast.warnings.push(
|
|
21635
|
+
`decision mode but no numeric scores found \u2014 add \`Option: <number>\` lines under each criterion, or switch to \`mode: matrix\`.`
|
|
21636
|
+
);
|
|
21637
|
+
}
|
|
21638
|
+
if (ast.baseline) {
|
|
21639
|
+
const ok = ast.options.some((o) => o.label === ast.baseline || o.id === ast.baseline);
|
|
21640
|
+
if (!ok) {
|
|
21641
|
+
ast.warnings.push(
|
|
21642
|
+
`baseline "${ast.baseline}" is not one of the declared options \u2014 ignored.`
|
|
21643
|
+
);
|
|
21644
|
+
delete ast.baseline;
|
|
21645
|
+
}
|
|
21646
|
+
}
|
|
21647
|
+
}
|
|
21648
|
+
break;
|
|
21649
|
+
}
|
|
21650
|
+
case "double-bubble": {
|
|
21651
|
+
if (!ast.bubble || !ast.bubble.left || !ast.bubble.right) {
|
|
21652
|
+
throw new ComparisonParseError(
|
|
21653
|
+
`a double-bubble needs both a \`left "\u2026"\` and a \`right "\u2026"\` centre to compare.`
|
|
21654
|
+
);
|
|
21655
|
+
}
|
|
21656
|
+
break;
|
|
21657
|
+
}
|
|
21658
|
+
}
|
|
21659
|
+
}
|
|
21660
|
+
var RESERVED_KEYWORDS = /* @__PURE__ */ new Set([
|
|
21661
|
+
"comparison",
|
|
21662
|
+
"compare",
|
|
21663
|
+
"vs",
|
|
21664
|
+
"tchart",
|
|
21665
|
+
"t-chart",
|
|
21666
|
+
"pugh",
|
|
21667
|
+
"decision-matrix",
|
|
21668
|
+
"decisionmatrix",
|
|
21669
|
+
"mode",
|
|
21670
|
+
"legend",
|
|
21671
|
+
"baseline",
|
|
21672
|
+
"title",
|
|
21673
|
+
"subject",
|
|
21674
|
+
"theme",
|
|
21675
|
+
"column",
|
|
21676
|
+
"col",
|
|
21677
|
+
"item",
|
|
21678
|
+
"pro",
|
|
21679
|
+
"con",
|
|
21680
|
+
"option",
|
|
21681
|
+
"opt",
|
|
21682
|
+
"criterion",
|
|
21683
|
+
"criteria",
|
|
21684
|
+
"row",
|
|
21685
|
+
"left",
|
|
21686
|
+
"right",
|
|
21687
|
+
"shared",
|
|
21688
|
+
"both",
|
|
21689
|
+
"left-only",
|
|
21690
|
+
"leftonly",
|
|
21691
|
+
"right-only",
|
|
21692
|
+
"rightonly"
|
|
21693
|
+
]);
|
|
21694
|
+
function cellPrefix(t) {
|
|
21695
|
+
const ci = t.indexOf(":");
|
|
21696
|
+
if (ci <= 0) return null;
|
|
21697
|
+
const pre = t.slice(0, ci).trim();
|
|
21698
|
+
if (!pre) return null;
|
|
21699
|
+
const firstWord2 = (pre.split(/\s+/)[0] ?? "").toLowerCase();
|
|
21700
|
+
if (RESERVED_KEYWORDS.has(firstWord2)) return null;
|
|
21701
|
+
return pre;
|
|
21702
|
+
}
|
|
21703
|
+
function findOption(options, ref) {
|
|
21704
|
+
const r7 = ref.toLowerCase();
|
|
21705
|
+
return options.find((o) => o.label.toLowerCase() === r7 || o.id.toLowerCase() === r7);
|
|
21706
|
+
}
|
|
21707
|
+
function requireLabel2(s, keyword, lineNo) {
|
|
21708
|
+
const q = matchQuoted6(s);
|
|
21709
|
+
if (q) return q.value;
|
|
21710
|
+
const bare = s.trim();
|
|
21711
|
+
if (!bare) throw new ComparisonParseError(`\`${keyword}\` needs a label`, lineNo);
|
|
21712
|
+
return bare;
|
|
21713
|
+
}
|
|
21714
|
+
function unquoteLoose(s) {
|
|
21715
|
+
const q = matchQuoted6(s);
|
|
21716
|
+
return q && q.length === s.length ? q.value : s;
|
|
21717
|
+
}
|
|
21718
|
+
function matchQuoted6(s) {
|
|
21719
|
+
if (!s) return void 0;
|
|
21720
|
+
const open = s[0];
|
|
21721
|
+
if (open !== '"' && open !== "\u300C" && open !== "\u201C" && open !== "\u300E") return void 0;
|
|
21722
|
+
const close = closingQuote6(open);
|
|
21723
|
+
const end = s.indexOf(close, 1);
|
|
21724
|
+
if (end < 0) return void 0;
|
|
21725
|
+
return { value: s.slice(1, end), length: end + 1 };
|
|
21726
|
+
}
|
|
21727
|
+
function closingQuote6(open) {
|
|
21728
|
+
return open === "\u300C" ? "\u300D" : open === "\u300E" ? "\u300F" : open === "\u201C" ? "\u201D" : '"';
|
|
21729
|
+
}
|
|
21730
|
+
function afterColon6(s) {
|
|
21731
|
+
const i = s.indexOf(":");
|
|
21732
|
+
return i < 0 ? "" : s.slice(i + 1).trim();
|
|
21733
|
+
}
|
|
21734
|
+
function stripComment8(line2) {
|
|
21735
|
+
let inQ = false;
|
|
21736
|
+
let qc = "";
|
|
21737
|
+
for (let i = 0; i < line2.length; i++) {
|
|
21738
|
+
const ch = line2[i];
|
|
21739
|
+
if (inQ) {
|
|
21740
|
+
if (ch === qc) inQ = false;
|
|
21741
|
+
continue;
|
|
21742
|
+
}
|
|
21743
|
+
if (ch === '"' || ch === "\u300C" || ch === "\u201C" || ch === "\u300E") {
|
|
21744
|
+
inQ = true;
|
|
21745
|
+
qc = closingQuote6(ch);
|
|
21746
|
+
continue;
|
|
21747
|
+
}
|
|
21748
|
+
if (ch === "#") return line2.slice(0, i);
|
|
21749
|
+
if (ch === "/" && line2[i + 1] === "/") return line2.slice(0, i);
|
|
21750
|
+
}
|
|
21751
|
+
return line2;
|
|
21752
|
+
}
|
|
21753
|
+
function truncate7(s, n) {
|
|
21754
|
+
return s.length <= n ? s : s.slice(0, n - 1) + "\u2026";
|
|
21755
|
+
}
|
|
21756
|
+
|
|
21757
|
+
// src/diagrams/comparison/compute.ts
|
|
21758
|
+
function scoreOf(v) {
|
|
21759
|
+
if (!v) return 0;
|
|
21760
|
+
if (typeof v.score === "number") return v.score;
|
|
21761
|
+
if (v.glyph === "yes") return 1;
|
|
21762
|
+
if (v.glyph === "partial") return 0.5;
|
|
21763
|
+
if (v.glyph === "no" || v.glyph === "na") return 0;
|
|
21764
|
+
return 0;
|
|
21765
|
+
}
|
|
21766
|
+
function computeDecision(ast) {
|
|
21767
|
+
const totals = {};
|
|
21768
|
+
const totalWeight = ast.criteria.reduce((s, c) => s + (c.weight ?? 1), 0);
|
|
21769
|
+
for (const opt of ast.options) {
|
|
21770
|
+
let sum = 0;
|
|
21771
|
+
for (const crit of ast.criteria) {
|
|
21772
|
+
const w = crit.weight ?? 1;
|
|
21773
|
+
sum += w * scoreOf(crit.cells[opt.id]);
|
|
21774
|
+
}
|
|
21775
|
+
totals[opt.id] = round7(sum);
|
|
21776
|
+
}
|
|
21777
|
+
const sorted = [...ast.options].sort((a, b) => totals[b.id] - totals[a.id]);
|
|
21778
|
+
const ranks = {};
|
|
21779
|
+
let lastTotal = Number.POSITIVE_INFINITY;
|
|
21780
|
+
let lastRank = 0;
|
|
21781
|
+
sorted.forEach((opt, i) => {
|
|
21782
|
+
const t = totals[opt.id];
|
|
21783
|
+
if (t < lastTotal) {
|
|
21784
|
+
lastRank = i + 1;
|
|
21785
|
+
lastTotal = t;
|
|
21786
|
+
}
|
|
21787
|
+
ranks[opt.id] = lastRank;
|
|
21788
|
+
});
|
|
21789
|
+
const winnerId = sorted.length ? sorted[0].id : "";
|
|
21790
|
+
const maxTotal = sorted.length ? totals[winnerId] : 0;
|
|
21791
|
+
const result = { totals, ranks, winnerId, maxTotal, totalWeight };
|
|
21792
|
+
if (ast.baseline) {
|
|
21793
|
+
const base = ast.options.find(
|
|
21794
|
+
(o) => o.id === ast.baseline || o.label === ast.baseline
|
|
21795
|
+
);
|
|
21796
|
+
if (base) {
|
|
21797
|
+
const baseTotal = totals[base.id];
|
|
21798
|
+
const deltas = {};
|
|
21799
|
+
for (const opt of ast.options) deltas[opt.id] = round7(totals[opt.id] - baseTotal);
|
|
21800
|
+
result.deltas = deltas;
|
|
21801
|
+
}
|
|
21802
|
+
}
|
|
21803
|
+
return result;
|
|
21804
|
+
}
|
|
21805
|
+
function decisionCaption(ast, r7) {
|
|
21806
|
+
if (!ast.options.length) return "Decision matrix: no options.";
|
|
21807
|
+
const winner = ast.options.find((o) => o.id === r7.winnerId);
|
|
21808
|
+
const tiedIds = ast.options.filter((o) => r7.ranks[o.id] === 1).map((o) => o.id);
|
|
21809
|
+
if (tiedIds.length > 1) {
|
|
21810
|
+
const names = tiedIds.map((id) => ast.options.find((o) => o.id === id)?.label).filter(Boolean).map((n) => `"${n}"`).join(" / ");
|
|
21811
|
+
return `Tie at the top: ${names} (weighted score ${fmt3(r7.maxTotal)} of ${ast.options.length} options).`;
|
|
21812
|
+
}
|
|
21813
|
+
return `Winner: "${winner?.label ?? r7.winnerId}" \u2014 weighted score ${fmt3(
|
|
21814
|
+
r7.maxTotal
|
|
21815
|
+
)}, highest of ${ast.options.length} option${ast.options.length === 1 ? "" : "s"}.`;
|
|
21816
|
+
}
|
|
21817
|
+
function round7(n) {
|
|
21818
|
+
return Math.round(n * 1e3) / 1e3;
|
|
21819
|
+
}
|
|
21820
|
+
function fmt3(n) {
|
|
21821
|
+
const r7 = Math.round(n * 100) / 100;
|
|
21822
|
+
return Number.isInteger(r7) ? String(r7) : String(r7);
|
|
21823
|
+
}
|
|
21824
|
+
|
|
21825
|
+
// src/diagrams/comparison/layout.ts
|
|
21826
|
+
var COMPARISON_CONST = {
|
|
21827
|
+
PAGE_PAD: 24,
|
|
21828
|
+
TITLE_H: 40,
|
|
21829
|
+
CAPTION_H: 30,
|
|
21830
|
+
HEADER_MIN_H: 36,
|
|
21831
|
+
ROW_MIN_H: 34,
|
|
21832
|
+
CELL_PAD_X: 12,
|
|
21833
|
+
CELL_PAD_Y: 8,
|
|
21834
|
+
LINE_H: 16,
|
|
21835
|
+
COL_MIN_W: 140,
|
|
21836
|
+
COL_MAX_W: 264,
|
|
21837
|
+
MARK_COL_MIN_W: 92,
|
|
21838
|
+
MARK_COL_MAX_W: 190,
|
|
21839
|
+
ROWHEAD_MIN_W: 120,
|
|
21840
|
+
ROWHEAD_MAX_W: 230,
|
|
21841
|
+
FONT: 12,
|
|
21842
|
+
HEADER_FONT: 13,
|
|
21843
|
+
// double-bubble — larger, rounder bubbles with generous spacing
|
|
21844
|
+
CENTER_RX: 70,
|
|
21845
|
+
CENTER_RY: 58,
|
|
21846
|
+
SHARED_RX: 60,
|
|
21847
|
+
SHARED_RY: 46,
|
|
21848
|
+
UNIQUE_RX: 70,
|
|
21849
|
+
UNIQUE_RY: 46,
|
|
21850
|
+
BUBBLE_VGAP: 22,
|
|
21851
|
+
// tchart
|
|
21852
|
+
TCHART_COL_GAP: 22,
|
|
21853
|
+
// pros-cons
|
|
21854
|
+
PC_COL_W: 322,
|
|
21855
|
+
PC_COL_GAP: 30,
|
|
21856
|
+
PC_PILL_H: 40,
|
|
21857
|
+
PC_ROW_MIN_H: 40,
|
|
21858
|
+
PC_BADGE_R: 11
|
|
21859
|
+
};
|
|
21860
|
+
function charW(ch, fontSize) {
|
|
21861
|
+
const cp = ch.codePointAt(0) ?? 0;
|
|
21862
|
+
if (cp >= 11904 && cp <= 40959) return fontSize;
|
|
21863
|
+
if (cp >= 44032 && cp <= 55203) return fontSize;
|
|
21864
|
+
if (cp >= 65280 && cp <= 65519) return fontSize;
|
|
21865
|
+
if (ch === " ") return fontSize * 0.3;
|
|
21866
|
+
if (/[ilj.,:'!|]/.test(ch)) return fontSize * 0.3;
|
|
21867
|
+
if (/[mwMW]/.test(ch)) return fontSize * 0.85;
|
|
21868
|
+
return fontSize * 0.56;
|
|
21869
|
+
}
|
|
21870
|
+
function measureText(s, fontSize) {
|
|
21871
|
+
let w = 0;
|
|
21872
|
+
for (const ch of s) w += charW(ch, fontSize);
|
|
21873
|
+
return w;
|
|
21874
|
+
}
|
|
21875
|
+
function wrapToWidth(s, maxW, fontSize) {
|
|
21876
|
+
if (!s) return [""];
|
|
21877
|
+
const hasSpaces = /\s/.test(s.trim());
|
|
21878
|
+
const tokens = hasSpaces ? s.split(/\s+/).filter(Boolean) : [...s];
|
|
21879
|
+
const sep = hasSpaces ? " " : "";
|
|
21880
|
+
const lines = [];
|
|
21881
|
+
let cur = "";
|
|
21882
|
+
for (const tok of tokens) {
|
|
21883
|
+
const trial = cur ? cur + sep + tok : tok;
|
|
21884
|
+
if (cur && measureText(trial, fontSize) > maxW) {
|
|
21885
|
+
lines.push(cur);
|
|
21886
|
+
cur = tok;
|
|
21887
|
+
} else {
|
|
21888
|
+
cur = trial;
|
|
21889
|
+
}
|
|
21890
|
+
}
|
|
21891
|
+
if (cur) lines.push(cur);
|
|
21892
|
+
return lines.length ? lines : [""];
|
|
21893
|
+
}
|
|
21894
|
+
var C2 = COMPARISON_CONST;
|
|
21895
|
+
function layoutComparison(ast) {
|
|
21896
|
+
switch (ast.mode) {
|
|
21897
|
+
case "tchart":
|
|
21898
|
+
return layoutColumns(ast);
|
|
21899
|
+
case "pros-cons":
|
|
21900
|
+
return layoutProsCons(ast);
|
|
21901
|
+
case "matrix":
|
|
21902
|
+
case "decision":
|
|
21903
|
+
return layoutGrid(ast);
|
|
21904
|
+
case "double-bubble":
|
|
21905
|
+
return layoutDoubleBubble(ast);
|
|
21906
|
+
}
|
|
21907
|
+
}
|
|
21908
|
+
function frame(ast) {
|
|
21909
|
+
const pad = C2.PAGE_PAD;
|
|
21910
|
+
const top = pad + (ast.title ? C2.TITLE_H : 0);
|
|
21911
|
+
return { top, pad };
|
|
21912
|
+
}
|
|
21913
|
+
function layoutColumns(ast) {
|
|
21914
|
+
const { top, pad } = frame(ast);
|
|
21915
|
+
const cells = [];
|
|
21916
|
+
const connectors = [];
|
|
21917
|
+
const frames = [];
|
|
21918
|
+
const gap = C2.TCHART_COL_GAP;
|
|
21919
|
+
const headGap = 10;
|
|
21920
|
+
const cardPadBottom = 12;
|
|
21921
|
+
const textLeft = 16;
|
|
21922
|
+
const colWidths = ast.columns.map((col) => {
|
|
21923
|
+
const headW = measureText(col.label, C2.HEADER_FONT) + 2 * C2.CELL_PAD_X;
|
|
21924
|
+
const itemW = Math.max(
|
|
21925
|
+
0,
|
|
21926
|
+
...col.items.map((it) => measureText(it, C2.FONT) + textLeft + 16)
|
|
21927
|
+
);
|
|
21928
|
+
return clamp(Math.max(headW, itemW, C2.COL_MIN_W), C2.COL_MIN_W, C2.COL_MAX_W);
|
|
21929
|
+
});
|
|
21930
|
+
const headerLines = ast.columns.map(
|
|
21931
|
+
(col, i) => wrapToWidth(col.label, colWidths[i] - 2 * C2.CELL_PAD_X, C2.HEADER_FONT)
|
|
21932
|
+
);
|
|
21933
|
+
const headerH = Math.max(
|
|
21934
|
+
C2.HEADER_MIN_H,
|
|
21935
|
+
...headerLines.map((l) => l.length * C2.LINE_H + 2 * C2.CELL_PAD_Y)
|
|
21936
|
+
);
|
|
21937
|
+
const colRows = ast.columns.map(
|
|
21938
|
+
(col, i) => col.items.map((it) => {
|
|
21939
|
+
const lines = wrapToWidth(it, colWidths[i] - textLeft - 14, C2.FONT);
|
|
21940
|
+
return { lines, h: Math.max(C2.ROW_MIN_H, lines.length * C2.LINE_H + 2 * C2.CELL_PAD_Y) };
|
|
21941
|
+
})
|
|
21942
|
+
);
|
|
21943
|
+
const itemsTop = top + headerH + headGap;
|
|
21944
|
+
const naturalH = colRows.map(
|
|
21945
|
+
(rows) => headerH + headGap + rows.reduce((s, r7) => s + r7.h, 0) + cardPadBottom
|
|
21946
|
+
);
|
|
21947
|
+
const cardH = Math.max(headerH + 44, ...naturalH);
|
|
21948
|
+
let x = pad;
|
|
21949
|
+
ast.columns.forEach((_col, i) => {
|
|
21950
|
+
const w = colWidths[i];
|
|
21951
|
+
frames.push({ x, y: top, w, h: cardH, rx: 12, variant: "card" });
|
|
21952
|
+
cells.push({
|
|
21953
|
+
x,
|
|
21954
|
+
y: top,
|
|
21955
|
+
w,
|
|
21956
|
+
h: headerH,
|
|
21957
|
+
lines: headerLines[i],
|
|
21958
|
+
variant: "colHeader",
|
|
21959
|
+
align: "middle",
|
|
21960
|
+
bold: true,
|
|
21961
|
+
paletteIndex: i,
|
|
21962
|
+
roundedTop: true
|
|
21963
|
+
});
|
|
21964
|
+
let cy = itemsTop;
|
|
21965
|
+
colRows[i].forEach((r7, k) => {
|
|
21966
|
+
cells.push({ x, y: cy, w, h: r7.h, lines: r7.lines, variant: "body", align: "start", bare: true });
|
|
21967
|
+
if (k < colRows[i].length - 1) {
|
|
21968
|
+
connectors.push({ x1: x + 14, y1: cy + r7.h, x2: x + w - 14, y2: cy + r7.h, light: true });
|
|
21969
|
+
}
|
|
21970
|
+
cy += r7.h;
|
|
21971
|
+
});
|
|
21972
|
+
x += w + gap;
|
|
21973
|
+
});
|
|
21974
|
+
const totalW = x - pad - gap;
|
|
21975
|
+
return {
|
|
21976
|
+
ast,
|
|
21977
|
+
mode: ast.mode,
|
|
21978
|
+
cells,
|
|
21979
|
+
ellipses: [],
|
|
21980
|
+
connectors,
|
|
21981
|
+
frames,
|
|
21982
|
+
width: Math.ceil(totalW + 2 * pad),
|
|
21983
|
+
height: Math.ceil(top + cardH + pad)
|
|
21984
|
+
};
|
|
21985
|
+
}
|
|
21986
|
+
function layoutProsCons(ast) {
|
|
21987
|
+
const { top, pad } = frame(ast);
|
|
21988
|
+
const cells = [];
|
|
21989
|
+
const connectors = [];
|
|
21990
|
+
const colW = C2.PC_COL_W;
|
|
21991
|
+
const leftX = pad;
|
|
21992
|
+
const rightX = pad + colW + C2.PC_COL_GAP;
|
|
21993
|
+
const badgeRoom = 2 * C2.PC_BADGE_R + 14;
|
|
21994
|
+
const pillH = C2.PC_PILL_H;
|
|
21995
|
+
const pill = (label, colX, kind) => {
|
|
21996
|
+
const pw = clamp(measureText(label, C2.HEADER_FONT) + badgeRoom + 30, 130, colW);
|
|
21997
|
+
cells.push({
|
|
21998
|
+
x: colX + (colW - pw) / 2,
|
|
21999
|
+
y: top,
|
|
22000
|
+
w: pw,
|
|
22001
|
+
h: pillH,
|
|
22002
|
+
lines: [label],
|
|
22003
|
+
variant: kind === "pro" ? "pillPos" : "pillNeg",
|
|
22004
|
+
align: "middle",
|
|
22005
|
+
bold: true,
|
|
22006
|
+
rx: pillH / 2,
|
|
22007
|
+
badge: { glyph: kind === "pro" ? "yes" : "no", tone: kind === "pro" ? "pos" : "neg" }
|
|
22008
|
+
});
|
|
22009
|
+
};
|
|
22010
|
+
pill("PROS", leftX, "pro");
|
|
22011
|
+
pill("CONS", rightX, "con");
|
|
22012
|
+
const itemsTop = top + pillH + 14;
|
|
22013
|
+
const itemCell = (txt, x, y, kind) => {
|
|
22014
|
+
const lines = wrapToWidth(txt, colW - badgeRoom - 14, C2.FONT);
|
|
22015
|
+
const h = Math.max(C2.PC_ROW_MIN_H, lines.length * C2.LINE_H + 2 * C2.CELL_PAD_Y);
|
|
22016
|
+
return {
|
|
22017
|
+
x,
|
|
22018
|
+
y,
|
|
22019
|
+
w: colW,
|
|
22020
|
+
h,
|
|
22021
|
+
lines,
|
|
22022
|
+
variant: kind,
|
|
22023
|
+
align: "start",
|
|
22024
|
+
bare: true,
|
|
22025
|
+
badge: { glyph: kind === "pro" ? "yes" : "no", tone: kind === "pro" ? "pos" : "neg" }
|
|
22026
|
+
};
|
|
22027
|
+
};
|
|
22028
|
+
let ly = itemsTop;
|
|
22029
|
+
for (const p of ast.pros) {
|
|
22030
|
+
const cell = itemCell(p, leftX, ly, "pro");
|
|
22031
|
+
cells.push(cell);
|
|
22032
|
+
ly += cell.h;
|
|
22033
|
+
}
|
|
22034
|
+
let ry = itemsTop;
|
|
22035
|
+
for (const c of ast.cons) {
|
|
22036
|
+
const cell = itemCell(c, rightX, ry, "con");
|
|
22037
|
+
cells.push(cell);
|
|
22038
|
+
ry += cell.h;
|
|
22039
|
+
}
|
|
22040
|
+
const bottom = Math.max(ly, ry);
|
|
22041
|
+
const dx = leftX + colW + C2.PC_COL_GAP / 2;
|
|
22042
|
+
connectors.push({ x1: dx, y1: itemsTop, x2: dx, y2: bottom - 6 });
|
|
22043
|
+
return {
|
|
22044
|
+
ast,
|
|
22045
|
+
mode: ast.mode,
|
|
22046
|
+
cells,
|
|
22047
|
+
ellipses: [],
|
|
22048
|
+
connectors,
|
|
22049
|
+
width: colW * 2 + C2.PC_COL_GAP + 2 * pad,
|
|
22050
|
+
height: Math.ceil(bottom + pad)
|
|
22051
|
+
};
|
|
22052
|
+
}
|
|
22053
|
+
function layoutGrid(ast) {
|
|
22054
|
+
const { top, pad } = frame(ast);
|
|
22055
|
+
const cells = [];
|
|
22056
|
+
const isDecision = ast.mode === "decision";
|
|
22057
|
+
const decision = isDecision ? computeDecision(ast) : void 0;
|
|
22058
|
+
const cellText = (oid, cid) => {
|
|
22059
|
+
const v = ast.criteria.find((c) => c.id === cid).cells[oid];
|
|
22060
|
+
if (!v) return { lines: [], variant: "body" };
|
|
22061
|
+
if (v.glyph) {
|
|
22062
|
+
const variant = v.glyph === "yes" ? "pos" : v.glyph === "no" ? "neg" : v.glyph === "partial" ? "warn" : "body";
|
|
22063
|
+
return { lines: v.glyph === "na" ? ["\u2014"] : [], glyph: v.glyph === "na" ? void 0 : v.glyph, variant };
|
|
22064
|
+
}
|
|
22065
|
+
if (typeof v.score === "number") return { lines: [fmt3(v.score)], variant: "body" };
|
|
22066
|
+
return { lines: v.text ? [v.text] : [], variant: "body" };
|
|
22067
|
+
};
|
|
22068
|
+
const rowHeadW = clamp(
|
|
22069
|
+
Math.max(
|
|
22070
|
+
C2.ROWHEAD_MIN_W,
|
|
22071
|
+
...ast.criteria.map((c) => measureText(c.label, C2.FONT) + 2 * C2.CELL_PAD_X + (isDecision ? 30 : 0)),
|
|
22072
|
+
measureText(isDecision ? "Weighted total" : "", C2.FONT) + 2 * C2.CELL_PAD_X
|
|
22073
|
+
),
|
|
22074
|
+
C2.ROWHEAD_MIN_W,
|
|
22075
|
+
C2.ROWHEAD_MAX_W
|
|
22076
|
+
);
|
|
22077
|
+
const optW = ast.options.map((o) => {
|
|
22078
|
+
const headW = measureText(o.label, C2.HEADER_FONT) + 2 * C2.CELL_PAD_X;
|
|
22079
|
+
const bodyW = Math.max(
|
|
22080
|
+
0,
|
|
22081
|
+
...ast.criteria.map((c) => {
|
|
22082
|
+
const ct = cellText(o.id, c.id);
|
|
22083
|
+
return Math.max(0, ...ct.lines.map((l) => measureText(l, C2.FONT))) + 2 * C2.CELL_PAD_X;
|
|
22084
|
+
})
|
|
22085
|
+
);
|
|
22086
|
+
return clamp(Math.max(headW, bodyW, C2.MARK_COL_MIN_W), C2.MARK_COL_MIN_W, C2.MARK_COL_MAX_W);
|
|
22087
|
+
});
|
|
22088
|
+
const headLines = ast.options.map(
|
|
22089
|
+
(o, i) => wrapToWidth(o.label, optW[i] - 2 * C2.CELL_PAD_X, C2.HEADER_FONT)
|
|
22090
|
+
);
|
|
22091
|
+
const headerH = Math.max(C2.HEADER_MIN_H, ...headLines.map((l) => l.length * C2.LINE_H + 2 * C2.CELL_PAD_Y));
|
|
22092
|
+
cells.push({
|
|
22093
|
+
x: pad,
|
|
22094
|
+
y: top,
|
|
22095
|
+
w: rowHeadW,
|
|
22096
|
+
h: headerH,
|
|
22097
|
+
lines: ast.title ? [] : [],
|
|
22098
|
+
variant: "corner",
|
|
22099
|
+
align: "start"
|
|
22100
|
+
});
|
|
22101
|
+
let hx = pad + rowHeadW;
|
|
22102
|
+
const colX = [];
|
|
22103
|
+
ast.options.forEach((o, i) => {
|
|
22104
|
+
colX.push(hx);
|
|
22105
|
+
const isBase = isDecision && ast.baseline && (o.label === ast.baseline || o.id === ast.baseline);
|
|
22106
|
+
cells.push({
|
|
22107
|
+
x: hx,
|
|
22108
|
+
y: top,
|
|
22109
|
+
w: optW[i],
|
|
22110
|
+
h: headerH,
|
|
22111
|
+
lines: headLines[i],
|
|
22112
|
+
variant: isBase ? "baseline" : "colHeader",
|
|
22113
|
+
align: "middle",
|
|
22114
|
+
bold: true,
|
|
22115
|
+
tag: isBase ? "datum" : void 0
|
|
22116
|
+
});
|
|
22117
|
+
hx += optW[i];
|
|
22118
|
+
});
|
|
22119
|
+
const gridW = rowHeadW + optW.reduce((a, b) => a + b, 0);
|
|
22120
|
+
let ry = top + headerH;
|
|
22121
|
+
for (const crit of ast.criteria) {
|
|
22122
|
+
const labelLines = wrapToWidth(crit.label, rowHeadW - 2 * C2.CELL_PAD_X - (isDecision ? 26 : 0), C2.FONT);
|
|
22123
|
+
const bodyLineCounts = ast.options.map((o) => {
|
|
22124
|
+
const ct = cellText(o.id, crit.id);
|
|
22125
|
+
const wrapped = ct.lines.flatMap(
|
|
22126
|
+
(l, idx) => idx === 0 ? wrapToWidth(l, optW[ast.options.indexOf(o)] - 2 * C2.CELL_PAD_X, C2.FONT) : [l]
|
|
22127
|
+
);
|
|
22128
|
+
return wrapped.length;
|
|
22129
|
+
});
|
|
22130
|
+
const rowH = Math.max(
|
|
22131
|
+
C2.ROW_MIN_H,
|
|
22132
|
+
labelLines.length * C2.LINE_H + 2 * C2.CELL_PAD_Y,
|
|
22133
|
+
...bodyLineCounts.map((n) => n * C2.LINE_H + 2 * C2.CELL_PAD_Y)
|
|
22134
|
+
);
|
|
22135
|
+
cells.push({
|
|
22136
|
+
x: pad,
|
|
22137
|
+
y: ry,
|
|
22138
|
+
w: rowHeadW,
|
|
22139
|
+
h: rowH,
|
|
22140
|
+
lines: labelLines,
|
|
22141
|
+
variant: "rowHeader",
|
|
22142
|
+
align: "start",
|
|
22143
|
+
tag: isDecision ? `\xD7${fmt3(crit.weight ?? 1)}` : void 0
|
|
22144
|
+
});
|
|
22145
|
+
ast.options.forEach((o, i) => {
|
|
22146
|
+
const ct = cellText(o.id, crit.id);
|
|
22147
|
+
const wrapped = ct.lines.length ? wrapToWidth(ct.lines[0], optW[i] - 2 * C2.CELL_PAD_X, C2.FONT) : [];
|
|
22148
|
+
cells.push({
|
|
22149
|
+
x: colX[i],
|
|
22150
|
+
y: ry,
|
|
22151
|
+
w: optW[i],
|
|
22152
|
+
h: rowH,
|
|
22153
|
+
lines: wrapped,
|
|
22154
|
+
variant: ct.variant,
|
|
22155
|
+
glyph: ct.glyph,
|
|
22156
|
+
align: "middle"
|
|
22157
|
+
});
|
|
22158
|
+
});
|
|
22159
|
+
ry += rowH;
|
|
22160
|
+
}
|
|
22161
|
+
let caption;
|
|
22162
|
+
if (isDecision && decision) {
|
|
22163
|
+
const totalH = C2.ROW_MIN_H;
|
|
22164
|
+
cells.push({
|
|
22165
|
+
x: pad,
|
|
22166
|
+
y: ry,
|
|
22167
|
+
w: rowHeadW,
|
|
22168
|
+
h: totalH,
|
|
22169
|
+
lines: ["Weighted total"],
|
|
22170
|
+
variant: "rowHeader",
|
|
22171
|
+
align: "start",
|
|
22172
|
+
bold: true
|
|
22173
|
+
});
|
|
22174
|
+
ast.options.forEach((o, i) => {
|
|
22175
|
+
const isWin = decision.ranks[o.id] === 1;
|
|
22176
|
+
cells.push({
|
|
22177
|
+
x: colX[i],
|
|
22178
|
+
y: ry,
|
|
22179
|
+
w: optW[i],
|
|
22180
|
+
h: totalH,
|
|
22181
|
+
lines: [fmt3(decision.totals[o.id])],
|
|
22182
|
+
variant: isWin ? "winner" : "total",
|
|
22183
|
+
align: "middle",
|
|
22184
|
+
bold: true,
|
|
22185
|
+
tag: `#${decision.ranks[o.id]}`
|
|
22186
|
+
});
|
|
22187
|
+
});
|
|
22188
|
+
ry += totalH;
|
|
22189
|
+
if (decision.deltas) {
|
|
22190
|
+
const dH = C2.ROW_MIN_H;
|
|
22191
|
+
cells.push({
|
|
22192
|
+
x: pad,
|
|
22193
|
+
y: ry,
|
|
22194
|
+
w: rowHeadW,
|
|
22195
|
+
h: dH,
|
|
22196
|
+
lines: ["vs datum"],
|
|
22197
|
+
variant: "rowHeader",
|
|
22198
|
+
align: "start"
|
|
22199
|
+
});
|
|
22200
|
+
ast.options.forEach((o, i) => {
|
|
22201
|
+
const d = decision.deltas[o.id];
|
|
22202
|
+
const s = d > 0 ? `+${fmt3(d)}` : fmt3(d);
|
|
22203
|
+
cells.push({
|
|
22204
|
+
x: colX[i],
|
|
22205
|
+
y: ry,
|
|
22206
|
+
w: optW[i],
|
|
22207
|
+
h: dH,
|
|
22208
|
+
lines: [s],
|
|
22209
|
+
variant: d > 0 ? "pos" : d < 0 ? "neg" : "body",
|
|
22210
|
+
align: "middle"
|
|
22211
|
+
});
|
|
22212
|
+
});
|
|
22213
|
+
ry += dH;
|
|
22214
|
+
}
|
|
22215
|
+
caption = decisionCaption(ast, decision);
|
|
22216
|
+
}
|
|
22217
|
+
const captionH = caption ? C2.CAPTION_H : 0;
|
|
22218
|
+
const result = {
|
|
22219
|
+
ast,
|
|
22220
|
+
mode: ast.mode,
|
|
22221
|
+
cells,
|
|
22222
|
+
ellipses: [],
|
|
22223
|
+
connectors: [],
|
|
22224
|
+
width: gridW + 2 * pad,
|
|
22225
|
+
height: ry + captionH + pad
|
|
22226
|
+
};
|
|
22227
|
+
if (decision) result.decision = decision;
|
|
22228
|
+
if (caption) result.caption = caption;
|
|
22229
|
+
return result;
|
|
22230
|
+
}
|
|
22231
|
+
function layoutDoubleBubble(ast) {
|
|
22232
|
+
const { top, pad } = frame(ast);
|
|
22233
|
+
const b = ast.bubble;
|
|
22234
|
+
const rawE = [];
|
|
22235
|
+
const rawC = [];
|
|
22236
|
+
const dxCS = C2.CENTER_RX + 72 + C2.SHARED_RX;
|
|
22237
|
+
const lcx = -dxCS;
|
|
22238
|
+
const rcx = dxCS;
|
|
22239
|
+
rawE.push({ cx: lcx, cy: 0, rx: C2.CENTER_RX, ry: C2.CENTER_RY, lines: wrapToWidth(b.left, C2.CENTER_RX * 1.4, C2.HEADER_FONT), variant: "center", side: "left" });
|
|
22240
|
+
rawE.push({ cx: rcx, cy: 0, rx: C2.CENTER_RX, ry: C2.CENTER_RY, lines: wrapToWidth(b.right, C2.CENTER_RX * 1.4, C2.HEADER_FONT), variant: "center", side: "right" });
|
|
22241
|
+
const sN = b.shared.length;
|
|
22242
|
+
const sStep = 2 * C2.SHARED_RY + C2.BUBBLE_VGAP;
|
|
22243
|
+
const sTotal = sN > 0 ? (sN - 1) * sStep : 0;
|
|
22244
|
+
b.shared.forEach((s, i) => {
|
|
22245
|
+
const sy = -sTotal / 2 + i * sStep;
|
|
22246
|
+
rawE.push({ cx: 0, cy: sy, rx: C2.SHARED_RX, ry: C2.SHARED_RY, lines: wrapToWidth(s, C2.SHARED_RX * 1.6, C2.FONT), variant: "shared" });
|
|
22247
|
+
rawC.push({ x1: lcx, y1: 0, x2: 0, y2: sy });
|
|
22248
|
+
rawC.push({ x1: rcx, y1: 0, x2: 0, y2: sy });
|
|
22249
|
+
});
|
|
22250
|
+
const placeFan = (items, cx, centreDeg, side) => {
|
|
22251
|
+
const n = items.length;
|
|
22252
|
+
if (n === 0) return;
|
|
22253
|
+
const half = Math.min(82, 30 + 17 * (n - 1));
|
|
22254
|
+
const stepDeg = n > 1 ? 2 * half / (n - 1) : 0;
|
|
22255
|
+
const stepRad = stepDeg * Math.PI / 180;
|
|
22256
|
+
const needChord = 2 * C2.UNIQUE_RY + 18;
|
|
22257
|
+
const rOrbit = Math.max(
|
|
22258
|
+
C2.CENTER_RX + 104,
|
|
22259
|
+
n > 1 ? needChord / (2 * Math.sin(stepRad / 2)) : C2.CENTER_RX + 104
|
|
22260
|
+
);
|
|
22261
|
+
items.forEach((it, i) => {
|
|
22262
|
+
const aDeg = n > 1 ? centreDeg - half + stepDeg * i : centreDeg;
|
|
22263
|
+
const a = aDeg * Math.PI / 180;
|
|
22264
|
+
const bx = cx + rOrbit * Math.cos(a);
|
|
22265
|
+
const by = rOrbit * Math.sin(a);
|
|
22266
|
+
rawE.push({ cx: bx, cy: by, rx: C2.UNIQUE_RX, ry: C2.UNIQUE_RY, lines: wrapToWidth(it, C2.UNIQUE_RX * 1.5, C2.FONT), variant: "unique", side });
|
|
22267
|
+
rawC.push({ x1: cx, y1: 0, x2: bx, y2: by });
|
|
22268
|
+
});
|
|
22269
|
+
};
|
|
22270
|
+
placeFan(b.leftOnly, lcx, 180, "left");
|
|
22271
|
+
placeFan(b.rightOnly, rcx, 0, "right");
|
|
22272
|
+
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
22273
|
+
for (const e of rawE) {
|
|
22274
|
+
minX = Math.min(minX, e.cx - e.rx);
|
|
22275
|
+
maxX = Math.max(maxX, e.cx + e.rx);
|
|
22276
|
+
minY = Math.min(minY, e.cy - e.ry);
|
|
22277
|
+
maxY = Math.max(maxY, e.cy + e.ry);
|
|
22278
|
+
}
|
|
22279
|
+
const offX = pad - minX;
|
|
22280
|
+
const offY = top - minY;
|
|
22281
|
+
const ellipses = rawE.map((e) => ({
|
|
22282
|
+
cx: round8(e.cx + offX),
|
|
22283
|
+
cy: round8(e.cy + offY),
|
|
22284
|
+
rx: e.rx,
|
|
22285
|
+
ry: e.ry,
|
|
22286
|
+
lines: e.lines,
|
|
22287
|
+
variant: e.variant,
|
|
22288
|
+
...e.side ? { side: e.side } : {}
|
|
22289
|
+
}));
|
|
22290
|
+
const connectors = rawC.map((c) => ({
|
|
22291
|
+
x1: round8(c.x1 + offX),
|
|
22292
|
+
y1: round8(c.y1 + offY),
|
|
22293
|
+
x2: round8(c.x2 + offX),
|
|
22294
|
+
y2: round8(c.y2 + offY)
|
|
22295
|
+
}));
|
|
22296
|
+
return {
|
|
22297
|
+
ast,
|
|
22298
|
+
mode: ast.mode,
|
|
22299
|
+
cells: [],
|
|
22300
|
+
ellipses,
|
|
22301
|
+
connectors,
|
|
22302
|
+
width: Math.ceil(maxX - minX + 2 * pad),
|
|
22303
|
+
height: Math.ceil(maxY - minY + top + pad)
|
|
22304
|
+
};
|
|
22305
|
+
}
|
|
22306
|
+
function clamp(v, lo, hi) {
|
|
22307
|
+
return Math.max(lo, Math.min(hi, v));
|
|
22308
|
+
}
|
|
22309
|
+
function round8(n) {
|
|
22310
|
+
return Math.round(n * 10) / 10;
|
|
22311
|
+
}
|
|
22312
|
+
|
|
22313
|
+
// src/diagrams/comparison/renderer.ts
|
|
22314
|
+
function ellipse(attrs) {
|
|
22315
|
+
return el("ellipse", attrs);
|
|
22316
|
+
}
|
|
22317
|
+
function renderComparison(text2, config) {
|
|
22318
|
+
return renderComparisonLayout(layoutComparison(parseComparison(text2)), config);
|
|
22319
|
+
}
|
|
22320
|
+
function renderComparisonLayout(layout, config) {
|
|
22321
|
+
const themeName = config?.theme ?? "default";
|
|
22322
|
+
const t = resolveComparisonTheme(themeName);
|
|
22323
|
+
const fontFamily = config?.fontFamily ?? DEFAULT_FONT_FAMILY;
|
|
22324
|
+
const pad = config?.padding ?? 0;
|
|
22325
|
+
const { ast } = layout;
|
|
22326
|
+
const width = layout.width + pad * 2;
|
|
22327
|
+
const height = layout.height + pad * 2;
|
|
22328
|
+
const a11y = ast.title ?? `Comparison (${ast.mode})`;
|
|
22329
|
+
const style = el(
|
|
22330
|
+
"style",
|
|
22331
|
+
{},
|
|
22332
|
+
`
|
|
22333
|
+
.sx-cmp-bg { fill: ${t.bg}; }
|
|
22334
|
+
.sx-cmp-title { fill: ${t.text}; font-size: ${TITLE.size}px; font-weight: ${TITLE.weight}; }
|
|
22335
|
+
.sx-cmp-caption { fill: ${t.captionText}; font-size: ${FONT_SIZE.label}px; font-style: italic; }
|
|
22336
|
+
.sx-cmp-tag { fill: ${t.tagText}; font-size: ${FONT_SIZE.small}px; }
|
|
22337
|
+
.sx-cmp-rect { stroke: ${t.gridStroke}; stroke-width: ${STROKE_WIDTH.thin}; }
|
|
22338
|
+
.sx-cmp-txt { font-size: ${FONT_SIZE.label}px; }
|
|
22339
|
+
.sx-cmp-rect-corner { fill: ${t.rowHeaderFill}; stroke: ${t.gridStroke}; }
|
|
22340
|
+
.sx-cmp-rect-colHeader { fill: ${t.headerFill}; stroke: ${t.headerStroke}; }
|
|
22341
|
+
.sx-cmp-txt-colHeader { fill: ${t.headerText}; font-size: ${FONT_SIZE.label}px; font-weight: 700; }
|
|
22342
|
+
${t.columnColors.map((c, i) => `.sx-cmp-ch-${i} { fill: ${c}; stroke: none; }`).join("\n")}
|
|
22343
|
+
.sx-cmp-cht { fill: ${t.columnText}; font-size: ${FONT_SIZE.label}px; font-weight: 700; }
|
|
22344
|
+
.sx-cmp-nostroke { stroke: none; }
|
|
22345
|
+
.sx-cmp-rect-baseline { fill: ${t.baselineFill}; stroke: ${t.gridStroke}; }
|
|
22346
|
+
.sx-cmp-txt-baseline { fill: ${t.cellText}; font-weight: 700; }
|
|
22347
|
+
.sx-cmp-rect-rowHeader { fill: ${t.rowHeaderFill}; stroke: ${t.gridStroke}; }
|
|
22348
|
+
.sx-cmp-txt-rowHeader { fill: ${t.cellText}; font-weight: 600; }
|
|
22349
|
+
.sx-cmp-rect-body { fill: ${t.cellFill}; stroke: ${t.gridStroke}; }
|
|
22350
|
+
.sx-cmp-rect-body-z { fill: ${t.cellAltFill}; stroke: ${t.gridStroke}; }
|
|
22351
|
+
.sx-cmp-txt-body { fill: ${t.cellText}; }
|
|
22352
|
+
.sx-cmp-bullet { fill: ${t.headerFill}; }
|
|
22353
|
+
.sx-cmp-rect-pos { fill: ${t.posFill}; stroke: ${t.gridStroke}; }
|
|
22354
|
+
.sx-cmp-txt-pos { fill: ${t.posText}; font-weight: 600; }
|
|
22355
|
+
.sx-cmp-rect-neg { fill: ${t.negFill}; stroke: ${t.gridStroke}; }
|
|
22356
|
+
.sx-cmp-txt-neg { fill: ${t.negText}; font-weight: 600; }
|
|
22357
|
+
.sx-cmp-rect-warn { fill: ${t.warnFill}; stroke: ${t.gridStroke}; }
|
|
22358
|
+
.sx-cmp-txt-warn { fill: ${t.warnText}; font-weight: 600; }
|
|
22359
|
+
.sx-cmp-txt-pro { fill: ${t.cellText}; }
|
|
22360
|
+
.sx-cmp-txt-con { fill: ${t.cellText}; }
|
|
22361
|
+
.sx-cmp-rect-pillPos { fill: ${t.pillPosFill}; stroke: none; }
|
|
22362
|
+
.sx-cmp-rect-pillNeg { fill: ${t.pillNegFill}; stroke: none; }
|
|
22363
|
+
.sx-cmp-txt-pillPos, .sx-cmp-txt-pillNeg { fill: ${t.pillText}; font-weight: 700; letter-spacing: 0.5px; }
|
|
22364
|
+
.sx-cmp-badge-pos { fill: ${t.pillPosFill}; }
|
|
22365
|
+
.sx-cmp-badge-neg { fill: ${t.pillNegFill}; }
|
|
22366
|
+
.sx-cmp-badge-glyph { fill: ${t.badgeText}; font-size: 13px; font-weight: 700; }
|
|
22367
|
+
.sx-cmp-rect-total { fill: ${t.totalFill}; stroke: ${t.gridStroke}; }
|
|
22368
|
+
.sx-cmp-txt-total { fill: ${t.cellText}; font-weight: 700; }
|
|
22369
|
+
.sx-cmp-rect-winner { fill: ${t.winnerFill}; stroke: ${t.winnerStroke}; stroke-width: ${STROKE_WIDTH.thick}; }
|
|
22370
|
+
.sx-cmp-txt-winner { fill: ${t.winnerText}; font-weight: 700; }
|
|
22371
|
+
.sx-cmp-glyph { font-size: 15px; font-weight: 700; }
|
|
22372
|
+
.sx-cmp-card { fill: ${t.cardFill}; stroke: ${t.cardStroke}; stroke-width: ${STROKE_WIDTH.thin}; }
|
|
22373
|
+
.sx-cmp-conn { fill: none; stroke: ${t.connectorStroke}; stroke-width: ${STROKE_WIDTH.normal}; }
|
|
22374
|
+
.sx-cmp-conn-light { fill: none; stroke: ${t.rowDivider}; stroke-width: ${STROKE_WIDTH.thin}; }
|
|
22375
|
+
.sx-cmp-ell { stroke: ${t.dbStroke}; stroke-width: ${STROKE_WIDTH.normal}; }
|
|
22376
|
+
.sx-cmp-ell-center-left { fill: ${t.dbLeftCenterFill}; }
|
|
22377
|
+
.sx-cmp-ell-center-right { fill: ${t.dbRightCenterFill}; }
|
|
22378
|
+
.sx-cmp-ell-shared { fill: ${t.dbSharedFill}; }
|
|
22379
|
+
.sx-cmp-ell-unique-left { fill: ${t.dbLeftFill}; }
|
|
22380
|
+
.sx-cmp-ell-unique-right { fill: ${t.dbRightFill}; }
|
|
22381
|
+
.sx-cmp-ltxt-center-left { fill: ${t.dbLeftCenterText}; font-size: ${FONT_SIZE.label}px; font-weight: 700; }
|
|
22382
|
+
.sx-cmp-ltxt-center-right { fill: ${t.dbRightCenterText}; font-size: ${FONT_SIZE.label}px; font-weight: 700; }
|
|
22383
|
+
.sx-cmp-ltxt-shared { fill: ${t.dbSharedText}; font-size: ${FONT_SIZE.label}px; font-weight: 600; }
|
|
22384
|
+
.sx-cmp-ltxt-unique-left { fill: ${t.dbLeftText}; font-size: ${FONT_SIZE.small}px; }
|
|
22385
|
+
.sx-cmp-ltxt-unique-right { fill: ${t.dbRightText}; font-size: ${FONT_SIZE.small}px; }
|
|
22386
|
+
`.trim()
|
|
22387
|
+
);
|
|
22388
|
+
const children = [
|
|
22389
|
+
title(a11y),
|
|
22390
|
+
desc(summarise7(layout)),
|
|
22391
|
+
style,
|
|
22392
|
+
rect({ x: 0, y: 0, width, height, class: "sx-cmp-bg" })
|
|
22393
|
+
];
|
|
22394
|
+
const inner = [];
|
|
22395
|
+
if (ast.title) {
|
|
22396
|
+
inner.push(
|
|
22397
|
+
text(
|
|
22398
|
+
{ x: layout.width / 2, y: TITLE.y, class: "sx-cmp-title", "font-family": fontFamily, "text-anchor": "middle" },
|
|
22399
|
+
ast.title
|
|
22400
|
+
)
|
|
22401
|
+
);
|
|
22402
|
+
}
|
|
22403
|
+
for (const f of layout.frames ?? []) {
|
|
22404
|
+
inner.push(rect({ x: f.x, y: f.y, width: f.w, height: f.h, rx: f.rx, class: "sx-cmp-card" }));
|
|
22405
|
+
}
|
|
22406
|
+
for (const c of layout.connectors) {
|
|
22407
|
+
inner.push(line({ x1: c.x1, y1: c.y1, x2: c.x2, y2: c.y2, class: c.light ? "sx-cmp-conn-light" : "sx-cmp-conn" }));
|
|
22408
|
+
}
|
|
22409
|
+
const colN = t.columnColors.length;
|
|
22410
|
+
for (const cell of layout.cells) {
|
|
22411
|
+
inner.push(renderCell(cell, fontFamily, colN));
|
|
22412
|
+
}
|
|
22413
|
+
for (const e of layout.ellipses) {
|
|
22414
|
+
const key = e.variant === "center" || e.variant === "unique" ? `${e.variant}-${e.side ?? "left"}` : e.variant;
|
|
22415
|
+
const cls = `sx-cmp-ell sx-cmp-ell-${key}`;
|
|
22416
|
+
const txtCls = `sx-cmp-ltxt-${key}`;
|
|
22417
|
+
inner.push(
|
|
22418
|
+
group({ class: "sx-cmp-bubble", "data-role": e.variant, ...e.side ? { "data-side": e.side } : {} }, [
|
|
22419
|
+
ellipse({ cx: e.cx, cy: e.cy, rx: e.rx, ry: e.ry, class: cls }),
|
|
22420
|
+
multilineText(
|
|
22421
|
+
{ x: e.cx, y: e.cy, class: txtCls, "font-family": fontFamily, "text-anchor": "middle", "dominant-baseline": "middle" },
|
|
22422
|
+
e.lines.join("<br/>"),
|
|
22423
|
+
C_LINE_H
|
|
22424
|
+
)
|
|
22425
|
+
])
|
|
22426
|
+
);
|
|
22427
|
+
}
|
|
22428
|
+
if (layout.caption) {
|
|
22429
|
+
inner.push(
|
|
22430
|
+
text(
|
|
22431
|
+
{ x: layout.width / 2, y: layout.height - 12, class: "sx-cmp-caption", "font-family": fontFamily, "text-anchor": "middle" },
|
|
22432
|
+
layout.caption
|
|
22433
|
+
)
|
|
22434
|
+
);
|
|
22435
|
+
}
|
|
22436
|
+
children.push(
|
|
22437
|
+
group({ transform: pad ? `translate(${pad}, ${pad})` : void 0, "font-family": fontFamily }, inner)
|
|
22438
|
+
);
|
|
22439
|
+
return svgRoot(
|
|
22440
|
+
{
|
|
22441
|
+
width,
|
|
22442
|
+
height,
|
|
22443
|
+
viewBox: `0 0 ${width} ${height}`,
|
|
22444
|
+
role: "img",
|
|
22445
|
+
"aria-label": a11y,
|
|
22446
|
+
"data-diagram-type": "comparison",
|
|
22447
|
+
"data-mode": ast.mode
|
|
22448
|
+
},
|
|
22449
|
+
children
|
|
22450
|
+
);
|
|
22451
|
+
}
|
|
22452
|
+
var C_LINE_H = 14;
|
|
22453
|
+
function renderCell(cell, fontFamily, colN) {
|
|
22454
|
+
const parts = [];
|
|
22455
|
+
const colHeaderClass = cell.variant === "colHeader" && cell.paletteIndex !== void 0 ? `sx-cmp-ch-${cell.paletteIndex % Math.max(1, colN)}` : void 0;
|
|
22456
|
+
if (!cell.bare) {
|
|
22457
|
+
if (cell.roundedTop) {
|
|
22458
|
+
parts.push(
|
|
22459
|
+
path({
|
|
22460
|
+
d: roundedTopRectPath(cell.x, cell.y, cell.w, cell.h, cell.rx ?? 12),
|
|
22461
|
+
class: colHeaderClass ?? "sx-cmp-rect-colHeader"
|
|
22462
|
+
})
|
|
22463
|
+
);
|
|
22464
|
+
} else {
|
|
22465
|
+
const rectVariant = cell.zebra && cell.variant === "body" ? "body-z" : cell.variant;
|
|
22466
|
+
const rectClass = colHeaderClass ? `sx-cmp-rect ${colHeaderClass}` : `sx-cmp-rect sx-cmp-rect-${rectVariant}${cell.noStroke ? " sx-cmp-nostroke" : ""}`;
|
|
22467
|
+
parts.push(
|
|
22468
|
+
rect({ x: cell.x, y: cell.y, width: cell.w, height: cell.h, rx: cell.rx, class: rectClass })
|
|
22469
|
+
);
|
|
22470
|
+
}
|
|
22471
|
+
}
|
|
22472
|
+
const txtClass = colHeaderClass ? "sx-cmp-txt sx-cmp-cht" : `sx-cmp-txt sx-cmp-txt-${cell.variant}`;
|
|
22473
|
+
const cy = cell.y + cell.h / 2;
|
|
22474
|
+
const br = 11;
|
|
22475
|
+
const drawBadge = (bcx) => {
|
|
22476
|
+
parts.push(circle({ cx: bcx, cy, r: br, class: `sx-cmp-badge-${cell.badge.tone}` }));
|
|
22477
|
+
parts.push(
|
|
22478
|
+
text(
|
|
22479
|
+
{ x: bcx, y: cy + 0.5, class: "sx-cmp-badge-glyph", "font-family": fontFamily, "text-anchor": "middle", "dominant-baseline": "middle" },
|
|
22480
|
+
cell.badge.glyph === "yes" ? "\u2713" : "\u2717"
|
|
22481
|
+
)
|
|
22482
|
+
);
|
|
22483
|
+
};
|
|
22484
|
+
if (cell.align === "start") {
|
|
22485
|
+
let tx = cell.x + 12;
|
|
22486
|
+
if (cell.badge) {
|
|
22487
|
+
const bcx = cell.x + 12 + br;
|
|
22488
|
+
drawBadge(bcx);
|
|
22489
|
+
tx = bcx + br + 10;
|
|
22490
|
+
} else if (cell.tag === "\u2022") {
|
|
22491
|
+
parts.push(circle({ cx: cell.x + 14, cy, r: 2.6, class: "sx-cmp-bullet" }));
|
|
22492
|
+
tx = cell.x + 24;
|
|
22493
|
+
}
|
|
22494
|
+
if (cell.lines.length) {
|
|
22495
|
+
parts.push(
|
|
22496
|
+
multilineText(
|
|
22497
|
+
{ x: tx, y: cy, class: txtClass, "font-family": fontFamily, "dominant-baseline": "middle" },
|
|
22498
|
+
cell.lines.join("<br/>"),
|
|
22499
|
+
C_LINE_H
|
|
22500
|
+
)
|
|
22501
|
+
);
|
|
22502
|
+
}
|
|
22503
|
+
} else if (cell.badge) {
|
|
22504
|
+
const bcx = cell.x + 18 + br;
|
|
22505
|
+
drawBadge(bcx);
|
|
22506
|
+
const labelCx = (bcx + br + 6 + (cell.x + cell.w - 12)) / 2;
|
|
22507
|
+
parts.push(
|
|
22508
|
+
multilineText(
|
|
22509
|
+
{ x: labelCx, y: cy, class: txtClass, "font-family": fontFamily, "text-anchor": "middle", "dominant-baseline": "middle" },
|
|
22510
|
+
cell.lines.join("<br/>"),
|
|
22511
|
+
C_LINE_H
|
|
22512
|
+
)
|
|
22513
|
+
);
|
|
22514
|
+
} else if (cell.glyph && cell.lines.length === 0) {
|
|
22515
|
+
parts.push(
|
|
22516
|
+
text(
|
|
22517
|
+
{ x: cell.x + cell.w / 2, y: cy, class: `sx-cmp-glyph ${glyphTextClass(cell.glyph)}`, "font-family": fontFamily, "text-anchor": "middle", "dominant-baseline": "middle" },
|
|
22518
|
+
glyphChar(cell.glyph)
|
|
22519
|
+
)
|
|
22520
|
+
);
|
|
22521
|
+
} else if (cell.lines.length) {
|
|
22522
|
+
parts.push(
|
|
22523
|
+
multilineText(
|
|
22524
|
+
{ x: cell.x + cell.w / 2, y: cy, class: txtClass, "font-family": fontFamily, "text-anchor": "middle", "dominant-baseline": "middle" },
|
|
22525
|
+
cell.lines.join("<br/>"),
|
|
22526
|
+
C_LINE_H
|
|
22527
|
+
)
|
|
22528
|
+
);
|
|
22529
|
+
}
|
|
22530
|
+
if (cell.tag && cell.tag !== "\u2022") {
|
|
22531
|
+
if (cell.variant === "baseline") {
|
|
22532
|
+
parts.push(
|
|
22533
|
+
text(
|
|
22534
|
+
{ x: cell.x + cell.w / 2, y: cell.y + cell.h - 5, class: "sx-cmp-tag", "font-family": fontFamily, "text-anchor": "middle" },
|
|
22535
|
+
cell.tag
|
|
22536
|
+
)
|
|
22537
|
+
);
|
|
22538
|
+
} else {
|
|
22539
|
+
parts.push(
|
|
22540
|
+
text(
|
|
22541
|
+
{ x: cell.x + cell.w - 5, y: cell.y + 13, class: "sx-cmp-tag", "font-family": fontFamily, "text-anchor": "end" },
|
|
22542
|
+
cell.tag
|
|
22543
|
+
)
|
|
22544
|
+
);
|
|
22545
|
+
}
|
|
22546
|
+
}
|
|
22547
|
+
const attrs = { class: "sx-cmp-cell-g", "data-variant": cell.variant };
|
|
22548
|
+
if (cell.glyph) attrs["data-glyph"] = cell.glyph;
|
|
22549
|
+
return group(attrs, parts);
|
|
22550
|
+
}
|
|
22551
|
+
function roundedTopRectPath(x, y, w, h, r7) {
|
|
22552
|
+
const rr = Math.max(0, Math.min(r7, w / 2, h));
|
|
22553
|
+
return `M ${x} ${y + h} L ${x} ${y + rr} Q ${x} ${y} ${x + rr} ${y} L ${x + w - rr} ${y} Q ${x + w} ${y} ${x + w} ${y + rr} L ${x + w} ${y + h} Z`;
|
|
22554
|
+
}
|
|
22555
|
+
function glyphChar(g) {
|
|
22556
|
+
return g === "yes" ? "\u2713" : g === "no" ? "\u2717" : g === "partial" ? "~" : "\u2014";
|
|
22557
|
+
}
|
|
22558
|
+
function glyphTextClass(g) {
|
|
22559
|
+
return g === "yes" ? "sx-cmp-txt-pos" : g === "no" ? "sx-cmp-txt-neg" : g === "partial" ? "sx-cmp-txt-warn" : "sx-cmp-txt-body";
|
|
22560
|
+
}
|
|
22561
|
+
function summarise7(layout) {
|
|
22562
|
+
const { ast } = layout;
|
|
22563
|
+
const parts = [];
|
|
22564
|
+
switch (ast.mode) {
|
|
22565
|
+
case "tchart":
|
|
22566
|
+
parts.push(`T-chart comparing ${ast.columns.length} column${plural2(ast.columns.length)}: ${ast.columns.map((c) => `"${c.label}"`).join(", ")}.`);
|
|
22567
|
+
break;
|
|
22568
|
+
case "pros-cons":
|
|
22569
|
+
parts.push(`Pros/cons${ast.subject ? ` for "${ast.subject}"` : ""}: ${ast.pros.length} pro${plural2(ast.pros.length)}, ${ast.cons.length} con${plural2(ast.cons.length)}.`);
|
|
22570
|
+
break;
|
|
22571
|
+
case "matrix":
|
|
22572
|
+
parts.push(`Comparison matrix: ${ast.options.length} option${plural2(ast.options.length)} \xD7 ${ast.criteria.length} criteria.`);
|
|
22573
|
+
break;
|
|
22574
|
+
case "decision":
|
|
22575
|
+
parts.push(`Decision matrix: ${ast.options.length} option${plural2(ast.options.length)} \xD7 ${ast.criteria.length} weighted criteria.`);
|
|
22576
|
+
if (layout.caption) parts.push(layout.caption);
|
|
22577
|
+
break;
|
|
22578
|
+
case "double-bubble":
|
|
22579
|
+
parts.push(`Double-bubble comparing "${ast.bubble?.left}" and "${ast.bubble?.right}": ${ast.bubble?.shared.length ?? 0} shared, ${ast.bubble?.leftOnly.length ?? 0}/${ast.bubble?.rightOnly.length ?? 0} unique.`);
|
|
22580
|
+
break;
|
|
22581
|
+
}
|
|
22582
|
+
for (const w of ast.warnings) parts.push(w);
|
|
22583
|
+
return parts.join(" ");
|
|
22584
|
+
}
|
|
22585
|
+
function plural2(n) {
|
|
22586
|
+
return n === 1 ? "" : "s";
|
|
22587
|
+
}
|
|
22588
|
+
|
|
22589
|
+
// src/diagrams/comparison/index.ts
|
|
22590
|
+
var comparison = {
|
|
22591
|
+
type: "comparison",
|
|
22592
|
+
detect(text2) {
|
|
22593
|
+
return /^\s*(comparison|compare|vs|tchart|t-chart|pugh|decision-matrix|decisionmatrix)\b/i.test(text2);
|
|
22594
|
+
},
|
|
22595
|
+
parse: parseComparison,
|
|
22596
|
+
render(text2, config) {
|
|
22597
|
+
return renderComparison(text2, config);
|
|
22598
|
+
}
|
|
22599
|
+
};
|
|
22600
|
+
|
|
21293
22601
|
// src/diagrams/causalloop/parser.ts
|
|
21294
22602
|
var CausalLoopParseError = class extends Error {
|
|
21295
22603
|
constructor(message, line2) {
|
|
@@ -21312,7 +22620,7 @@ function parseCausalLoop(text2) {
|
|
|
21312
22620
|
let i = 0;
|
|
21313
22621
|
let headerSeen = false;
|
|
21314
22622
|
for (; i < lines.length; i++) {
|
|
21315
|
-
const t =
|
|
22623
|
+
const t = stripComment9(lines[i] ?? "").trim();
|
|
21316
22624
|
if (t === "") continue;
|
|
21317
22625
|
const h = /^(causalloop|cld)\b(.*)$/i.exec(t);
|
|
21318
22626
|
if (h) {
|
|
@@ -21333,7 +22641,7 @@ function parseCausalLoop(text2) {
|
|
|
21333
22641
|
);
|
|
21334
22642
|
}
|
|
21335
22643
|
for (; i < lines.length; i++) {
|
|
21336
|
-
const t =
|
|
22644
|
+
const t = stripComment9(lines[i] ?? "").trim();
|
|
21337
22645
|
if (t === "") continue;
|
|
21338
22646
|
const lineNo = i + 1;
|
|
21339
22647
|
const lm = /^layout\s*:\s*(\S+)/i.exec(t);
|
|
@@ -21355,9 +22663,9 @@ function parseCausalLoop(text2) {
|
|
|
21355
22663
|
parseLinkLine(ast, t, lineNo);
|
|
21356
22664
|
continue;
|
|
21357
22665
|
}
|
|
21358
|
-
ast.warnings.push(`Line ${lineNo}: unrecognised line: "${
|
|
22666
|
+
ast.warnings.push(`Line ${lineNo}: unrecognised line: "${truncate8(t, 80)}"`);
|
|
21359
22667
|
}
|
|
21360
|
-
|
|
22668
|
+
validate5(ast);
|
|
21361
22669
|
return ast;
|
|
21362
22670
|
}
|
|
21363
22671
|
function parseVarLine(ast, rest, lineNo) {
|
|
@@ -21369,7 +22677,7 @@ function parseLoopLine(ast, rest, lineNo) {
|
|
|
21369
22677
|
const m = /^([RB]\d+)\s+(.+)$/i.exec(rest);
|
|
21370
22678
|
if (!m) {
|
|
21371
22679
|
throw new CausalLoopParseError(
|
|
21372
|
-
`'loop' needs a loop id (e.g. R1, B1) and a phrase, got "${
|
|
22680
|
+
`'loop' needs a loop id (e.g. R1, B1) and a phrase, got "${truncate8(rest, 60)}"`,
|
|
21373
22681
|
lineNo
|
|
21374
22682
|
);
|
|
21375
22683
|
}
|
|
@@ -21380,7 +22688,7 @@ function parseLoopLine(ast, rest, lineNo) {
|
|
|
21380
22688
|
function parseLinkLine(ast, t, lineNo) {
|
|
21381
22689
|
const arrowIdx = topLevelArrow(t);
|
|
21382
22690
|
if (arrowIdx < 0) {
|
|
21383
|
-
throw new CausalLoopParseError(`malformed link (expected '->'): "${
|
|
22691
|
+
throw new CausalLoopParseError(`malformed link (expected '->'): "${truncate8(t, 60)}"`, lineNo);
|
|
21384
22692
|
}
|
|
21385
22693
|
const fromRaw = t.slice(0, arrowIdx).trim();
|
|
21386
22694
|
let rhs = t.slice(arrowIdx + 2).trim();
|
|
@@ -21422,7 +22730,7 @@ function parseLinkLine(ast, t, lineNo) {
|
|
|
21422
22730
|
if (label) link.label = label;
|
|
21423
22731
|
ast.links.push(link);
|
|
21424
22732
|
}
|
|
21425
|
-
function
|
|
22733
|
+
function validate5(ast) {
|
|
21426
22734
|
if (ast.links.length === 0) {
|
|
21427
22735
|
throw new CausalLoopParseError(
|
|
21428
22736
|
"a causal loop diagram needs at least one causal link (A -> B : +)"
|
|
@@ -21502,7 +22810,7 @@ function stripLeadingQuoted(s) {
|
|
|
21502
22810
|
return void 0;
|
|
21503
22811
|
}
|
|
21504
22812
|
}
|
|
21505
|
-
function
|
|
22813
|
+
function stripComment9(line2) {
|
|
21506
22814
|
let i = 0;
|
|
21507
22815
|
while (i < line2.length) {
|
|
21508
22816
|
const ch = line2[i];
|
|
@@ -21518,7 +22826,7 @@ function stripComment8(line2) {
|
|
|
21518
22826
|
}
|
|
21519
22827
|
return line2;
|
|
21520
22828
|
}
|
|
21521
|
-
function
|
|
22829
|
+
function truncate8(s, n) {
|
|
21522
22830
|
return s.length <= n ? s : s.slice(0, n - 1) + "\u2026";
|
|
21523
22831
|
}
|
|
21524
22832
|
|
|
@@ -21675,17 +22983,17 @@ var CAUSALLOOP_CONST = {
|
|
|
21675
22983
|
};
|
|
21676
22984
|
function layoutCausalLoop(ast) {
|
|
21677
22985
|
const analysis = analyseCausalLoop(ast);
|
|
21678
|
-
const
|
|
22986
|
+
const C3 = CAUSALLOOP_CONST;
|
|
21679
22987
|
const nodes = /* @__PURE__ */ new Map();
|
|
21680
22988
|
for (const v of ast.variables) {
|
|
21681
|
-
const halfW = Math.max(20, v.label.length *
|
|
22989
|
+
const halfW = Math.max(20, v.label.length * C3.CHAR_W / 2);
|
|
21682
22990
|
nodes.set(v.id, {
|
|
21683
22991
|
id: v.id,
|
|
21684
22992
|
label: v.label,
|
|
21685
22993
|
cx: 0,
|
|
21686
22994
|
cy: 0,
|
|
21687
22995
|
halfW,
|
|
21688
|
-
halfH:
|
|
22996
|
+
halfH: C3.LABEL_H / 2
|
|
21689
22997
|
});
|
|
21690
22998
|
}
|
|
21691
22999
|
const ringIds = ringOrder(ast, analysis);
|
|
@@ -21695,9 +23003,9 @@ function layoutCausalLoop(ast) {
|
|
|
21695
23003
|
let cy0 = 0;
|
|
21696
23004
|
let ringR = 0;
|
|
21697
23005
|
if (ringIds.length > 0) {
|
|
21698
|
-
ringR = Math.max(
|
|
21699
|
-
cx0 =
|
|
21700
|
-
cy0 =
|
|
23006
|
+
ringR = Math.max(C3.MIN_RING_R, C3.RING_GAP * ringIds.length / (2 * Math.PI));
|
|
23007
|
+
cx0 = C3.CANVAS_PAD + ringR + maxHalfW(ringIds, nodes);
|
|
23008
|
+
cy0 = C3.CANVAS_PAD + ringR + C3.LABEL_H;
|
|
21701
23009
|
const step = 2 * Math.PI / ringIds.length;
|
|
21702
23010
|
ringIds.forEach((id, i) => {
|
|
21703
23011
|
const ang = -Math.PI / 2 + i * step;
|
|
@@ -21707,14 +23015,14 @@ function layoutCausalLoop(ast) {
|
|
|
21707
23015
|
});
|
|
21708
23016
|
}
|
|
21709
23017
|
if (openIds.length > 0) {
|
|
21710
|
-
const rowY = ringIds.length > 0 ? cy0 + ringR +
|
|
21711
|
-
let x =
|
|
23018
|
+
const rowY = ringIds.length > 0 ? cy0 + ringR + C3.OPEN_ROW_GAP : C3.CANVAS_PAD + C3.LABEL_H;
|
|
23019
|
+
let x = C3.CANVAS_PAD;
|
|
21712
23020
|
for (const id of openIds) {
|
|
21713
23021
|
const node = nodes.get(id);
|
|
21714
23022
|
x += node.halfW;
|
|
21715
23023
|
node.cx = x;
|
|
21716
23024
|
node.cy = rowY;
|
|
21717
|
-
x += node.halfW +
|
|
23025
|
+
x += node.halfW + C3.OPEN_ROW_GAP;
|
|
21718
23026
|
}
|
|
21719
23027
|
}
|
|
21720
23028
|
const center = { x: cx0, y: cy0 };
|
|
@@ -21742,8 +23050,8 @@ function layoutCausalLoop(ast) {
|
|
|
21742
23050
|
maxX = Math.max(maxX, l.polarityX + 12);
|
|
21743
23051
|
maxY = Math.max(maxY, l.polarityY + 12);
|
|
21744
23052
|
}
|
|
21745
|
-
const width = Math.ceil(maxX +
|
|
21746
|
-
const height = Math.ceil(maxY +
|
|
23053
|
+
const width = Math.ceil(maxX + C3.CANVAS_PAD);
|
|
23054
|
+
const height = Math.ceil(maxY + C3.CANVAS_PAD);
|
|
21747
23055
|
return {
|
|
21748
23056
|
ast,
|
|
21749
23057
|
analysis,
|
|
@@ -21781,7 +23089,7 @@ function ringOrder(ast, analysis) {
|
|
|
21781
23089
|
return order;
|
|
21782
23090
|
}
|
|
21783
23091
|
function layoutLink(l, idx, nodes, center, ringSet, pairIndex) {
|
|
21784
|
-
const
|
|
23092
|
+
const C3 = CAUSALLOOP_CONST;
|
|
21785
23093
|
const a = nodes.get(l.from);
|
|
21786
23094
|
const b = nodes.get(l.to);
|
|
21787
23095
|
if (l.from === l.to) {
|
|
@@ -21809,17 +23117,17 @@ function layoutLink(l, idx, nodes, center, ringSet, pairIndex) {
|
|
|
21809
23117
|
ny = ux;
|
|
21810
23118
|
}
|
|
21811
23119
|
const side = pairIndex % 2 === 0 ? 1 : -1;
|
|
21812
|
-
const bow = dist *
|
|
23120
|
+
const bow = dist * C3.CURVE_BOW * side;
|
|
21813
23121
|
const ctrlX = mx + nx * bow;
|
|
21814
23122
|
const ctrlY = my + ny * bow;
|
|
21815
|
-
const path2 = `M ${
|
|
23123
|
+
const path2 = `M ${fmt4(start.x)} ${fmt4(start.y)} Q ${fmt4(ctrlX)} ${fmt4(ctrlY)} ${fmt4(end.x)} ${fmt4(end.y)}`;
|
|
21816
23124
|
let tx = end.x - ctrlX;
|
|
21817
23125
|
let ty = end.y - ctrlY;
|
|
21818
23126
|
const tn = Math.hypot(tx, ty) || 1;
|
|
21819
23127
|
tx /= tn;
|
|
21820
23128
|
ty /= tn;
|
|
21821
|
-
const polarityX = end.x - tx *
|
|
21822
|
-
const polarityY = end.y - ty *
|
|
23129
|
+
const polarityX = end.x - tx * C3.HEAD_OFFSET + nx * side * 10;
|
|
23130
|
+
const polarityY = end.y - ty * C3.HEAD_OFFSET + ny * side * 10;
|
|
21823
23131
|
const result = {
|
|
21824
23132
|
linkIndex: idx,
|
|
21825
23133
|
from: l.from,
|
|
@@ -21856,9 +23164,9 @@ function selfLink(l, idx, a) {
|
|
|
21856
23164
|
const x1 = a.cx - a.halfW * 0.4;
|
|
21857
23165
|
const x2 = a.cx + a.halfW * 0.4;
|
|
21858
23166
|
const loopTop = topY - 34;
|
|
21859
|
-
const path2 = `M ${
|
|
23167
|
+
const path2 = `M ${fmt4(x1)} ${fmt4(topY)} C ${fmt4(x1 - 12)} ${fmt4(loopTop)} ${fmt4(
|
|
21860
23168
|
x2 + 12
|
|
21861
|
-
)} ${
|
|
23169
|
+
)} ${fmt4(loopTop)} ${fmt4(x2)} ${fmt4(topY)}`;
|
|
21862
23170
|
const result = {
|
|
21863
23171
|
linkIndex: idx,
|
|
21864
23172
|
from: l.from,
|
|
@@ -21885,7 +23193,7 @@ function boxExit(node, ux, uy) {
|
|
|
21885
23193
|
return { x: node.cx + ux * t, y: node.cy + uy * t };
|
|
21886
23194
|
}
|
|
21887
23195
|
function layoutGlyph(loop, nodes, center) {
|
|
21888
|
-
const
|
|
23196
|
+
const C3 = CAUSALLOOP_CONST;
|
|
21889
23197
|
const pts = loop.variables.map((id) => nodes.get(id));
|
|
21890
23198
|
let sx = 0;
|
|
21891
23199
|
let sy = 0;
|
|
@@ -21925,10 +23233,10 @@ function layoutGlyph(loop, nodes, center) {
|
|
|
21925
23233
|
loop,
|
|
21926
23234
|
cx: gx,
|
|
21927
23235
|
cy: gy,
|
|
21928
|
-
r:
|
|
23236
|
+
r: C3.GLYPH_R,
|
|
21929
23237
|
clockwise,
|
|
21930
23238
|
phraseX: gx,
|
|
21931
|
-
phraseY: gy +
|
|
23239
|
+
phraseY: gy + C3.GLYPH_R + 13
|
|
21932
23240
|
};
|
|
21933
23241
|
}
|
|
21934
23242
|
function maxHalfW(ids, nodes) {
|
|
@@ -21936,7 +23244,7 @@ function maxHalfW(ids, nodes) {
|
|
|
21936
23244
|
for (const id of ids) m = Math.max(m, nodes.get(id).halfW);
|
|
21937
23245
|
return m;
|
|
21938
23246
|
}
|
|
21939
|
-
function
|
|
23247
|
+
function fmt4(n) {
|
|
21940
23248
|
return (Math.round(n * 100) / 100).toString();
|
|
21941
23249
|
}
|
|
21942
23250
|
|
|
@@ -21983,7 +23291,7 @@ function renderCausalLoopLayout(layout, config) {
|
|
|
21983
23291
|
);
|
|
21984
23292
|
const children = [
|
|
21985
23293
|
title(a11y),
|
|
21986
|
-
desc(
|
|
23294
|
+
desc(summarise8(layout)),
|
|
21987
23295
|
styleBlock,
|
|
21988
23296
|
el("rect", { x: 0, y: 0, width, height, class: "sx-cld-bg" })
|
|
21989
23297
|
];
|
|
@@ -22091,9 +23399,9 @@ function arrowhead(x, y, tx, ty) {
|
|
|
22091
23399
|
const by = y - ty * len;
|
|
22092
23400
|
const px = -ty;
|
|
22093
23401
|
const py = tx;
|
|
22094
|
-
const p1 = `${
|
|
22095
|
-
const p2 = `${
|
|
22096
|
-
const tip = `${
|
|
23402
|
+
const p1 = `${fmt5(bx + px * wide)},${fmt5(by + py * wide)}`;
|
|
23403
|
+
const p2 = `${fmt5(bx - px * wide)},${fmt5(by - py * wide)}`;
|
|
23404
|
+
const tip = `${fmt5(x)},${fmt5(y)}`;
|
|
22097
23405
|
return polygon({ points: `${tip} ${p1} ${p2}`, class: "sx-cld-arrow" });
|
|
22098
23406
|
}
|
|
22099
23407
|
function renderGlyph(g) {
|
|
@@ -22107,7 +23415,7 @@ function renderGlyph(g) {
|
|
|
22107
23415
|
const ey = g.cy + r7 * Math.sin(endAng);
|
|
22108
23416
|
const largeArc = 1;
|
|
22109
23417
|
const sweepFlag = g.clockwise ? 1 : 0;
|
|
22110
|
-
const arc = `M ${
|
|
23418
|
+
const arc = `M ${fmt5(sx)} ${fmt5(sy)} A ${r7} ${r7} 0 ${largeArc} ${sweepFlag} ${fmt5(ex)} ${fmt5(ey)}`;
|
|
22111
23419
|
const dir = g.clockwise ? 1 : -1;
|
|
22112
23420
|
const tx = -Math.sin(endAng) * dir;
|
|
22113
23421
|
const ty = Math.cos(endAng) * dir;
|
|
@@ -22148,11 +23456,11 @@ function glyphArrow(x, y, tx, ty) {
|
|
|
22148
23456
|
const by = y - ty * len;
|
|
22149
23457
|
const px = -ty;
|
|
22150
23458
|
const py = tx;
|
|
22151
|
-
const p1 = `${
|
|
22152
|
-
const p2 = `${
|
|
22153
|
-
return polygon({ points: `${
|
|
23459
|
+
const p1 = `${fmt5(bx + px * wide)},${fmt5(by + py * wide)}`;
|
|
23460
|
+
const p2 = `${fmt5(bx - px * wide)},${fmt5(by - py * wide)}`;
|
|
23461
|
+
return polygon({ points: `${fmt5(x)},${fmt5(y)} ${p1} ${p2}`, class: "sx-cld-glyph-head" });
|
|
22154
23462
|
}
|
|
22155
|
-
function
|
|
23463
|
+
function summarise8(layout) {
|
|
22156
23464
|
const { ast, analysis } = layout;
|
|
22157
23465
|
const parts = [
|
|
22158
23466
|
`Causal loop diagram${ast.title ? ` "${ast.title}"` : ""}: ${ast.variables.length} variable${ast.variables.length === 1 ? "" : "s"}, ${ast.links.length} causal link${ast.links.length === 1 ? "" : "s"}.`
|
|
@@ -22178,7 +23486,7 @@ function summarise7(layout) {
|
|
|
22178
23486
|
for (const w of ast.warnings) parts.push(w);
|
|
22179
23487
|
return parts.join(" ");
|
|
22180
23488
|
}
|
|
22181
|
-
function
|
|
23489
|
+
function fmt5(n) {
|
|
22182
23490
|
return (Math.round(n * 100) / 100).toString();
|
|
22183
23491
|
}
|
|
22184
23492
|
|
|
@@ -22406,11 +23714,11 @@ function analyseMarkov(ast) {
|
|
|
22406
23714
|
if (Math.abs(sum - 1) > ROW_SUM_TOL) {
|
|
22407
23715
|
if (ast.normalize) {
|
|
22408
23716
|
for (let j = 0; j < n; j++) P[i][j] /= sum;
|
|
22409
|
-
notes.push(`State "${order[i]}" out-edges summed to ${
|
|
23717
|
+
notes.push(`State "${order[i]}" out-edges summed to ${round9(sum)}; normalised to 1 (normalize: true).`);
|
|
22410
23718
|
} else {
|
|
22411
23719
|
const st = ast.states[i];
|
|
22412
23720
|
throw new MarkovParseError(
|
|
22413
|
-
`state "${order[i]}": outgoing probabilities sum to ${
|
|
23721
|
+
`state "${order[i]}": outgoing probabilities sum to ${round9(sum)}, must be 1.0 \u2014 fix the values or set "normalize: true"`,
|
|
22414
23722
|
st.line
|
|
22415
23723
|
);
|
|
22416
23724
|
}
|
|
@@ -22454,17 +23762,17 @@ function classifyStates(P, order, ast) {
|
|
|
22454
23762
|
if (indexOf[s] !== -1) continue;
|
|
22455
23763
|
const work = [{ v: s, pi: 0 }];
|
|
22456
23764
|
while (work.length > 0) {
|
|
22457
|
-
const
|
|
22458
|
-
const v =
|
|
22459
|
-
if (
|
|
23765
|
+
const frame2 = work[work.length - 1];
|
|
23766
|
+
const v = frame2.v;
|
|
23767
|
+
if (frame2.pi === 0) {
|
|
22460
23768
|
indexOf[v] = lowlink[v] = counter++;
|
|
22461
23769
|
stack.push(v);
|
|
22462
23770
|
onStack[v] = true;
|
|
22463
23771
|
}
|
|
22464
23772
|
let recursed = false;
|
|
22465
|
-
while (
|
|
22466
|
-
const w = adj[v][
|
|
22467
|
-
|
|
23773
|
+
while (frame2.pi < adj[v].length) {
|
|
23774
|
+
const w = adj[v][frame2.pi];
|
|
23775
|
+
frame2.pi++;
|
|
22468
23776
|
if (indexOf[w] === -1) {
|
|
22469
23777
|
work.push({ v: w, pi: 0 });
|
|
22470
23778
|
recursed = true;
|
|
@@ -22743,7 +24051,7 @@ function invert(mat) {
|
|
|
22743
24051
|
}
|
|
22744
24052
|
return A.map((row) => row.slice(m));
|
|
22745
24053
|
}
|
|
22746
|
-
function
|
|
24054
|
+
function round9(x) {
|
|
22747
24055
|
return Math.round(x * 1e6) / 1e6;
|
|
22748
24056
|
}
|
|
22749
24057
|
|
|
@@ -22767,7 +24075,7 @@ var MARKOV_CONST = {
|
|
|
22767
24075
|
};
|
|
22768
24076
|
function layoutMarkov(ast) {
|
|
22769
24077
|
const analysis = analyseMarkov(ast);
|
|
22770
|
-
const
|
|
24078
|
+
const C3 = MARKOV_CONST;
|
|
22771
24079
|
const states = ast.states;
|
|
22772
24080
|
states.length;
|
|
22773
24081
|
const classOf = analysis.classification?.byState;
|
|
@@ -22780,9 +24088,9 @@ function layoutMarkov(ast) {
|
|
|
22780
24088
|
let width = 0;
|
|
22781
24089
|
let height = 0;
|
|
22782
24090
|
if (ast.layout === "layered" && analysis.classification) {
|
|
22783
|
-
({ width, height } = placeLayered(ast, analysis.classification, centres,
|
|
24091
|
+
({ width, height } = placeLayered(ast, analysis.classification, centres, C3));
|
|
22784
24092
|
} else {
|
|
22785
|
-
({ width, height } = placeRing(states.map((s) => s.id), centres,
|
|
24093
|
+
({ width, height } = placeRing(states.map((s) => s.id), centres, C3));
|
|
22786
24094
|
}
|
|
22787
24095
|
const ringCenter = { x: width / 2, y: height / 2 };
|
|
22788
24096
|
const boxes = states.map((st) => {
|
|
@@ -22794,7 +24102,7 @@ function layoutMarkov(ast) {
|
|
|
22794
24102
|
state: st,
|
|
22795
24103
|
cx: c.x,
|
|
22796
24104
|
cy: c.y,
|
|
22797
|
-
r:
|
|
24105
|
+
r: C3.STATE_R,
|
|
22798
24106
|
isAbsorbing
|
|
22799
24107
|
};
|
|
22800
24108
|
if (tag) box2.classTag = tag;
|
|
@@ -22806,18 +24114,18 @@ function layoutMarkov(ast) {
|
|
|
22806
24114
|
for (const tr of ast.transitions) present.add(arcKey(tr.from, tr.to));
|
|
22807
24115
|
const arcs = ast.transitions.map((tr) => {
|
|
22808
24116
|
if (tr.self) {
|
|
22809
|
-
return selfLoopGeom(tr, centres.get(tr.from), ringCenter, ast.layout,
|
|
24117
|
+
return selfLoopGeom(tr, centres.get(tr.from), ringCenter, ast.layout, C3);
|
|
22810
24118
|
}
|
|
22811
24119
|
const a = centres.get(tr.from);
|
|
22812
24120
|
const b = centres.get(tr.to);
|
|
22813
24121
|
const hasReverse = present.has(arcKey(tr.to, tr.from));
|
|
22814
24122
|
const sign = hasReverse ? tr.from < tr.to ? 1 : -1 : 1;
|
|
22815
|
-
const bow = hasReverse ?
|
|
22816
|
-
return curvedArcGeom(tr, a, b, sign * bow,
|
|
24123
|
+
const bow = hasReverse ? C3.BOW : C3.SOLO_BOW;
|
|
24124
|
+
return curvedArcGeom(tr, a, b, sign * bow, C3);
|
|
22817
24125
|
});
|
|
22818
24126
|
return {
|
|
22819
24127
|
width,
|
|
22820
|
-
height: height + (ast.title ?
|
|
24128
|
+
height: height + (ast.title ? C3.TITLE_BAND : 0),
|
|
22821
24129
|
...ast.title ? { title: ast.title } : {},
|
|
22822
24130
|
states: boxes,
|
|
22823
24131
|
arcs,
|
|
@@ -22825,28 +24133,28 @@ function layoutMarkov(ast) {
|
|
|
22825
24133
|
ast
|
|
22826
24134
|
};
|
|
22827
24135
|
}
|
|
22828
|
-
function placeRing(ids, centres,
|
|
24136
|
+
function placeRing(ids, centres, C3) {
|
|
22829
24137
|
const n = ids.length;
|
|
22830
24138
|
if (n === 1) {
|
|
22831
|
-
const cx =
|
|
22832
|
-
const cy =
|
|
24139
|
+
const cx = C3.PADDING + C3.STATE_R + C3.LOOP_OUT;
|
|
24140
|
+
const cy = C3.PADDING + C3.STATE_R + C3.LOOP_OUT;
|
|
22833
24141
|
centres.set(ids[0], { x: cx, y: cy });
|
|
22834
24142
|
const dim2 = 2 * cx;
|
|
22835
24143
|
return { width: dim2, height: dim2 };
|
|
22836
24144
|
}
|
|
22837
24145
|
if (n === 2) {
|
|
22838
|
-
const cy =
|
|
22839
|
-
const dx = 2 *
|
|
22840
|
-
const cx02 =
|
|
24146
|
+
const cy = C3.PADDING + C3.STATE_R + C3.LOOP_OUT;
|
|
24147
|
+
const dx = 2 * C3.STATE_R + C3.RING_GAP + 60;
|
|
24148
|
+
const cx02 = C3.PADDING + C3.STATE_R + C3.LOOP_OUT;
|
|
22841
24149
|
centres.set(ids[0], { x: cx02, y: cy });
|
|
22842
24150
|
centres.set(ids[1], { x: cx02 + dx, y: cy });
|
|
22843
|
-
const width = cx02 + dx +
|
|
22844
|
-
const height = cy +
|
|
24151
|
+
const width = cx02 + dx + C3.STATE_R + C3.LOOP_OUT + C3.PADDING;
|
|
24152
|
+
const height = cy + C3.STATE_R + C3.LOOP_OUT + C3.PADDING;
|
|
22845
24153
|
return { width, height };
|
|
22846
24154
|
}
|
|
22847
|
-
const minArc = 2 *
|
|
22848
|
-
const radius = Math.max(minArc / (2 * Math.sin(Math.PI / n)), 2 *
|
|
22849
|
-
const margin =
|
|
24155
|
+
const minArc = 2 * C3.STATE_R + C3.RING_GAP;
|
|
24156
|
+
const radius = Math.max(minArc / (2 * Math.sin(Math.PI / n)), 2 * C3.STATE_R);
|
|
24157
|
+
const margin = C3.PADDING + C3.STATE_R + C3.LOOP_OUT;
|
|
22850
24158
|
const cx0 = margin + radius;
|
|
22851
24159
|
const cy0 = margin + radius;
|
|
22852
24160
|
ids.forEach((id, i) => {
|
|
@@ -22859,7 +24167,7 @@ function placeRing(ids, centres, C2) {
|
|
|
22859
24167
|
const dim = 2 * (radius + margin);
|
|
22860
24168
|
return { width: dim, height: dim };
|
|
22861
24169
|
}
|
|
22862
|
-
function placeLayered(ast, classification, centres,
|
|
24170
|
+
function placeLayered(ast, classification, centres, C3) {
|
|
22863
24171
|
const tier = (id) => {
|
|
22864
24172
|
const k = classification.byState[id];
|
|
22865
24173
|
if (k === "absorbing") return 2;
|
|
@@ -22869,18 +24177,18 @@ function placeLayered(ast, classification, centres, C2) {
|
|
|
22869
24177
|
const cols = [[], [], []];
|
|
22870
24178
|
for (const st of ast.states) cols[tier(st.id)].push(st.id);
|
|
22871
24179
|
const maxRows = Math.max(1, ...cols.map((c) => c.length));
|
|
22872
|
-
const margin =
|
|
24180
|
+
const margin = C3.PADDING + C3.STATE_R + C3.LOOP_OUT;
|
|
22873
24181
|
cols.forEach((col, ci) => {
|
|
22874
|
-
const x = margin + ci *
|
|
22875
|
-
const totalH = (col.length - 1) *
|
|
22876
|
-
const startY = margin + ((maxRows - 1) *
|
|
22877
|
-
col.forEach((id, ri) => centres.set(id, { x, y: startY + ri *
|
|
24182
|
+
const x = margin + ci * C3.TIER_DX;
|
|
24183
|
+
const totalH = (col.length - 1) * C3.TIER_DY;
|
|
24184
|
+
const startY = margin + ((maxRows - 1) * C3.TIER_DY - totalH) / 2;
|
|
24185
|
+
col.forEach((id, ri) => centres.set(id, { x, y: startY + ri * C3.TIER_DY }));
|
|
22878
24186
|
});
|
|
22879
|
-
const width = margin + 2 *
|
|
22880
|
-
const height = margin + (maxRows - 1) *
|
|
24187
|
+
const width = margin + 2 * C3.TIER_DX + C3.STATE_R + C3.LOOP_OUT + C3.PADDING;
|
|
24188
|
+
const height = margin + (maxRows - 1) * C3.TIER_DY + C3.STATE_R + C3.LOOP_OUT + C3.PADDING;
|
|
22881
24189
|
return { width, height };
|
|
22882
24190
|
}
|
|
22883
|
-
function curvedArcGeom(tr, a, b, bow,
|
|
24191
|
+
function curvedArcGeom(tr, a, b, bow, C3) {
|
|
22884
24192
|
const dx = b.x - a.x;
|
|
22885
24193
|
const dy = b.y - a.y;
|
|
22886
24194
|
const len = Math.hypot(dx, dy) || 1;
|
|
@@ -22893,8 +24201,8 @@ function curvedArcGeom(tr, a, b, bow, C2) {
|
|
|
22893
24201
|
x: (a.x + b.x) / 2 + nx * bow,
|
|
22894
24202
|
y: (a.y + b.y) / 2 + ny * bow
|
|
22895
24203
|
};
|
|
22896
|
-
const start = aimToBoundary(a, mid,
|
|
22897
|
-
const end = aimToBoundary(b, mid,
|
|
24204
|
+
const start = aimToBoundary(a, mid, C3.STATE_R);
|
|
24205
|
+
const end = aimToBoundary(b, mid, C3.STATE_R);
|
|
22898
24206
|
const c1 = { x: (start.x + mid.x) / 2, y: (start.y + mid.y) / 2 };
|
|
22899
24207
|
const c2 = { x: (end.x + mid.x) / 2, y: (end.y + mid.y) / 2 };
|
|
22900
24208
|
return {
|
|
@@ -22911,7 +24219,7 @@ function aimToBoundary(centre, target, r7) {
|
|
|
22911
24219
|
const len = Math.hypot(dx, dy) || 1;
|
|
22912
24220
|
return { x: centre.x + dx / len * r7, y: centre.y + dy / len * r7 };
|
|
22913
24221
|
}
|
|
22914
|
-
function selfLoopGeom(tr, c, ringCenter, layout,
|
|
24222
|
+
function selfLoopGeom(tr, c, ringCenter, layout, C3) {
|
|
22915
24223
|
let ox = c.x - ringCenter.x;
|
|
22916
24224
|
let oy = c.y - ringCenter.y;
|
|
22917
24225
|
if (layout === "layered" || ox === 0 && oy === 0) {
|
|
@@ -22923,26 +24231,26 @@ function selfLoopGeom(tr, c, ringCenter, layout, C2) {
|
|
|
22923
24231
|
const uy = oy / ol;
|
|
22924
24232
|
const tx = -uy;
|
|
22925
24233
|
const ty = ux;
|
|
22926
|
-
const spread =
|
|
24234
|
+
const spread = C3.STATE_R * 0.6;
|
|
22927
24235
|
const foot1 = {
|
|
22928
|
-
x: c.x + ux *
|
|
22929
|
-
y: c.y + uy *
|
|
24236
|
+
x: c.x + ux * C3.STATE_R * 0.85 - tx * spread,
|
|
24237
|
+
y: c.y + uy * C3.STATE_R * 0.85 - ty * spread
|
|
22930
24238
|
};
|
|
22931
24239
|
const foot2 = {
|
|
22932
|
-
x: c.x + ux *
|
|
22933
|
-
y: c.y + uy *
|
|
24240
|
+
x: c.x + ux * C3.STATE_R * 0.85 + tx * spread,
|
|
24241
|
+
y: c.y + uy * C3.STATE_R * 0.85 + ty * spread
|
|
22934
24242
|
};
|
|
22935
24243
|
const apex = {
|
|
22936
|
-
x: c.x + ux * (
|
|
22937
|
-
y: c.y + uy * (
|
|
24244
|
+
x: c.x + ux * (C3.STATE_R + C3.LOOP_OUT),
|
|
24245
|
+
y: c.y + uy * (C3.STATE_R + C3.LOOP_OUT)
|
|
22938
24246
|
};
|
|
22939
24247
|
const ctrl1 = {
|
|
22940
|
-
x: foot1.x + ux *
|
|
22941
|
-
y: foot1.y + uy *
|
|
24248
|
+
x: foot1.x + ux * C3.LOOP_OUT - tx * C3.LOOP_R,
|
|
24249
|
+
y: foot1.y + uy * C3.LOOP_OUT - ty * C3.LOOP_R
|
|
22942
24250
|
};
|
|
22943
24251
|
const ctrl2 = {
|
|
22944
|
-
x: foot2.x + ux *
|
|
22945
|
-
y: foot2.y + uy *
|
|
24252
|
+
x: foot2.x + ux * C3.LOOP_OUT + tx * C3.LOOP_R,
|
|
24253
|
+
y: foot2.y + uy * C3.LOOP_OUT + ty * C3.LOOP_R
|
|
22946
24254
|
};
|
|
22947
24255
|
return {
|
|
22948
24256
|
transition: tr,
|
|
@@ -23019,7 +24327,7 @@ function renderState2(sb) {
|
|
|
23019
24327
|
parts.push(
|
|
23020
24328
|
text(
|
|
23021
24329
|
{ class: "sx-markov-pi", x: sb.cx, y: sb.cy + sb.r + 14, "text-anchor": "middle" },
|
|
23022
|
-
`\u03C0=${
|
|
24330
|
+
`\u03C0=${fmt6(sb.pi)}`
|
|
23023
24331
|
)
|
|
23024
24332
|
);
|
|
23025
24333
|
}
|
|
@@ -23028,7 +24336,7 @@ function renderState2(sb) {
|
|
|
23028
24336
|
"data-id": sb.state.id
|
|
23029
24337
|
};
|
|
23030
24338
|
if (sb.classTag) attrs["data-class"] = sb.classTag;
|
|
23031
|
-
if (sb.pi !== void 0) attrs["data-pi"] =
|
|
24339
|
+
if (sb.pi !== void 0) attrs["data-pi"] = fmt6(sb.pi);
|
|
23032
24340
|
return group(attrs, parts);
|
|
23033
24341
|
}
|
|
23034
24342
|
function arcPath2(ag) {
|
|
@@ -23041,7 +24349,7 @@ function renderArc3(ag) {
|
|
|
23041
24349
|
path({ class: cls, d: arcPath2(ag), "marker-end": "url(#sx-markov-head)" }),
|
|
23042
24350
|
text(
|
|
23043
24351
|
{ class: "sx-markov-prob", x: ag.labelX, y: ag.labelY + 3, "text-anchor": "middle" },
|
|
23044
|
-
|
|
24352
|
+
fmt6(ag.transition.probability)
|
|
23045
24353
|
)
|
|
23046
24354
|
];
|
|
23047
24355
|
return group(
|
|
@@ -23049,7 +24357,7 @@ function renderArc3(ag) {
|
|
|
23049
24357
|
class: ag.self ? "sx-markov-arc-g sx-markov-arc-self-g" : "sx-markov-arc-g",
|
|
23050
24358
|
"data-from": ag.transition.from,
|
|
23051
24359
|
"data-to": ag.transition.to,
|
|
23052
|
-
"data-prob":
|
|
24360
|
+
"data-prob": fmt6(ag.transition.probability)
|
|
23053
24361
|
},
|
|
23054
24362
|
parts
|
|
23055
24363
|
);
|
|
@@ -23070,11 +24378,11 @@ function buildDesc(layout) {
|
|
|
23070
24378
|
}
|
|
23071
24379
|
if (a.stationary) {
|
|
23072
24380
|
if (a.stationary.unique) {
|
|
23073
|
-
const entries = layout.analysis.order.filter((id) => a.stationary.pi[id] !== void 0).map((id) => `${id}=${
|
|
24381
|
+
const entries = layout.analysis.order.filter((id) => a.stationary.pi[id] !== void 0).map((id) => `${id}=${fmt6(a.stationary.pi[id])}`);
|
|
23074
24382
|
out.push(`Stationary \u03C0: { ${entries.join(", ")} }.`);
|
|
23075
24383
|
} else if (a.stationary.perClass.length) {
|
|
23076
24384
|
const blocks = a.stationary.perClass.map((pc2) => {
|
|
23077
|
-
const e = pc2.states.map((id) => `${id}=${
|
|
24385
|
+
const e = pc2.states.map((id) => `${id}=${fmt6(pc2.pi[id])}`).join(", ");
|
|
23078
24386
|
return `{ ${e} }`;
|
|
23079
24387
|
});
|
|
23080
24388
|
out.push(`Stationary \u03C0 (per recurrent class, not globally unique): ${blocks.join("; ")}.`);
|
|
@@ -23082,10 +24390,10 @@ function buildDesc(layout) {
|
|
|
23082
24390
|
}
|
|
23083
24391
|
if (a.absorbing) {
|
|
23084
24392
|
const ab = a.absorbing;
|
|
23085
|
-
const tParts = ab.transient.map((id, i) => `${id}=${
|
|
24393
|
+
const tParts = ab.transient.map((id, i) => `${id}=${fmt6(ab.t[i])}`);
|
|
23086
24394
|
out.push(`Expected steps to absorption t: { ${tParts.join(", ")} }.`);
|
|
23087
24395
|
const bRows = ab.transient.map((from, i) => {
|
|
23088
|
-
const probs = ab.absorbing.map((to, j) => `${to}=${
|
|
24396
|
+
const probs = ab.absorbing.map((to, j) => `${to}=${fmt6(ab.B[i][j])}`).join(", ");
|
|
23089
24397
|
return `${from}\u2192(${probs})`;
|
|
23090
24398
|
});
|
|
23091
24399
|
out.push(`Absorption probabilities B: ${bRows.join("; ")}.`);
|
|
@@ -23141,7 +24449,7 @@ function renderMarkov(textOrAst, config) {
|
|
|
23141
24449
|
const layout = layoutMarkov(ast);
|
|
23142
24450
|
return renderMarkovLayout(layout, config);
|
|
23143
24451
|
}
|
|
23144
|
-
function
|
|
24452
|
+
function fmt6(x) {
|
|
23145
24453
|
if (!Number.isFinite(x)) return String(x);
|
|
23146
24454
|
const r7 = Math.round(x * 1e3) / 1e3;
|
|
23147
24455
|
return String(r7);
|
|
@@ -23187,7 +24495,7 @@ function parseGitGraph(text2) {
|
|
|
23187
24495
|
i = skipBlankAndDirectives(rawLines, i, ast);
|
|
23188
24496
|
let headerSeen = false;
|
|
23189
24497
|
while (i < rawLines.length) {
|
|
23190
|
-
const t =
|
|
24498
|
+
const t = stripComment10(rawLines[i] ?? "").trim();
|
|
23191
24499
|
if (t === "") {
|
|
23192
24500
|
i++;
|
|
23193
24501
|
continue;
|
|
@@ -23195,7 +24503,7 @@ function parseGitGraph(text2) {
|
|
|
23195
24503
|
const h = /^gitgraph\b\s*:?\s*(.*)$/i.exec(t);
|
|
23196
24504
|
if (!h) {
|
|
23197
24505
|
throw new GitGraphParseError(
|
|
23198
|
-
`expected a 'gitGraph' header, got: ${
|
|
24506
|
+
`expected a 'gitGraph' header, got: ${truncate9(t)}`,
|
|
23199
24507
|
i + 1
|
|
23200
24508
|
);
|
|
23201
24509
|
}
|
|
@@ -23214,7 +24522,7 @@ function parseGitGraph(text2) {
|
|
|
23214
24522
|
throw new GitGraphParseError("empty gitGraph (no header)");
|
|
23215
24523
|
}
|
|
23216
24524
|
for (; i < rawLines.length; i++) {
|
|
23217
|
-
const t =
|
|
24525
|
+
const t = stripComment10(rawLines[i] ?? "").trim();
|
|
23218
24526
|
if (t === "") continue;
|
|
23219
24527
|
if (/^%%\{/.test(t)) {
|
|
23220
24528
|
applyInit(t, ast);
|
|
@@ -23223,7 +24531,7 @@ function parseGitGraph(text2) {
|
|
|
23223
24531
|
const op = parseOperation2(t, i + 1);
|
|
23224
24532
|
if (op) ast.operations.push(op);
|
|
23225
24533
|
}
|
|
23226
|
-
|
|
24534
|
+
validate6(ast);
|
|
23227
24535
|
return ast;
|
|
23228
24536
|
}
|
|
23229
24537
|
function parseOperation2(line2, lineNo) {
|
|
@@ -23265,7 +24573,7 @@ function parseOptions(rest, lineNo) {
|
|
|
23265
24573
|
const keyMatch = /^([A-Za-z]+)\s*:/.exec(s.slice(i));
|
|
23266
24574
|
if (!keyMatch) {
|
|
23267
24575
|
throw new GitGraphParseError(
|
|
23268
|
-
`unexpected token near '${
|
|
24576
|
+
`unexpected token near '${truncate9(s.slice(i))}' (expected key: value)`,
|
|
23269
24577
|
lineNo
|
|
23270
24578
|
);
|
|
23271
24579
|
}
|
|
@@ -23380,7 +24688,7 @@ function parseCherryPick(rest, lineNo) {
|
|
|
23380
24688
|
}
|
|
23381
24689
|
return { kind: "cherry-pick", id: o.id, tag: o.tag, parent: o.parent, line: lineNo };
|
|
23382
24690
|
}
|
|
23383
|
-
function
|
|
24691
|
+
function validate6(ast) {
|
|
23384
24692
|
const firstOp = ast.operations[0];
|
|
23385
24693
|
if (firstOp && firstOp.kind !== "commit" && firstOp.kind !== "branch") ;
|
|
23386
24694
|
}
|
|
@@ -23401,7 +24709,7 @@ function parseFrontmatter2(lines, start, ast) {
|
|
|
23401
24709
|
function skipBlankAndDirectives(lines, start, ast) {
|
|
23402
24710
|
let i = start;
|
|
23403
24711
|
for (; i < lines.length; i++) {
|
|
23404
|
-
const t =
|
|
24712
|
+
const t = stripComment10(lines[i] ?? "").trim();
|
|
23405
24713
|
if (t === "") continue;
|
|
23406
24714
|
if (/^%%\{/.test(t)) {
|
|
23407
24715
|
applyInit(t, ast);
|
|
@@ -23434,7 +24742,7 @@ function applyConfigLines(lines, ast) {
|
|
|
23434
24742
|
if (tv && !/^(LR|TB|BT)$/i.test(tv)) ast.title = tv;
|
|
23435
24743
|
}
|
|
23436
24744
|
}
|
|
23437
|
-
function
|
|
24745
|
+
function stripComment10(line2) {
|
|
23438
24746
|
const idx = line2.indexOf("%%");
|
|
23439
24747
|
if (idx >= 0 && line2.slice(idx, idx + 3) !== "%%{") {
|
|
23440
24748
|
return line2.slice(0, idx);
|
|
@@ -23444,7 +24752,7 @@ function stripComment9(line2) {
|
|
|
23444
24752
|
function isQuote(ch) {
|
|
23445
24753
|
return ch === '"' || ch === "'" || ch === "\u201C" || ch === "\u2018" || ch === "\u300C" || ch === "\u300E" || ch === "\xAB";
|
|
23446
24754
|
}
|
|
23447
|
-
function
|
|
24755
|
+
function truncate9(s) {
|
|
23448
24756
|
return s.length > 40 ? `${s.slice(0, 40)}\u2026` : s;
|
|
23449
24757
|
}
|
|
23450
24758
|
|
|
@@ -23650,18 +24958,18 @@ function assignLanes(ast, state2) {
|
|
|
23650
24958
|
}
|
|
23651
24959
|
function layoutGitGraph(ast) {
|
|
23652
24960
|
const replay = replayGitGraph(ast);
|
|
23653
|
-
const
|
|
24961
|
+
const C3 = GITGRAPH_CONST;
|
|
23654
24962
|
const branchByName = new Map(replay.branches.map((b) => [b.name, b]));
|
|
23655
24963
|
const laneCount = replay.branches.length;
|
|
23656
24964
|
const commitCount = replay.commits.length;
|
|
23657
|
-
const headBand = ast.showBranches ?
|
|
23658
|
-
const timeAt = (s) => headBand +
|
|
23659
|
-
const crossAt = (l) =>
|
|
24965
|
+
const headBand = ast.showBranches ? C3.PILL_GUTTER : C3.LEAD_IN;
|
|
24966
|
+
const timeAt = (s) => headBand + C3.LEAD_IN + s * C3.TIME_STEP;
|
|
24967
|
+
const crossAt = (l) => C3.PAD + C3.TAG_BAND + C3.LANE_GAP / 2 + l * C3.LANE_GAP;
|
|
23660
24968
|
const timeSpan = commitCount > 0 ? timeAt(commitCount - 1) : timeAt(0);
|
|
23661
24969
|
const crossSpan = crossAt(Math.max(0, laneCount - 1));
|
|
23662
24970
|
const isVertical = ast.orientation === "TB" || ast.orientation === "BT";
|
|
23663
|
-
const timeMax = timeSpan +
|
|
23664
|
-
const crossMax = crossSpan +
|
|
24971
|
+
const timeMax = timeSpan + C3.TIME_STEP / 2 + (ast.showCommitLabel ? C3.LABEL_BAND : C3.PAD);
|
|
24972
|
+
const crossMax = crossSpan + C3.LANE_GAP / 2 + C3.PAD;
|
|
23665
24973
|
const width = isVertical ? crossMax : timeMax;
|
|
23666
24974
|
const height = isVertical ? timeMax : crossMax;
|
|
23667
24975
|
const place = (t, c) => {
|
|
@@ -23692,12 +25000,12 @@ function layoutGitGraph(ast) {
|
|
|
23692
25000
|
}
|
|
23693
25001
|
const firstOwn = own[0];
|
|
23694
25002
|
const isTrunk = !firstOwn || firstOwn.parents.length === 0;
|
|
23695
|
-
const startT = isTrunk ? timeAt(startSeq) -
|
|
25003
|
+
const startT = isTrunk ? timeAt(startSeq) - C3.TIME_STEP / 2 : timeAt(startSeq);
|
|
23696
25004
|
const endT = timeAt(endSeq);
|
|
23697
25005
|
const c = crossAt(info.lane);
|
|
23698
25006
|
const head = place(startT, c);
|
|
23699
25007
|
const tail = place(endT, c);
|
|
23700
|
-
const pillT = headBand -
|
|
25008
|
+
const pillT = headBand - C3.LEAD_IN / 2;
|
|
23701
25009
|
const pillPos = place(pillT, c);
|
|
23702
25010
|
return {
|
|
23703
25011
|
info,
|
|
@@ -23821,7 +25129,7 @@ function renderGitGraphLayout(layout, config) {
|
|
|
23821
25129
|
const styleBlock = buildStyle2(pal, ast.showBranches);
|
|
23822
25130
|
const children = [
|
|
23823
25131
|
title(a11y),
|
|
23824
|
-
desc(
|
|
25132
|
+
desc(summarise9(layout)),
|
|
23825
25133
|
styleBlock,
|
|
23826
25134
|
rect({ x: 0, y: 0, width, height, class: "sx-gg-bg" })
|
|
23827
25135
|
];
|
|
@@ -24071,7 +25379,7 @@ ${laneRules}
|
|
|
24071
25379
|
function num2(n) {
|
|
24072
25380
|
return Number.isInteger(n) ? String(n) : n.toFixed(2);
|
|
24073
25381
|
}
|
|
24074
|
-
function
|
|
25382
|
+
function summarise9(layout) {
|
|
24075
25383
|
const c = layout.replay.commits.length;
|
|
24076
25384
|
const b = layout.replay.branches.length;
|
|
24077
25385
|
const merges = layout.replay.commits.filter((n) => n.isMerge).length;
|
|
@@ -24363,7 +25671,7 @@ function parseEpc(text2) {
|
|
|
24363
25671
|
let i = 0;
|
|
24364
25672
|
let headerSeen = false;
|
|
24365
25673
|
while (i < rawLines.length) {
|
|
24366
|
-
const t =
|
|
25674
|
+
const t = stripComment11(rawLines[i] ?? "").trim();
|
|
24367
25675
|
if (t === "") {
|
|
24368
25676
|
i++;
|
|
24369
25677
|
continue;
|
|
@@ -24371,7 +25679,7 @@ function parseEpc(text2) {
|
|
|
24371
25679
|
const h = /^epc\b(.*)$/i.exec(t);
|
|
24372
25680
|
if (h) {
|
|
24373
25681
|
const after = h[1].trim();
|
|
24374
|
-
const q =
|
|
25682
|
+
const q = matchQuoted7(after);
|
|
24375
25683
|
if (q) ast.title = q.value;
|
|
24376
25684
|
headerSeen = true;
|
|
24377
25685
|
i++;
|
|
@@ -24382,11 +25690,11 @@ function parseEpc(text2) {
|
|
|
24382
25690
|
}
|
|
24383
25691
|
if (!headerSeen) return finish(ast);
|
|
24384
25692
|
for (; i < rawLines.length; i++) {
|
|
24385
|
-
const t =
|
|
25693
|
+
const t = stripComment11(rawLines[i] ?? "").trim();
|
|
24386
25694
|
if (t === "") continue;
|
|
24387
25695
|
const lineNo = i + 1;
|
|
24388
25696
|
if (/^layout\s*:/i.test(t)) {
|
|
24389
|
-
const v =
|
|
25697
|
+
const v = afterColon7(t).toLowerCase();
|
|
24390
25698
|
if (v === "tb" || v === "lr") ast.direction = v;
|
|
24391
25699
|
else ast.warnings.push(`Line ${lineNo}: unknown layout "${v}" \u2014 using "tb".`);
|
|
24392
25700
|
continue;
|
|
@@ -24400,7 +25708,7 @@ function parseEpc(text2) {
|
|
|
24400
25708
|
parseDeclLine(ast, kw[1].toLowerCase(), t.slice(kw[0].length).trim(), lineNo);
|
|
24401
25709
|
continue;
|
|
24402
25710
|
}
|
|
24403
|
-
ast.warnings.push(`Line ${lineNo}: unrecognised line: "${
|
|
25711
|
+
ast.warnings.push(`Line ${lineNo}: unrecognised line: "${truncate10(t, 80)}"`);
|
|
24404
25712
|
}
|
|
24405
25713
|
return finish(ast);
|
|
24406
25714
|
}
|
|
@@ -24434,13 +25742,13 @@ function parseEdgeLine(ast, line2, lineNo) {
|
|
|
24434
25742
|
const colon = topLevelColon(body);
|
|
24435
25743
|
if (colon >= 0) {
|
|
24436
25744
|
const labelPart = body.slice(colon + 1).trim();
|
|
24437
|
-
const q =
|
|
25745
|
+
const q = matchQuoted7(labelPart);
|
|
24438
25746
|
edgeLabel2 = q ? q.value : labelPart;
|
|
24439
25747
|
body = body.slice(0, colon).trim();
|
|
24440
25748
|
}
|
|
24441
25749
|
const parts = splitArrow(body).map((p) => p.trim()).filter((p) => p.length > 0);
|
|
24442
25750
|
if (parts.length < 2) {
|
|
24443
|
-
throw new EpcParseError(`an edge needs at least two nodes around '->', got "${
|
|
25751
|
+
throw new EpcParseError(`an edge needs at least two nodes around '->', got "${truncate10(line2, 60)}"`, lineNo);
|
|
24444
25752
|
}
|
|
24445
25753
|
for (const p of parts) {
|
|
24446
25754
|
if (!isId2(p)) throw new EpcParseError(`invalid node reference "${p}" in edge`, lineNo);
|
|
@@ -24477,11 +25785,11 @@ function ensureRef(ast, id, _lineNo) {
|
|
|
24477
25785
|
}
|
|
24478
25786
|
function parseIdAndLabel3(s, lineNo) {
|
|
24479
25787
|
const m = /^([A-Za-z_]\w*)/.exec(s.trim());
|
|
24480
|
-
if (!m) throw new EpcParseError(`expected a node id, got "${
|
|
25788
|
+
if (!m) throw new EpcParseError(`expected a node id, got "${truncate10(s, 40)}"`, lineNo);
|
|
24481
25789
|
const id = m[1];
|
|
24482
25790
|
const rest = s.trim().slice(id.length).trim();
|
|
24483
25791
|
if (rest === "") return { id };
|
|
24484
|
-
const q =
|
|
25792
|
+
const q = matchQuoted7(rest);
|
|
24485
25793
|
if (q) return { id, label: q.value };
|
|
24486
25794
|
return { id, label: rest };
|
|
24487
25795
|
}
|
|
@@ -24504,7 +25812,7 @@ function splitArrow(s) {
|
|
|
24504
25812
|
}
|
|
24505
25813
|
if (ch === '"' || ch === "\u300C" || ch === "\u201C") {
|
|
24506
25814
|
inQ = true;
|
|
24507
|
-
qc =
|
|
25815
|
+
qc = closingQuote7(ch);
|
|
24508
25816
|
buf += ch;
|
|
24509
25817
|
continue;
|
|
24510
25818
|
}
|
|
@@ -24529,30 +25837,30 @@ function topLevelColon(s) {
|
|
|
24529
25837
|
}
|
|
24530
25838
|
if (ch === '"' || ch === "\u300C" || ch === "\u201C") {
|
|
24531
25839
|
inQ = true;
|
|
24532
|
-
qc =
|
|
25840
|
+
qc = closingQuote7(ch);
|
|
24533
25841
|
continue;
|
|
24534
25842
|
}
|
|
24535
25843
|
if (ch === ":") return i;
|
|
24536
25844
|
}
|
|
24537
25845
|
return -1;
|
|
24538
25846
|
}
|
|
24539
|
-
function
|
|
25847
|
+
function matchQuoted7(s) {
|
|
24540
25848
|
if (!s) return void 0;
|
|
24541
25849
|
const open = s[0];
|
|
24542
25850
|
if (open !== '"' && open !== "\u300C" && open !== "\u201C") return void 0;
|
|
24543
|
-
const close =
|
|
25851
|
+
const close = closingQuote7(open);
|
|
24544
25852
|
const end = s.indexOf(close, 1);
|
|
24545
25853
|
if (end < 0) return void 0;
|
|
24546
25854
|
return { value: s.slice(1, end), length: end + 1 };
|
|
24547
25855
|
}
|
|
24548
|
-
function
|
|
25856
|
+
function closingQuote7(open) {
|
|
24549
25857
|
return open === "\u300C" ? "\u300D" : open === "\u201C" ? "\u201D" : '"';
|
|
24550
25858
|
}
|
|
24551
|
-
function
|
|
25859
|
+
function afterColon7(s) {
|
|
24552
25860
|
const i = s.indexOf(":");
|
|
24553
25861
|
return i < 0 ? "" : s.slice(i + 1).trim();
|
|
24554
25862
|
}
|
|
24555
|
-
function
|
|
25863
|
+
function stripComment11(line2) {
|
|
24556
25864
|
let inQ = false, qc = "";
|
|
24557
25865
|
for (let i = 0; i < line2.length; i++) {
|
|
24558
25866
|
const ch = line2[i];
|
|
@@ -24562,7 +25870,7 @@ function stripComment10(line2) {
|
|
|
24562
25870
|
}
|
|
24563
25871
|
if (ch === '"' || ch === "\u300C" || ch === "\u201C") {
|
|
24564
25872
|
inQ = true;
|
|
24565
|
-
qc =
|
|
25873
|
+
qc = closingQuote7(ch);
|
|
24566
25874
|
continue;
|
|
24567
25875
|
}
|
|
24568
25876
|
if (ch === "#") return line2.slice(0, i);
|
|
@@ -24570,7 +25878,7 @@ function stripComment10(line2) {
|
|
|
24570
25878
|
}
|
|
24571
25879
|
return line2;
|
|
24572
25880
|
}
|
|
24573
|
-
function
|
|
25881
|
+
function truncate10(s, n) {
|
|
24574
25882
|
return s.length <= n ? s : s.slice(0, n - 1) + "\u2026";
|
|
24575
25883
|
}
|
|
24576
25884
|
|
|
@@ -24912,7 +26220,7 @@ function renderEpcLayout(layout, config) {
|
|
|
24912
26220
|
);
|
|
24913
26221
|
const children = [
|
|
24914
26222
|
title(a11y),
|
|
24915
|
-
desc(
|
|
26223
|
+
desc(summarise10(layout)),
|
|
24916
26224
|
styleBlock,
|
|
24917
26225
|
defs([
|
|
24918
26226
|
el("marker", {
|
|
@@ -25056,7 +26364,7 @@ function renderEdge6(e) {
|
|
|
25056
26364
|
parts
|
|
25057
26365
|
);
|
|
25058
26366
|
}
|
|
25059
|
-
function
|
|
26367
|
+
function summarise10(layout) {
|
|
25060
26368
|
const { ast, analysis } = layout;
|
|
25061
26369
|
const counts = { event: 0, function: 0, connector: 0 };
|
|
25062
26370
|
for (const n of ast.nodes) counts[n.kind]++;
|
|
@@ -25151,12 +26459,12 @@ function parseIdef0(text2) {
|
|
|
25151
26459
|
let i = 0;
|
|
25152
26460
|
let headerSeen = false;
|
|
25153
26461
|
for (; i < rawLines.length; i++) {
|
|
25154
|
-
const t =
|
|
26462
|
+
const t = stripComment12(rawLines[i] ?? "").trim();
|
|
25155
26463
|
if (t === "") continue;
|
|
25156
26464
|
const h = /^idef0\b(.*)$/i.exec(t);
|
|
25157
26465
|
if (h) {
|
|
25158
26466
|
const after = h[1].trim();
|
|
25159
|
-
const q =
|
|
26467
|
+
const q = matchQuoted8(after);
|
|
25160
26468
|
if (q) ast.title = q.value;
|
|
25161
26469
|
headerSeen = true;
|
|
25162
26470
|
i++;
|
|
@@ -25167,7 +26475,7 @@ function parseIdef0(text2) {
|
|
|
25167
26475
|
throw new Idef0ParseError(`an idef0 diagram must start with the 'idef0' keyword`);
|
|
25168
26476
|
}
|
|
25169
26477
|
for (; i < rawLines.length; i++) {
|
|
25170
|
-
const t =
|
|
26478
|
+
const t = stripComment12(rawLines[i] ?? "").trim();
|
|
25171
26479
|
if (t === "") continue;
|
|
25172
26480
|
const lineNo = i + 1;
|
|
25173
26481
|
const nodeM = /^node\s+(.+)$/i.exec(t);
|
|
@@ -25178,7 +26486,7 @@ function parseIdef0(text2) {
|
|
|
25178
26486
|
const metaM = /^(purpose|viewpoint)\b\s*(.*)$/i.exec(t);
|
|
25179
26487
|
if (metaM) {
|
|
25180
26488
|
const key = metaM[1].toLowerCase();
|
|
25181
|
-
const q =
|
|
26489
|
+
const q = matchQuoted8(metaM[2].trim());
|
|
25182
26490
|
ast[key] = q ? q.value : metaM[2].trim();
|
|
25183
26491
|
continue;
|
|
25184
26492
|
}
|
|
@@ -25196,17 +26504,17 @@ function parseIdef0(text2) {
|
|
|
25196
26504
|
parseFlowArrow(ast, t, lineNo);
|
|
25197
26505
|
continue;
|
|
25198
26506
|
}
|
|
25199
|
-
ast.warnings.push(`Line ${lineNo}: unrecognised line: "${
|
|
26507
|
+
ast.warnings.push(`Line ${lineNo}: unrecognised line: "${truncate11(t, 80)}"`);
|
|
25200
26508
|
}
|
|
25201
26509
|
return ast;
|
|
25202
26510
|
}
|
|
25203
26511
|
function parseFunction2(ast, rest, lineNo) {
|
|
25204
26512
|
const idM = /^([A-Za-z_]\w*)/.exec(rest);
|
|
25205
|
-
if (!idM) throw new Idef0ParseError(`function needs an id, got "${
|
|
26513
|
+
if (!idM) throw new Idef0ParseError(`function needs an id, got "${truncate11(rest, 40)}"`, lineNo);
|
|
25206
26514
|
const id = idM[1];
|
|
25207
26515
|
let tail = rest.slice(id.length).trim();
|
|
25208
26516
|
let name = id;
|
|
25209
|
-
const q =
|
|
26517
|
+
const q = matchQuoted8(tail);
|
|
25210
26518
|
if (q) {
|
|
25211
26519
|
name = q.value;
|
|
25212
26520
|
tail = tail.slice(q.length).trim();
|
|
@@ -25228,11 +26536,11 @@ function parseFunction2(ast, rest, lineNo) {
|
|
|
25228
26536
|
}
|
|
25229
26537
|
function parseRoleArrow(ast, role, rest, lineNo) {
|
|
25230
26538
|
const idM = /^([A-Za-z_]\w*)/.exec(rest);
|
|
25231
|
-
if (!idM) throw new Idef0ParseError(`${role} needs a box id, got "${
|
|
26539
|
+
if (!idM) throw new Idef0ParseError(`${role} needs a box id, got "${truncate11(rest, 40)}"`, lineNo);
|
|
25232
26540
|
const boxId = idM[1];
|
|
25233
26541
|
let tail = rest.slice(boxId.length).trim();
|
|
25234
26542
|
let label = "";
|
|
25235
|
-
const q =
|
|
26543
|
+
const q = matchQuoted8(tail);
|
|
25236
26544
|
if (q) {
|
|
25237
26545
|
label = q.value;
|
|
25238
26546
|
tail = tail.slice(q.length).trim();
|
|
@@ -25258,10 +26566,10 @@ function parseFlowArrow(ast, t, lineNo) {
|
|
|
25258
26566
|
const lhs = t.slice(0, arrowIdx).trim();
|
|
25259
26567
|
let rhs = t.slice(arrowIdx + 2).trim();
|
|
25260
26568
|
const srcM = /^([A-Za-z_]\w*)$/.exec(lhs);
|
|
25261
|
-
if (!srcM) throw new Idef0ParseError(`flow arrow source must be a box id, got "${
|
|
26569
|
+
if (!srcM) throw new Idef0ParseError(`flow arrow source must be a box id, got "${truncate11(lhs, 40)}"`, lineNo);
|
|
25262
26570
|
const srcId = srcM[1];
|
|
25263
26571
|
const tgtM = /^([A-Za-z_]\w*)(?:\.([a-z]+))?/i.exec(rhs);
|
|
25264
|
-
if (!tgtM) throw new Idef0ParseError(`flow arrow target must be a box id, got "${
|
|
26572
|
+
if (!tgtM) throw new Idef0ParseError(`flow arrow target must be a box id, got "${truncate11(rhs, 40)}"`, lineNo);
|
|
25265
26573
|
const tgtId = tgtM[1];
|
|
25266
26574
|
const roleWord = tgtM[2]?.toLowerCase();
|
|
25267
26575
|
let role = "input";
|
|
@@ -25282,7 +26590,7 @@ function parseFlowArrow(ast, t, lineNo) {
|
|
|
25282
26590
|
}
|
|
25283
26591
|
rhs = rhs.slice(tgtM[0].length).trim();
|
|
25284
26592
|
let label = "";
|
|
25285
|
-
const q =
|
|
26593
|
+
const q = matchQuoted8(rhs);
|
|
25286
26594
|
if (q) {
|
|
25287
26595
|
label = q.value;
|
|
25288
26596
|
rhs = rhs.slice(q.length).trim();
|
|
@@ -25305,19 +26613,19 @@ function parseFlowArrow(ast, t, lineNo) {
|
|
|
25305
26613
|
function consumeTunnel(s) {
|
|
25306
26614
|
return /\(\s*tunnel\s*\)/i.test(s);
|
|
25307
26615
|
}
|
|
25308
|
-
function
|
|
26616
|
+
function matchQuoted8(s) {
|
|
25309
26617
|
if (!s) return void 0;
|
|
25310
26618
|
const open = s[0];
|
|
25311
26619
|
if (open !== '"' && open !== "\u300C" && open !== "\u201C") return void 0;
|
|
25312
|
-
const close =
|
|
26620
|
+
const close = closingQuote8(open);
|
|
25313
26621
|
const end = s.indexOf(close, 1);
|
|
25314
26622
|
if (end < 0) return void 0;
|
|
25315
26623
|
return { value: s.slice(1, end), length: end + 1 };
|
|
25316
26624
|
}
|
|
25317
|
-
function
|
|
26625
|
+
function closingQuote8(open) {
|
|
25318
26626
|
return open === "\u300C" ? "\u300D" : open === "\u201C" ? "\u201D" : '"';
|
|
25319
26627
|
}
|
|
25320
|
-
function
|
|
26628
|
+
function stripComment12(line2) {
|
|
25321
26629
|
let inQ = false;
|
|
25322
26630
|
let qc = "";
|
|
25323
26631
|
for (let i = 0; i < line2.length; i++) {
|
|
@@ -25328,14 +26636,14 @@ function stripComment11(line2) {
|
|
|
25328
26636
|
}
|
|
25329
26637
|
if (ch === '"' || ch === "\u300C" || ch === "\u201C") {
|
|
25330
26638
|
inQ = true;
|
|
25331
|
-
qc =
|
|
26639
|
+
qc = closingQuote8(ch);
|
|
25332
26640
|
continue;
|
|
25333
26641
|
}
|
|
25334
26642
|
if (ch === "#") return line2.slice(0, i);
|
|
25335
26643
|
}
|
|
25336
26644
|
return line2;
|
|
25337
26645
|
}
|
|
25338
|
-
function
|
|
26646
|
+
function truncate11(s, n) {
|
|
25339
26647
|
return s.length <= n ? s : s.slice(0, n - 1) + "\u2026";
|
|
25340
26648
|
}
|
|
25341
26649
|
|
|
@@ -25493,22 +26801,22 @@ var IDEF0_CONST = {
|
|
|
25493
26801
|
};
|
|
25494
26802
|
function layoutIdef0(astIn) {
|
|
25495
26803
|
const ast = analyseIdef0(astIn);
|
|
25496
|
-
const
|
|
25497
|
-
const ox =
|
|
25498
|
-
const oy =
|
|
26804
|
+
const C3 = IDEF0_CONST;
|
|
26805
|
+
const ox = C3.MARGIN;
|
|
26806
|
+
const oy = C3.MARGIN + C3.TITLE_H;
|
|
25499
26807
|
const boxes = ast.boxes.map((box2, idx) => ({
|
|
25500
26808
|
box: box2,
|
|
25501
|
-
x: ox + idx *
|
|
25502
|
-
y: oy + idx *
|
|
25503
|
-
width:
|
|
25504
|
-
height:
|
|
26809
|
+
x: ox + idx * C3.STEP_X,
|
|
26810
|
+
y: oy + idx * C3.STEP_Y,
|
|
26811
|
+
width: C3.BOX_W,
|
|
26812
|
+
height: C3.BOX_H
|
|
25505
26813
|
}));
|
|
25506
26814
|
const boxIndex = new Map(boxes.map((b, i) => [b.box.id, i]));
|
|
25507
26815
|
const lastBox = boxes[boxes.length - 1];
|
|
25508
|
-
const contentRight = lastBox.x +
|
|
25509
|
-
const contentBottom = lastBox.y +
|
|
25510
|
-
const width = contentRight +
|
|
25511
|
-
const height = contentBottom +
|
|
26816
|
+
const contentRight = lastBox.x + C3.BOX_W;
|
|
26817
|
+
const contentBottom = lastBox.y + C3.BOX_H;
|
|
26818
|
+
const width = contentRight + C3.MARGIN;
|
|
26819
|
+
const height = contentBottom + C3.MARGIN + C3.TITLEBLOCK_H;
|
|
25512
26820
|
const arrows = ast.arrows.map(
|
|
25513
26821
|
(arrow2) => routeArrow(arrow2, boxes, boxIndex)
|
|
25514
26822
|
);
|
|
@@ -25527,7 +26835,7 @@ function sidePoint(b, side) {
|
|
|
25527
26835
|
}
|
|
25528
26836
|
}
|
|
25529
26837
|
function routeArrow(arrow2, boxes, boxIndex) {
|
|
25530
|
-
const
|
|
26838
|
+
const C3 = IDEF0_CONST;
|
|
25531
26839
|
const targetSide = ICOM_SIDE[arrow2.role];
|
|
25532
26840
|
const fromBoundary = arrow2.from.kind === "boundary";
|
|
25533
26841
|
const toBoundary = arrow2.to.kind === "boundary";
|
|
@@ -25560,10 +26868,10 @@ function routeArrow(arrow2, boxes, boxIndex) {
|
|
|
25560
26868
|
margin: false
|
|
25561
26869
|
};
|
|
25562
26870
|
}
|
|
25563
|
-
const marginY =
|
|
26871
|
+
const marginY = C3.MARGIN / 2 + C3.TITLE_H;
|
|
25564
26872
|
let d;
|
|
25565
26873
|
if (targetSide === "left") {
|
|
25566
|
-
const approachX = end.x -
|
|
26874
|
+
const approachX = end.x - C3.FEEDBACK_LEADIN;
|
|
25567
26875
|
d = `M ${start.x} ${start.y} L ${start.x + 20} ${start.y} L ${start.x + 20} ${marginY} L ${approachX} ${marginY} L ${approachX} ${end.y} L ${end.x} ${end.y}`;
|
|
25568
26876
|
} else {
|
|
25569
26877
|
d = `M ${start.x} ${start.y} L ${start.x + 20} ${start.y} L ${start.x + 20} ${marginY} L ${end.x} ${marginY} L ${end.x} ${end.y}`;
|
|
@@ -25577,7 +26885,7 @@ function routeArrow(arrow2, boxes, boxIndex) {
|
|
|
25577
26885
|
};
|
|
25578
26886
|
}
|
|
25579
26887
|
function routeBoundary(arrow2, boxes, boxIndex, targetSide, fromBoundary) {
|
|
25580
|
-
const
|
|
26888
|
+
const C3 = IDEF0_CONST;
|
|
25581
26889
|
const boxEnd = fromBoundary ? arrow2.to : arrow2.from;
|
|
25582
26890
|
const b = boxes[boxIndex.get(boxEnd.boxId)];
|
|
25583
26891
|
const side = fromBoundary ? targetSide : "right";
|
|
@@ -25585,16 +26893,16 @@ function routeBoundary(arrow2, boxes, boxIndex, targetSide, fromBoundary) {
|
|
|
25585
26893
|
let stub;
|
|
25586
26894
|
switch (side) {
|
|
25587
26895
|
case "left":
|
|
25588
|
-
stub = { x: edge.x -
|
|
26896
|
+
stub = { x: edge.x - C3.STUB, y: edge.y };
|
|
25589
26897
|
break;
|
|
25590
26898
|
case "top":
|
|
25591
|
-
stub = { x: edge.x, y: edge.y -
|
|
26899
|
+
stub = { x: edge.x, y: edge.y - C3.STUB };
|
|
25592
26900
|
break;
|
|
25593
26901
|
case "right":
|
|
25594
|
-
stub = { x: edge.x +
|
|
26902
|
+
stub = { x: edge.x + C3.STUB, y: edge.y };
|
|
25595
26903
|
break;
|
|
25596
26904
|
case "bottom":
|
|
25597
|
-
stub = { x: edge.x, y: edge.y +
|
|
26905
|
+
stub = { x: edge.x, y: edge.y + C3.STUB };
|
|
25598
26906
|
break;
|
|
25599
26907
|
}
|
|
25600
26908
|
let path2;
|
|
@@ -25669,7 +26977,7 @@ function renderIdef0Layout(layout, config) {
|
|
|
25669
26977
|
);
|
|
25670
26978
|
const children = [
|
|
25671
26979
|
title(a11y),
|
|
25672
|
-
desc(
|
|
26980
|
+
desc(summarise11(layout)),
|
|
25673
26981
|
styleBlock,
|
|
25674
26982
|
rect({ x: 0, y: 0, width, height, class: "sx-idef0-bg" })
|
|
25675
26983
|
];
|
|
@@ -25827,7 +27135,7 @@ function renderTitleBlock(width, height, node, title2) {
|
|
|
25827
27135
|
text({ x: c2 + 6, y: y + 13, class: "sx-idef0-tb-key" }, "NUMBER")
|
|
25828
27136
|
]);
|
|
25829
27137
|
}
|
|
25830
|
-
function
|
|
27138
|
+
function summarise11(layout) {
|
|
25831
27139
|
const { ast } = layout;
|
|
25832
27140
|
const counts = {};
|
|
25833
27141
|
for (const a of ast.arrows) counts[a.role] = (counts[a.role] ?? 0) + 1;
|
|
@@ -25897,7 +27205,7 @@ function normalizeQuotes3(text2) {
|
|
|
25897
27205
|
for (const ch of text2) out += QUOTE_FOLD.get(ch) ?? ch;
|
|
25898
27206
|
return out;
|
|
25899
27207
|
}
|
|
25900
|
-
function
|
|
27208
|
+
function stripComment13(line2) {
|
|
25901
27209
|
let inQuote = false;
|
|
25902
27210
|
for (let i = 0; i < line2.length; i++) {
|
|
25903
27211
|
const ch = line2[i];
|
|
@@ -25941,7 +27249,7 @@ function parseThreatModel(text2) {
|
|
|
25941
27249
|
let i = 0;
|
|
25942
27250
|
let headerSeen = false;
|
|
25943
27251
|
for (; i < rawLines.length; i++) {
|
|
25944
|
-
const t =
|
|
27252
|
+
const t = stripComment13(rawLines[i] ?? "").trim();
|
|
25945
27253
|
if (t === "") continue;
|
|
25946
27254
|
const h = /^(threatmodel|stride)\b(.*)$/i.exec(t);
|
|
25947
27255
|
if (h) {
|
|
@@ -25960,7 +27268,7 @@ function parseThreatModel(text2) {
|
|
|
25960
27268
|
}
|
|
25961
27269
|
for (; i < rawLines.length; i++) {
|
|
25962
27270
|
const lineNo = i + 1;
|
|
25963
|
-
const t =
|
|
27271
|
+
const t = stripComment13(rawLines[i] ?? "").trim();
|
|
25964
27272
|
if (t === "") continue;
|
|
25965
27273
|
const titleM = /^title\s*:\s*(.+)$/i.exec(t);
|
|
25966
27274
|
if (titleM) {
|
|
@@ -26054,7 +27362,7 @@ function parseThreatModel(text2) {
|
|
|
26054
27362
|
);
|
|
26055
27363
|
}
|
|
26056
27364
|
resolveEndpoints(ast, byId);
|
|
26057
|
-
|
|
27365
|
+
validate7(ast, byId);
|
|
26058
27366
|
return ast;
|
|
26059
27367
|
}
|
|
26060
27368
|
function resolveEndpoints(ast, byId) {
|
|
@@ -26077,7 +27385,7 @@ function resolveEndpoints(ast, byId) {
|
|
|
26077
27385
|
b.members = b.members.map(canon);
|
|
26078
27386
|
}
|
|
26079
27387
|
}
|
|
26080
|
-
function
|
|
27388
|
+
function validate7(ast, byId) {
|
|
26081
27389
|
for (const f of ast.flows) {
|
|
26082
27390
|
const s = byId.get(f.source)?.node;
|
|
26083
27391
|
const tg = byId.get(f.target)?.node;
|
|
@@ -26488,7 +27796,7 @@ function renderThreatModelLayout(layout, config) {
|
|
|
26488
27796
|
]);
|
|
26489
27797
|
const children = [
|
|
26490
27798
|
title(a11y),
|
|
26491
|
-
desc(
|
|
27799
|
+
desc(summarise12(layout)),
|
|
26492
27800
|
styleBlock,
|
|
26493
27801
|
markerDefs,
|
|
26494
27802
|
rect({ x: 0, y: 0, width, height, class: "sx-tm-bg" })
|
|
@@ -26604,8 +27912,8 @@ ${n.label}` : n.label;
|
|
|
26604
27912
|
}
|
|
26605
27913
|
function strideBadge(n, fontFamily) {
|
|
26606
27914
|
const letters = n.stride.categories.join("");
|
|
26607
|
-
const
|
|
26608
|
-
const bw = letters.length *
|
|
27915
|
+
const charW2 = 7;
|
|
27916
|
+
const bw = letters.length * charW2 + 10;
|
|
26609
27917
|
const bh = 15;
|
|
26610
27918
|
const bx = n.cx - bw / 2;
|
|
26611
27919
|
const by = n.y - bh - 4;
|
|
@@ -26634,7 +27942,7 @@ function strideBadge(n, fontFamily) {
|
|
|
26634
27942
|
}
|
|
26635
27943
|
function renderFlow(f, fontFamily) {
|
|
26636
27944
|
const pts = f.points;
|
|
26637
|
-
const d = "M " + pts.map((p) => `${
|
|
27945
|
+
const d = "M " + pts.map((p) => `${round10(p.x)} ${round10(p.y)}`).join(" L ");
|
|
26638
27946
|
const crossing = f.crossesBoundary ? "true" : void 0;
|
|
26639
27947
|
const marker = f.crossesBoundary ? "url(#sx-tm-mk-x)" : "url(#sx-tm-mk)";
|
|
26640
27948
|
const labelHaloW = f.label.length * 5.4 + 8;
|
|
@@ -26702,10 +28010,10 @@ function arrowMarker2(id, cls, crossing) {
|
|
|
26702
28010
|
]
|
|
26703
28011
|
);
|
|
26704
28012
|
}
|
|
26705
|
-
function
|
|
28013
|
+
function round10(n) {
|
|
26706
28014
|
return Math.round(n * 100) / 100;
|
|
26707
28015
|
}
|
|
26708
|
-
function
|
|
28016
|
+
function summarise12(layout) {
|
|
26709
28017
|
const a = layout.analysis;
|
|
26710
28018
|
const counts = {
|
|
26711
28019
|
external: layout.nodes.filter((n) => n.kind === "external").length,
|
|
@@ -26917,7 +28225,7 @@ function parseWeldSpec(raw) {
|
|
|
26917
28225
|
function emptyJoint() {
|
|
26918
28226
|
return { around: false, field: false };
|
|
26919
28227
|
}
|
|
26920
|
-
function
|
|
28228
|
+
function stripComment14(line2) {
|
|
26921
28229
|
const hash = line2.indexOf("#");
|
|
26922
28230
|
if (hash >= 0 && (line2.slice(0, hash).match(/["'“‘]/g)?.length ?? 0) % 2 === 0) {
|
|
26923
28231
|
return line2.slice(0, hash);
|
|
@@ -26946,7 +28254,7 @@ function parseJointBody(body, joint) {
|
|
|
26946
28254
|
}
|
|
26947
28255
|
function parseWelding(text2) {
|
|
26948
28256
|
const ast = { type: "welding", standard: "aws", joints: [], warnings: [] };
|
|
26949
|
-
const src = text2.split(/\r?\n/).map(
|
|
28257
|
+
const src = text2.split(/\r?\n/).map(stripComment14).join("\n");
|
|
26950
28258
|
const headEnd = src.search(/\bjoint\b/i);
|
|
26951
28259
|
const headerScope = headEnd >= 0 ? src.slice(0, headEnd) : src;
|
|
26952
28260
|
const header = headerScope.match(/welding\b([^\n]*)/i);
|
|
@@ -27014,9 +28322,9 @@ function layoutWelding(ast) {
|
|
|
27014
28322
|
var W = 18;
|
|
27015
28323
|
var H = 15;
|
|
27016
28324
|
function pl(points, cls) {
|
|
27017
|
-
return polygon({ points: points.map((p) => `${
|
|
28325
|
+
return polygon({ points: points.map((p) => `${round11(p[0])},${round11(p[1])}`).join(" "), class: cls, fill: "none" });
|
|
27018
28326
|
}
|
|
27019
|
-
function
|
|
28327
|
+
function round11(n) {
|
|
27020
28328
|
return Math.round(n * 100) / 100;
|
|
27021
28329
|
}
|
|
27022
28330
|
function weldGlyph(type, cx, y, dir, cls) {
|
|
@@ -27032,7 +28340,7 @@ function weldGlyph(type, cx, y, dir, cls) {
|
|
|
27032
28340
|
line({ x1: cx + 3, y1: y, x2: cx + 3, y2: yb, class: cls })
|
|
27033
28341
|
];
|
|
27034
28342
|
case "vgroove":
|
|
27035
|
-
return [path({ d: `M ${
|
|
28343
|
+
return [path({ d: `M ${round11(x0)} ${round11(yb)} L ${round11(cx)} ${round11(y)} L ${round11(x1)} ${round11(yb)}`, class: cls, fill: "none" })];
|
|
27036
28344
|
case "bevel":
|
|
27037
28345
|
return [
|
|
27038
28346
|
line({ x1: cx - 4, y1: y, x2: cx - 4, y2: yb, class: cls }),
|
|
@@ -27041,7 +28349,7 @@ function weldGlyph(type, cx, y, dir, cls) {
|
|
|
27041
28349
|
case "ugroove":
|
|
27042
28350
|
return [
|
|
27043
28351
|
path({
|
|
27044
|
-
d: `M ${
|
|
28352
|
+
d: `M ${round11(x0)} ${round11(y)} L ${round11(x0)} ${round11(y + dir * H * 0.45)} Q ${round11(x0)} ${round11(yb)} ${round11(cx)} ${round11(yb)} Q ${round11(x1)} ${round11(yb)} ${round11(x1)} ${round11(y + dir * H * 0.45)} L ${round11(x1)} ${round11(y)}`,
|
|
27045
28353
|
class: cls,
|
|
27046
28354
|
fill: "none"
|
|
27047
28355
|
})
|
|
@@ -27049,20 +28357,20 @@ function weldGlyph(type, cx, y, dir, cls) {
|
|
|
27049
28357
|
case "jgroove":
|
|
27050
28358
|
return [
|
|
27051
28359
|
path({
|
|
27052
|
-
d: `M ${
|
|
28360
|
+
d: `M ${round11(cx - 4)} ${round11(y)} L ${round11(cx - 4)} ${round11(y + dir * H * 0.45)} Q ${round11(cx - 4)} ${round11(yb)} ${round11(x1)} ${round11(yb)}`,
|
|
27053
28361
|
class: cls,
|
|
27054
28362
|
fill: "none"
|
|
27055
28363
|
})
|
|
27056
28364
|
];
|
|
27057
28365
|
case "flarev":
|
|
27058
28366
|
return [
|
|
27059
|
-
path({ d: `M ${
|
|
27060
|
-
path({ d: `M ${
|
|
28367
|
+
path({ d: `M ${round11(x0)} ${round11(yb)} Q ${round11(cx - 2)} ${round11(yb)} ${round11(cx)} ${round11(y)}`, class: cls, fill: "none" }),
|
|
28368
|
+
path({ d: `M ${round11(x1)} ${round11(yb)} Q ${round11(cx + 2)} ${round11(yb)} ${round11(cx)} ${round11(y)}`, class: cls, fill: "none" })
|
|
27061
28369
|
];
|
|
27062
28370
|
case "flarebevel":
|
|
27063
28371
|
return [
|
|
27064
28372
|
line({ x1: cx - 4, y1: y, x2: cx - 4, y2: yb, class: cls }),
|
|
27065
|
-
path({ d: `M ${
|
|
28373
|
+
path({ d: `M ${round11(cx - 4)} ${round11(y)} Q ${round11(x1)} ${round11(y)} ${round11(x1)} ${round11(yb)}`, class: cls, fill: "none" })
|
|
27066
28374
|
];
|
|
27067
28375
|
case "plug":
|
|
27068
28376
|
case "slot": {
|
|
@@ -27080,12 +28388,12 @@ function weldGlyph(type, cx, y, dir, cls) {
|
|
|
27080
28388
|
case "backing": {
|
|
27081
28389
|
const rr = W * 0.45;
|
|
27082
28390
|
const sweep = dir > 0 ? 1 : 0;
|
|
27083
|
-
return [path({ d: `M ${
|
|
28391
|
+
return [path({ d: `M ${round11(cx - rr)} ${round11(y)} A ${round11(rr)} ${round11(rr)} 0 0 ${sweep} ${round11(cx + rr)} ${round11(y)}`, class: cls, fill: "none" })];
|
|
27084
28392
|
}
|
|
27085
28393
|
case "surfacing": {
|
|
27086
28394
|
const r7 = W / 4;
|
|
27087
28395
|
const yy = y + dir * 3;
|
|
27088
|
-
const bump = (off) => path({ d: `M ${
|
|
28396
|
+
const bump = (off) => path({ d: `M ${round11(cx - W / 2)} ${round11(off)} a ${round11(r7)} ${round11(r7)} 0 0 ${dir > 0 ? 1 : 0} ${round11(W / 2)} 0 a ${round11(r7)} ${round11(r7)} 0 0 ${dir > 0 ? 1 : 0} ${round11(W / 2)} 0`, class: cls, fill: "none" });
|
|
27089
28397
|
return [bump(y), bump(yy)];
|
|
27090
28398
|
}
|
|
27091
28399
|
case "edge":
|
|
@@ -27103,7 +28411,7 @@ function contourGlyph(contour, cx, y, dir, cls) {
|
|
|
27103
28411
|
}
|
|
27104
28412
|
const bulge = contour === "convex" ? dir : -dir;
|
|
27105
28413
|
return path({
|
|
27106
|
-
d: `M ${
|
|
28414
|
+
d: `M ${round11(cx - half)} ${round11(yy)} Q ${round11(cx)} ${round11(yy + bulge * 5)} ${round11(cx + half)} ${round11(yy)}`,
|
|
27107
28415
|
class: cls,
|
|
27108
28416
|
fill: "none"
|
|
27109
28417
|
});
|
|
@@ -30948,7 +32256,7 @@ var ErdParseError = class extends Error {
|
|
|
30948
32256
|
}
|
|
30949
32257
|
lineNumber;
|
|
30950
32258
|
};
|
|
30951
|
-
function
|
|
32259
|
+
function stripComment15(s) {
|
|
30952
32260
|
let out = "";
|
|
30953
32261
|
let inQuote = false;
|
|
30954
32262
|
for (let i = 0; i < s.length; i++) {
|
|
@@ -31002,7 +32310,7 @@ function parseCardToken(raw, side) {
|
|
|
31002
32310
|
}
|
|
31003
32311
|
function lex(text2) {
|
|
31004
32312
|
return text2.split(/\r?\n/).map((raw, i) => ({
|
|
31005
|
-
text:
|
|
32313
|
+
text: stripComment15(raw).trim(),
|
|
31006
32314
|
lineNumber: i + 1
|
|
31007
32315
|
})).filter((l) => l.text.length > 0);
|
|
31008
32316
|
}
|
|
@@ -31380,8 +32688,8 @@ var ERD_CONST = {
|
|
|
31380
32688
|
EDGE_BEND_STAGGER: 10
|
|
31381
32689
|
};
|
|
31382
32690
|
function measureEntity(ent) {
|
|
31383
|
-
const
|
|
31384
|
-
const headerWidth =
|
|
32691
|
+
const C3 = ERD_CONST;
|
|
32692
|
+
const headerWidth = C3.ENTITY_PADDING_X * 2 + ent.name.length * C3.CHAR_W_HEADER;
|
|
31385
32693
|
let widest = headerWidth;
|
|
31386
32694
|
const rows = [];
|
|
31387
32695
|
for (let i = 0; i < ent.attributes.length; i++) {
|
|
@@ -31389,14 +32697,14 @@ function measureEntity(ent) {
|
|
|
31389
32697
|
const namePart = a.name;
|
|
31390
32698
|
const typePart = a.type ?? "";
|
|
31391
32699
|
const markerCount = (a.pk ? 1 : 0) + (a.fk ? 1 : 0) + (a.uk ? 1 : 0) + (a.notNull && !a.pk ? 1 : 0);
|
|
31392
|
-
const markerWidth = markerCount * (
|
|
31393
|
-
const w =
|
|
32700
|
+
const markerWidth = markerCount * (C3.CHAR_W_MARKER * 2.4 + 4);
|
|
32701
|
+
const w = C3.ENTITY_PADDING_X * 2 + namePart.length * C3.CHAR_W_ROW + (typePart ? C3.TYPE_GAP + typePart.length * C3.CHAR_W_ROW : 0) + markerWidth;
|
|
31394
32702
|
if (w > widest) widest = w;
|
|
31395
|
-
const yCenter =
|
|
32703
|
+
const yCenter = C3.HEADER_HEIGHT + i * C3.ROW_HEIGHT + C3.ROW_HEIGHT / 2;
|
|
31396
32704
|
rows.push({ attribute: a, yCenter });
|
|
31397
32705
|
}
|
|
31398
|
-
const width = Math.max(widest,
|
|
31399
|
-
const height =
|
|
32706
|
+
const width = Math.max(widest, C3.ENTITY_MIN_WIDTH);
|
|
32707
|
+
const height = C3.HEADER_HEIGHT + ent.attributes.length * C3.ROW_HEIGHT + C3.ROW_PAD_Y;
|
|
31400
32708
|
return { width, height, rows };
|
|
31401
32709
|
}
|
|
31402
32710
|
function buildColumnAssignment(ast) {
|
|
@@ -31493,15 +32801,15 @@ function reorderByBarycenter(layerToEnts, layers, refs) {
|
|
|
31493
32801
|
sweep("down");
|
|
31494
32802
|
}
|
|
31495
32803
|
function assignYCoordinates(orderedLayers, measured, neighbors) {
|
|
31496
|
-
const
|
|
32804
|
+
const C3 = ERD_CONST;
|
|
31497
32805
|
const placed = /* @__PURE__ */ new Map();
|
|
31498
32806
|
for (const ls of orderedLayers) {
|
|
31499
|
-
let prevBottom =
|
|
32807
|
+
let prevBottom = C3.PADDING - C3.ROW_GAP;
|
|
31500
32808
|
for (let i = 0; i < ls.ids.length; i++) {
|
|
31501
32809
|
const id = ls.ids[i];
|
|
31502
32810
|
const m = measured.get(id);
|
|
31503
32811
|
const ns = neighbors.get(id);
|
|
31504
|
-
let target =
|
|
32812
|
+
let target = C3.PADDING;
|
|
31505
32813
|
if (ns) {
|
|
31506
32814
|
const placedNeighborCenters = [];
|
|
31507
32815
|
for (const n of ns) {
|
|
@@ -31515,7 +32823,7 @@ function assignYCoordinates(orderedLayers, measured, neighbors) {
|
|
|
31515
32823
|
target = med - m.height / 2;
|
|
31516
32824
|
}
|
|
31517
32825
|
}
|
|
31518
|
-
const y = Math.max(target, prevBottom +
|
|
32826
|
+
const y = Math.max(target, prevBottom + C3.ROW_GAP);
|
|
31519
32827
|
placed.set(id, {
|
|
31520
32828
|
id,
|
|
31521
32829
|
y,
|
|
@@ -31528,7 +32836,7 @@ function assignYCoordinates(orderedLayers, measured, neighbors) {
|
|
|
31528
32836
|
}
|
|
31529
32837
|
for (let li = orderedLayers.length - 1; li >= 0; li--) {
|
|
31530
32838
|
const ls = orderedLayers[li];
|
|
31531
|
-
let prevBottom =
|
|
32839
|
+
let prevBottom = C3.PADDING - C3.ROW_GAP;
|
|
31532
32840
|
for (let i = 0; i < ls.ids.length; i++) {
|
|
31533
32841
|
const id = ls.ids[i];
|
|
31534
32842
|
const slot = placed.get(id);
|
|
@@ -31547,7 +32855,7 @@ function assignYCoordinates(orderedLayers, measured, neighbors) {
|
|
|
31547
32855
|
target = med - slot.height / 2;
|
|
31548
32856
|
}
|
|
31549
32857
|
}
|
|
31550
|
-
const lower = prevBottom +
|
|
32858
|
+
const lower = prevBottom + C3.ROW_GAP;
|
|
31551
32859
|
const newY = Math.max(lower, Math.min(slot.y, target));
|
|
31552
32860
|
slot.y = newY;
|
|
31553
32861
|
prevBottom = newY + slot.height;
|
|
@@ -31558,7 +32866,7 @@ function assignYCoordinates(orderedLayers, measured, neighbors) {
|
|
|
31558
32866
|
return out;
|
|
31559
32867
|
}
|
|
31560
32868
|
function layoutErd(ast) {
|
|
31561
|
-
const
|
|
32869
|
+
const C3 = ERD_CONST;
|
|
31562
32870
|
const isLR = ast.direction === "LR";
|
|
31563
32871
|
const measured = /* @__PURE__ */ new Map();
|
|
31564
32872
|
for (const e of ast.entities) {
|
|
@@ -31606,30 +32914,30 @@ function layoutErd(ast) {
|
|
|
31606
32914
|
const orderingCoord = assignYCoordinates(orderedLayers, measureForOrdering, neighbors);
|
|
31607
32915
|
const placed = [];
|
|
31608
32916
|
if (isLR) {
|
|
31609
|
-
let cursorX =
|
|
32917
|
+
let cursorX = C3.PADDING;
|
|
31610
32918
|
for (const ls of layerSizes) {
|
|
31611
32919
|
for (const id of ls.ids) {
|
|
31612
32920
|
const m = measured.get(id);
|
|
31613
32921
|
const x = cursorX + (ls.maxWidth - m.width) / 2;
|
|
31614
|
-
const y = orderingCoord.get(id) ??
|
|
32922
|
+
const y = orderingCoord.get(id) ?? C3.PADDING;
|
|
31615
32923
|
placed.push({
|
|
31616
32924
|
entity: m.ent,
|
|
31617
32925
|
x,
|
|
31618
32926
|
y,
|
|
31619
32927
|
width: m.width,
|
|
31620
32928
|
height: m.height,
|
|
31621
|
-
headerHeight:
|
|
32929
|
+
headerHeight: C3.HEADER_HEIGHT,
|
|
31622
32930
|
rows: m.rows
|
|
31623
32931
|
});
|
|
31624
32932
|
}
|
|
31625
|
-
cursorX += ls.maxWidth +
|
|
32933
|
+
cursorX += ls.maxWidth + C3.COL_GAP;
|
|
31626
32934
|
}
|
|
31627
32935
|
} else {
|
|
31628
|
-
let cursorY =
|
|
32936
|
+
let cursorY = C3.PADDING;
|
|
31629
32937
|
for (const ls of layerSizes) {
|
|
31630
32938
|
for (const id of ls.ids) {
|
|
31631
32939
|
const m = measured.get(id);
|
|
31632
|
-
const x = orderingCoord.get(id) ??
|
|
32940
|
+
const x = orderingCoord.get(id) ?? C3.PADDING;
|
|
31633
32941
|
const y = cursorY + (ls.maxHeight - m.height) / 2;
|
|
31634
32942
|
placed.push({
|
|
31635
32943
|
entity: m.ent,
|
|
@@ -31637,11 +32945,11 @@ function layoutErd(ast) {
|
|
|
31637
32945
|
y,
|
|
31638
32946
|
width: m.width,
|
|
31639
32947
|
height: m.height,
|
|
31640
|
-
headerHeight:
|
|
32948
|
+
headerHeight: C3.HEADER_HEIGHT,
|
|
31641
32949
|
rows: m.rows
|
|
31642
32950
|
});
|
|
31643
32951
|
}
|
|
31644
|
-
cursorY += ls.maxHeight +
|
|
32952
|
+
cursorY += ls.maxHeight + C3.ROW_GAP;
|
|
31645
32953
|
}
|
|
31646
32954
|
}
|
|
31647
32955
|
let maxX = 0;
|
|
@@ -31650,8 +32958,8 @@ function layoutErd(ast) {
|
|
|
31650
32958
|
if (e.x + e.width > maxX) maxX = e.x + e.width;
|
|
31651
32959
|
if (e.y + e.height > maxY) maxY = e.y + e.height;
|
|
31652
32960
|
}
|
|
31653
|
-
const width = maxX +
|
|
31654
|
-
const height = maxY +
|
|
32961
|
+
const width = maxX + C3.PADDING;
|
|
32962
|
+
const height = maxY + C3.PADDING;
|
|
31655
32963
|
const placedById = new Map(placed.map((p) => [p.entity.id, p]));
|
|
31656
32964
|
const edges = [];
|
|
31657
32965
|
const bendBucketUses = /* @__PURE__ */ new Map();
|
|
@@ -31688,7 +32996,7 @@ function rowYByColumn(e, col) {
|
|
|
31688
32996
|
return e.y + e.height / 2;
|
|
31689
32997
|
}
|
|
31690
32998
|
function routeOrthogonal(a, b, fromCol, toCol, bendBucketUses) {
|
|
31691
|
-
const
|
|
32999
|
+
const C3 = ERD_CONST;
|
|
31692
33000
|
const aCenterX = a.x + a.width / 2;
|
|
31693
33001
|
const bCenterX = b.x + b.width / 2;
|
|
31694
33002
|
const aCenterY = a.y + a.height / 2;
|
|
@@ -31712,14 +33020,14 @@ function routeOrthogonal(a, b, fromCol, toCol, bendBucketUses) {
|
|
|
31712
33020
|
const useIdx = bendBucketUses.get(bucketKey) ?? 0;
|
|
31713
33021
|
bendBucketUses.set(bucketKey, useIdx + 1);
|
|
31714
33022
|
const sign = useIdx % 2 === 0 ? 1 : -1;
|
|
31715
|
-
const stagger = Math.ceil(useIdx / 2) *
|
|
33023
|
+
const stagger = Math.ceil(useIdx / 2) * C3.EDGE_BEND_STAGGER * sign;
|
|
31716
33024
|
const midX = baseMidX + stagger;
|
|
31717
33025
|
const path2 = `M ${aAnchor.x} ${aAnchor.y} L ${midX} ${aAnchor.y} L ${midX} ${bAnchor.y} L ${bAnchor.x} ${bAnchor.y}`;
|
|
31718
33026
|
return {
|
|
31719
33027
|
path: path2,
|
|
31720
33028
|
fromAnchor: { x: aAnchor.x, y: aAnchor.y, side: aSide },
|
|
31721
33029
|
toAnchor: { x: bAnchor.x, y: bAnchor.y, side: bSide },
|
|
31722
|
-
labelAt: { x: midX, y: (aAnchor.y + bAnchor.y) / 2 -
|
|
33030
|
+
labelAt: { x: midX, y: (aAnchor.y + bAnchor.y) / 2 - C3.LABEL_OFFSET }
|
|
31723
33031
|
};
|
|
31724
33032
|
} else {
|
|
31725
33033
|
const baseMidY = (aAnchor.y + bAnchor.y) / 2;
|
|
@@ -31727,14 +33035,14 @@ function routeOrthogonal(a, b, fromCol, toCol, bendBucketUses) {
|
|
|
31727
33035
|
const useIdx = bendBucketUses.get(bucketKey) ?? 0;
|
|
31728
33036
|
bendBucketUses.set(bucketKey, useIdx + 1);
|
|
31729
33037
|
const sign = useIdx % 2 === 0 ? 1 : -1;
|
|
31730
|
-
const stagger = Math.ceil(useIdx / 2) *
|
|
33038
|
+
const stagger = Math.ceil(useIdx / 2) * C3.EDGE_BEND_STAGGER * sign;
|
|
31731
33039
|
const midY = baseMidY + stagger;
|
|
31732
33040
|
const path2 = `M ${aAnchor.x} ${aAnchor.y} L ${aAnchor.x} ${midY} L ${bAnchor.x} ${midY} L ${bAnchor.x} ${bAnchor.y}`;
|
|
31733
33041
|
return {
|
|
31734
33042
|
path: path2,
|
|
31735
33043
|
fromAnchor: { x: aAnchor.x, y: aAnchor.y, side: aSide },
|
|
31736
33044
|
toAnchor: { x: bAnchor.x, y: bAnchor.y, side: bSide },
|
|
31737
|
-
labelAt: { x: (aAnchor.x + bAnchor.x) / 2, y: midY -
|
|
33045
|
+
labelAt: { x: (aAnchor.x + bAnchor.x) / 2, y: midY - C3.LABEL_OFFSET }
|
|
31738
33046
|
};
|
|
31739
33047
|
}
|
|
31740
33048
|
}
|
|
@@ -31785,7 +33093,7 @@ function attrMarkers(a) {
|
|
|
31785
33093
|
return out;
|
|
31786
33094
|
}
|
|
31787
33095
|
function renderEntity(e) {
|
|
31788
|
-
const
|
|
33096
|
+
const C3 = ERD_CONST;
|
|
31789
33097
|
const body = [];
|
|
31790
33098
|
body.push(
|
|
31791
33099
|
rect({
|
|
@@ -31821,9 +33129,9 @@ function renderEntity(e) {
|
|
|
31821
33129
|
body.push(
|
|
31822
33130
|
line({
|
|
31823
33131
|
x1: e.x,
|
|
31824
|
-
y1: e.y + e.headerHeight + i *
|
|
33132
|
+
y1: e.y + e.headerHeight + i * C3.ROW_HEIGHT,
|
|
31825
33133
|
x2: e.x + e.width,
|
|
31826
|
-
y2: e.y + e.headerHeight + i *
|
|
33134
|
+
y2: e.y + e.headerHeight + i * C3.ROW_HEIGHT,
|
|
31827
33135
|
class: "lt-erd-row-divider"
|
|
31828
33136
|
})
|
|
31829
33137
|
);
|
|
@@ -31831,7 +33139,7 @@ function renderEntity(e) {
|
|
|
31831
33139
|
body.push(
|
|
31832
33140
|
text(
|
|
31833
33141
|
{
|
|
31834
|
-
x: e.x +
|
|
33142
|
+
x: e.x + C3.ENTITY_PADDING_X,
|
|
31835
33143
|
y: cy,
|
|
31836
33144
|
class: a.pk ? "lt-erd-attr-name-pk" : "lt-erd-attr-name"
|
|
31837
33145
|
},
|
|
@@ -31842,7 +33150,7 @@ function renderEntity(e) {
|
|
|
31842
33150
|
const markerW = 26;
|
|
31843
33151
|
const markerGap = 4;
|
|
31844
33152
|
const markersBlockW = markers6.length * markerW + (markers6.length - 1) * markerGap;
|
|
31845
|
-
const markersStartX = e.x + e.width -
|
|
33153
|
+
const markersStartX = e.x + e.width - C3.ENTITY_PADDING_X - markersBlockW;
|
|
31846
33154
|
if (a.type) {
|
|
31847
33155
|
body.push(
|
|
31848
33156
|
text(
|
|
@@ -31890,25 +33198,25 @@ function renderEntity(e) {
|
|
|
31890
33198
|
);
|
|
31891
33199
|
}
|
|
31892
33200
|
function renderGlyph2(ax, ay, dirX, dirY, card) {
|
|
31893
|
-
const
|
|
33201
|
+
const C3 = ERD_CONST;
|
|
31894
33202
|
const px = -dirY;
|
|
31895
33203
|
const py = dirX;
|
|
31896
|
-
const barDist =
|
|
33204
|
+
const barDist = C3.GLYPH_OFFSET;
|
|
31897
33205
|
const barX = ax + dirX * barDist;
|
|
31898
33206
|
const barY = ay + dirY * barDist;
|
|
31899
33207
|
const footTipX = ax;
|
|
31900
33208
|
const footTipY = ay;
|
|
31901
|
-
const footBaseX = ax + dirX *
|
|
31902
|
-
const footBaseY = ay + dirY *
|
|
33209
|
+
const footBaseX = ax + dirX * C3.GLYPH_FOOT_LEN;
|
|
33210
|
+
const footBaseY = ay + dirY * C3.GLYPH_FOOT_LEN;
|
|
31903
33211
|
const parts = [];
|
|
31904
33212
|
switch (card) {
|
|
31905
33213
|
case "one-mandatory": {
|
|
31906
33214
|
parts.push(
|
|
31907
33215
|
line({
|
|
31908
|
-
x1: barX + px *
|
|
31909
|
-
y1: barY + py *
|
|
31910
|
-
x2: barX - px *
|
|
31911
|
-
y2: barY - py *
|
|
33216
|
+
x1: barX + px * C3.GLYPH_BAR_HALF,
|
|
33217
|
+
y1: barY + py * C3.GLYPH_BAR_HALF,
|
|
33218
|
+
x2: barX - px * C3.GLYPH_BAR_HALF,
|
|
33219
|
+
y2: barY - py * C3.GLYPH_BAR_HALF,
|
|
31912
33220
|
class: "lt-erd-glyph"
|
|
31913
33221
|
})
|
|
31914
33222
|
);
|
|
@@ -31919,7 +33227,7 @@ function renderGlyph2(ax, ay, dirX, dirY, card) {
|
|
|
31919
33227
|
circle({
|
|
31920
33228
|
cx: barX,
|
|
31921
33229
|
cy: barY,
|
|
31922
|
-
r:
|
|
33230
|
+
r: C3.GLYPH_CIRCLE_R,
|
|
31923
33231
|
class: "lt-erd-glyph-circle"
|
|
31924
33232
|
})
|
|
31925
33233
|
);
|
|
@@ -31928,10 +33236,10 @@ function renderGlyph2(ax, ay, dirX, dirY, card) {
|
|
|
31928
33236
|
case "many-mandatory": {
|
|
31929
33237
|
parts.push(
|
|
31930
33238
|
line({
|
|
31931
|
-
x1: barX + px *
|
|
31932
|
-
y1: barY + py *
|
|
31933
|
-
x2: barX - px *
|
|
31934
|
-
y2: barY - py *
|
|
33239
|
+
x1: barX + px * C3.GLYPH_BAR_HALF,
|
|
33240
|
+
y1: barY + py * C3.GLYPH_BAR_HALF,
|
|
33241
|
+
x2: barX - px * C3.GLYPH_BAR_HALF,
|
|
33242
|
+
y2: barY - py * C3.GLYPH_BAR_HALF,
|
|
31935
33243
|
class: "lt-erd-glyph"
|
|
31936
33244
|
})
|
|
31937
33245
|
);
|
|
@@ -31942,8 +33250,8 @@ function renderGlyph2(ax, ay, dirX, dirY, card) {
|
|
|
31942
33250
|
line({
|
|
31943
33251
|
x1: footBaseX,
|
|
31944
33252
|
y1: footBaseY,
|
|
31945
|
-
x2: footTipX + px *
|
|
31946
|
-
y2: footTipY + py *
|
|
33253
|
+
x2: footTipX + px * C3.GLYPH_BAR_HALF,
|
|
33254
|
+
y2: footTipY + py * C3.GLYPH_BAR_HALF,
|
|
31947
33255
|
class: "lt-erd-glyph"
|
|
31948
33256
|
})
|
|
31949
33257
|
);
|
|
@@ -31951,8 +33259,8 @@ function renderGlyph2(ax, ay, dirX, dirY, card) {
|
|
|
31951
33259
|
line({
|
|
31952
33260
|
x1: footBaseX,
|
|
31953
33261
|
y1: footBaseY,
|
|
31954
|
-
x2: footTipX - px *
|
|
31955
|
-
y2: footTipY - py *
|
|
33262
|
+
x2: footTipX - px * C3.GLYPH_BAR_HALF,
|
|
33263
|
+
y2: footTipY - py * C3.GLYPH_BAR_HALF,
|
|
31956
33264
|
class: "lt-erd-glyph"
|
|
31957
33265
|
})
|
|
31958
33266
|
);
|
|
@@ -31963,7 +33271,7 @@ function renderGlyph2(ax, ay, dirX, dirY, card) {
|
|
|
31963
33271
|
circle({
|
|
31964
33272
|
cx: barX,
|
|
31965
33273
|
cy: barY,
|
|
31966
|
-
r:
|
|
33274
|
+
r: C3.GLYPH_CIRCLE_R,
|
|
31967
33275
|
class: "lt-erd-glyph-circle"
|
|
31968
33276
|
})
|
|
31969
33277
|
);
|
|
@@ -31974,8 +33282,8 @@ function renderGlyph2(ax, ay, dirX, dirY, card) {
|
|
|
31974
33282
|
line({
|
|
31975
33283
|
x1: footBaseX,
|
|
31976
33284
|
y1: footBaseY,
|
|
31977
|
-
x2: footTipX + px *
|
|
31978
|
-
y2: footTipY + py *
|
|
33285
|
+
x2: footTipX + px * C3.GLYPH_BAR_HALF,
|
|
33286
|
+
y2: footTipY + py * C3.GLYPH_BAR_HALF,
|
|
31979
33287
|
class: "lt-erd-glyph"
|
|
31980
33288
|
})
|
|
31981
33289
|
);
|
|
@@ -31983,8 +33291,8 @@ function renderGlyph2(ax, ay, dirX, dirY, card) {
|
|
|
31983
33291
|
line({
|
|
31984
33292
|
x1: footBaseX,
|
|
31985
33293
|
y1: footBaseY,
|
|
31986
|
-
x2: footTipX - px *
|
|
31987
|
-
y2: footTipY - py *
|
|
33294
|
+
x2: footTipX - px * C3.GLYPH_BAR_HALF,
|
|
33295
|
+
y2: footTipY - py * C3.GLYPH_BAR_HALF,
|
|
31988
33296
|
class: "lt-erd-glyph"
|
|
31989
33297
|
})
|
|
31990
33298
|
);
|
|
@@ -32129,7 +33437,7 @@ var BreadboardParseError = class extends Error {
|
|
|
32129
33437
|
}
|
|
32130
33438
|
lineNumber;
|
|
32131
33439
|
};
|
|
32132
|
-
function
|
|
33440
|
+
function stripComment16(s) {
|
|
32133
33441
|
let out = "";
|
|
32134
33442
|
let inQuote = false;
|
|
32135
33443
|
for (let i = 0; i < s.length; i++) {
|
|
@@ -32150,7 +33458,7 @@ function unquote8(v) {
|
|
|
32150
33458
|
}
|
|
32151
33459
|
function lex2(text2) {
|
|
32152
33460
|
return text2.split(/\r?\n/).map((raw, i) => ({
|
|
32153
|
-
text:
|
|
33461
|
+
text: stripComment16(raw).trimEnd().replace(/^\s+/, ""),
|
|
32154
33462
|
lineNumber: i + 1
|
|
32155
33463
|
})).filter((l) => l.text.length > 0);
|
|
32156
33464
|
}
|
|
@@ -34091,7 +35399,7 @@ function layerPool(ast, pool, colByObj) {
|
|
|
34091
35399
|
}
|
|
34092
35400
|
}
|
|
34093
35401
|
}
|
|
34094
|
-
function
|
|
35402
|
+
function fmt7(n) {
|
|
34095
35403
|
return (Math.round(n * 100) / 100).toString();
|
|
34096
35404
|
}
|
|
34097
35405
|
function routeSequenceFlow(f, objCenter, objById) {
|
|
@@ -34112,11 +35420,11 @@ function routeSequenceFlow(f, objCenter, objById) {
|
|
|
34112
35420
|
let labelAnchor;
|
|
34113
35421
|
if (Math.abs(dx) >= Math.abs(dy)) {
|
|
34114
35422
|
const midX = (from.x + to.x) / 2;
|
|
34115
|
-
path2 = `M ${
|
|
35423
|
+
path2 = `M ${fmt7(from.x)} ${fmt7(from.y)} L ${fmt7(midX)} ${fmt7(from.y)} L ${fmt7(midX)} ${fmt7(to.y)} L ${fmt7(to.x)} ${fmt7(to.y)}`;
|
|
34116
35424
|
labelAnchor = { x: midX, y: (from.y + to.y) / 2 - 6 };
|
|
34117
35425
|
} else {
|
|
34118
35426
|
const midY = (from.y + to.y) / 2;
|
|
34119
|
-
path2 = `M ${
|
|
35427
|
+
path2 = `M ${fmt7(from.x)} ${fmt7(from.y)} L ${fmt7(from.x)} ${fmt7(midY)} L ${fmt7(to.x)} ${fmt7(midY)} L ${fmt7(to.x)} ${fmt7(to.y)}`;
|
|
34120
35428
|
labelAnchor = { x: (from.x + to.x) / 2, y: midY - 6 };
|
|
34121
35429
|
}
|
|
34122
35430
|
return { flow: f, path: path2, labelAnchor };
|
|
@@ -34139,7 +35447,7 @@ function routeMessageFlow(f, objCenter, poolByLabel) {
|
|
|
34139
35447
|
const A = endpoint(f.from);
|
|
34140
35448
|
const B = endpoint(f.to);
|
|
34141
35449
|
const midY = (A.y + B.y) / 2;
|
|
34142
|
-
const path2 = `M ${
|
|
35450
|
+
const path2 = `M ${fmt7(A.x)} ${fmt7(A.y)} L ${fmt7(A.x)} ${fmt7(midY)} L ${fmt7(B.x)} ${fmt7(midY)} L ${fmt7(B.x)} ${fmt7(B.y)}`;
|
|
34143
35451
|
return { flow: f, path: path2, labelAnchor: { x: (A.x + B.x) / 2, y: midY - 6 } };
|
|
34144
35452
|
}
|
|
34145
35453
|
|
|
@@ -41089,6 +42397,7 @@ var plugins = [
|
|
|
41089
42397
|
eventtree,
|
|
41090
42398
|
fmea,
|
|
41091
42399
|
rbd,
|
|
42400
|
+
comparison,
|
|
41092
42401
|
causalloop,
|
|
41093
42402
|
markov,
|
|
41094
42403
|
gitgraph,
|
|
@@ -41245,6 +42554,6 @@ function renderWithPlugin(prepared, plugin, config) {
|
|
|
41245
42554
|
return plugin.render(prepared, renderConfig);
|
|
41246
42555
|
}
|
|
41247
42556
|
|
|
41248
|
-
export { FLOORPLAN_SYMBOLS, GEOMETRY, bowtie2 as bowtie, causalloop, decisiontree, drawDeviceIcon, epc, eventtree, faulttree, fmea, gitgraph, iconSize, idef0, markov, network, parse, parseResult, pert, petri, pid, prisma, rbd, render, renderEquip, renderPreview, renderResult, sequence, state, threatmodel, timeline, umlclass, usecase, welding };
|
|
41249
|
-
//# sourceMappingURL=chunk-
|
|
41250
|
-
//# sourceMappingURL=chunk-
|
|
42557
|
+
export { FLOORPLAN_SYMBOLS, GEOMETRY, bowtie2 as bowtie, causalloop, comparison, decisiontree, drawDeviceIcon, epc, eventtree, faulttree, fmea, gitgraph, iconSize, idef0, markov, network, parse, parseResult, pert, petri, pid, prisma, rbd, render, renderEquip, renderPreview, renderResult, sequence, state, threatmodel, timeline, umlclass, usecase, welding };
|
|
42558
|
+
//# sourceMappingURL=chunk-4QLIFOKH.js.map
|
|
42559
|
+
//# sourceMappingURL=chunk-4QLIFOKH.js.map
|