schematex 0.9.4 → 0.9.6
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 +45 -0
- package/dist/ai/ai-sdk.cjs +8 -8
- package/dist/ai/ai-sdk.d.cts +3 -3
- package/dist/ai/ai-sdk.d.ts +3 -3
- package/dist/ai/ai-sdk.js +3 -3
- package/dist/ai/index.cjs +17 -17
- package/dist/ai/index.d.cts +4 -4
- package/dist/ai/index.d.ts +4 -4
- package/dist/ai/index.js +4 -4
- package/dist/{api-1xoGiseb.d.cts → api-BOJJlNb1.d.ts} +2 -2
- package/dist/{api-CgXRSnCn.d.ts → api-v9t1T1v6.d.cts} +2 -2
- package/dist/browser.cjs +9 -9
- package/dist/browser.d.cts +3 -3
- package/dist/browser.d.ts +3 -3
- package/dist/browser.js +3 -3
- package/dist/{chunk-UFXDAIDD.js → chunk-4W75FGWO.js} +1714 -658
- package/dist/chunk-4W75FGWO.js.map +1 -0
- package/dist/{chunk-NIYB6CHH.js → chunk-CVTHUOAM.js} +265 -15
- package/dist/chunk-CVTHUOAM.js.map +1 -0
- package/dist/{chunk-TX3YWZZX.cjs → chunk-HX64QWB6.cjs} +267 -17
- package/dist/chunk-HX64QWB6.cjs.map +1 -0
- package/dist/{chunk-PFZKW3HE.js → chunk-II4GLKGF.js} +2 -2
- package/dist/chunk-II4GLKGF.js.map +1 -0
- package/dist/{chunk-GTCAJPQR.cjs → chunk-KH5GRKUM.cjs} +1715 -658
- package/dist/chunk-KH5GRKUM.cjs.map +1 -0
- package/dist/{chunk-WJXLF42K.cjs → chunk-N3HU635X.cjs} +2 -2
- package/dist/chunk-N3HU635X.cjs.map +1 -0
- package/dist/{diagnostics-CDwnQ65n.d.cts → diagnostics-5bVLlGNj.d.cts} +1 -1
- package/dist/{diagnostics-CDwnQ65n.d.ts → diagnostics-5bVLlGNj.d.ts} +1 -1
- package/dist/diagrams/blockdiagram/index.d.cts +1 -1
- package/dist/diagrams/blockdiagram/index.d.ts +1 -1
- package/dist/diagrams/circuit/index.d.cts +1 -1
- package/dist/diagrams/circuit/index.d.ts +1 -1
- package/dist/diagrams/ecomap/index.d.cts +1 -1
- package/dist/diagrams/ecomap/index.d.ts +1 -1
- package/dist/diagrams/entity/index.d.cts +1 -1
- package/dist/diagrams/entity/index.d.ts +1 -1
- package/dist/diagrams/fishbone/index.d.cts +1 -1
- package/dist/diagrams/fishbone/index.d.ts +1 -1
- package/dist/diagrams/flowchart/index.d.cts +2 -2
- package/dist/diagrams/flowchart/index.d.ts +2 -2
- package/dist/diagrams/genogram/index.d.cts +1 -1
- package/dist/diagrams/genogram/index.d.ts +1 -1
- package/dist/diagrams/ladder/index.d.cts +1 -1
- package/dist/diagrams/ladder/index.d.ts +1 -1
- package/dist/diagrams/logic/index.d.cts +1 -1
- package/dist/diagrams/logic/index.d.ts +1 -1
- package/dist/diagrams/orgchart/index.d.cts +1 -1
- package/dist/diagrams/orgchart/index.d.ts +1 -1
- package/dist/diagrams/pedigree/index.d.cts +1 -1
- package/dist/diagrams/pedigree/index.d.ts +1 -1
- package/dist/diagrams/phylo/index.d.cts +1 -1
- package/dist/diagrams/phylo/index.d.ts +1 -1
- package/dist/diagrams/sld/index.cjs +7 -7
- package/dist/diagrams/sld/index.d.cts +1 -1
- package/dist/diagrams/sld/index.d.ts +1 -1
- package/dist/diagrams/sld/index.js +1 -1
- package/dist/diagrams/sociogram/index.d.cts +1 -1
- package/dist/diagrams/sociogram/index.d.ts +1 -1
- package/dist/diagrams/timing/index.d.cts +1 -1
- package/dist/diagrams/timing/index.d.ts +1 -1
- package/dist/diagrams/venn/index.d.cts +1 -1
- package/dist/diagrams/venn/index.d.ts +1 -1
- package/dist/{index-DNOoLmYX.d.cts → index-Cmf4Rcve.d.cts} +1 -1
- package/dist/{index-CYSH3_ca.d.ts → index-syc0E5Ss.d.ts} +1 -1
- package/dist/index.cjs +41 -37
- package/dist/index.d.cts +7 -5
- package/dist/index.d.ts +7 -5
- package/dist/index.js +4 -4
- package/dist/react.cjs +3 -3
- package/dist/react.d.cts +2 -2
- package/dist/react.d.ts +2 -2
- package/dist/react.js +2 -2
- package/dist/{tools-CbYmQ3hH.d.cts → tools-B98iarLm.d.cts} +2 -2
- package/dist/{tools-BhTti-oG.d.ts → tools-CCZ1IcIN.d.ts} +2 -2
- package/package.json +1 -1
- package/dist/chunk-GTCAJPQR.cjs.map +0 -1
- package/dist/chunk-NIYB6CHH.js.map +0 -1
- package/dist/chunk-PFZKW3HE.js.map +0 -1
- package/dist/chunk-TX3YWZZX.cjs.map +0 -1
- package/dist/chunk-UFXDAIDD.js.map +0 -1
- package/dist/chunk-WJXLF42K.cjs.map +0 -1
|
@@ -2,7 +2,7 @@ import { orgchart } from './chunk-3J4DZPZC.js';
|
|
|
2
2
|
import { circuit } from './chunk-RDYACU2G.js';
|
|
3
3
|
import { blockdiagram } from './chunk-3PH2MQGN.js';
|
|
4
4
|
import { ladder } from './chunk-B4CMWA6Y.js';
|
|
5
|
-
import { sld } from './chunk-
|
|
5
|
+
import { sld } from './chunk-II4GLKGF.js';
|
|
6
6
|
import { entity } from './chunk-JEMAOC2D.js';
|
|
7
7
|
import { fishbone } from './chunk-GYYYULBL.js';
|
|
8
8
|
import { venn } from './chunk-SXOAAQNY.js';
|
|
@@ -2754,8 +2754,8 @@ function renderEras(layout, theme) {
|
|
|
2754
2754
|
layout.eras.forEach((e, i) => {
|
|
2755
2755
|
const l = leftmostOnRow.get(e.bandRow);
|
|
2756
2756
|
if (l === void 0 || e.x < layout.eras[l].x) leftmostOnRow.set(e.bandRow, i);
|
|
2757
|
-
const
|
|
2758
|
-
if (
|
|
2757
|
+
const r7 = rightmostOnRow.get(e.bandRow);
|
|
2758
|
+
if (r7 === void 0 || e.x + e.width > layout.eras[r7].x + layout.eras[r7].width) rightmostOnRow.set(e.bandRow, i);
|
|
2759
2759
|
});
|
|
2760
2760
|
const plotEnd = layout.plotX + layout.plotW;
|
|
2761
2761
|
const items = layout.eras.map((e, i) => {
|
|
@@ -2881,20 +2881,20 @@ function renderSwimlanePoints(layout, theme) {
|
|
|
2881
2881
|
function renderMarker(ev, color, shape, isMilestone) {
|
|
2882
2882
|
const x = ev.x;
|
|
2883
2883
|
const y = ev.y;
|
|
2884
|
-
const
|
|
2884
|
+
const r7 = isMilestone ? 8 : 5;
|
|
2885
2885
|
const klass = isMilestone ? "st-milestone" : "st-event-dot";
|
|
2886
2886
|
switch (shape) {
|
|
2887
2887
|
case "square":
|
|
2888
|
-
return rect({ x: x -
|
|
2888
|
+
return rect({ x: x - r7, y: y - r7, width: r7 * 2, height: r7 * 2, fill: color, class: klass, "data-event-id": ev.event.id });
|
|
2889
2889
|
case "diamond":
|
|
2890
|
-
return path({ d: `M ${x},${y -
|
|
2890
|
+
return path({ d: `M ${x},${y - r7} L ${x + r7},${y} L ${x},${y + r7} L ${x - r7},${y} Z`, fill: color, class: klass, "data-event-id": ev.event.id });
|
|
2891
2891
|
case "star":
|
|
2892
|
-
return path({ d: starPath(x, y,
|
|
2892
|
+
return path({ d: starPath(x, y, r7 + 2, (r7 + 2) / 2.5, 5), fill: color, class: klass, "data-event-id": ev.event.id });
|
|
2893
2893
|
case "flag":
|
|
2894
|
-
return path({ d: `M ${x -
|
|
2894
|
+
return path({ d: `M ${x - r7},${y + r7} L ${x - r7},${y - r7 - 4} L ${x + r7 + 4},${y - r7 - 1} L ${x - r7},${y + 2}`, fill: color, class: klass, "data-event-id": ev.event.id });
|
|
2895
2895
|
case "circle":
|
|
2896
2896
|
default:
|
|
2897
|
-
return circle({ cx: x, cy: y, r:
|
|
2897
|
+
return circle({ cx: x, cy: y, r: r7, fill: color, class: klass, "data-event-id": ev.event.id });
|
|
2898
2898
|
}
|
|
2899
2899
|
}
|
|
2900
2900
|
function renderLabels(layout) {
|
|
@@ -3150,10 +3150,10 @@ function starPath(cx, cy, rOuter, rInner, points) {
|
|
|
3150
3150
|
const step = Math.PI / points;
|
|
3151
3151
|
let d = "";
|
|
3152
3152
|
for (let i = 0; i < points * 2; i++) {
|
|
3153
|
-
const
|
|
3153
|
+
const r7 = i % 2 === 0 ? rOuter : rInner;
|
|
3154
3154
|
const a = i * step - Math.PI / 2;
|
|
3155
|
-
const x = cx +
|
|
3156
|
-
const y = cy +
|
|
3155
|
+
const x = cx + r7 * Math.cos(a);
|
|
3156
|
+
const y = cy + r7 * Math.sin(a);
|
|
3157
3157
|
d += (i === 0 ? "M" : "L") + x.toFixed(2) + "," + y.toFixed(2) + " ";
|
|
3158
3158
|
}
|
|
3159
3159
|
return d + "Z";
|
|
@@ -3424,7 +3424,7 @@ function parseStateDiagram(src) {
|
|
|
3424
3424
|
}
|
|
3425
3425
|
ctxTop.regionMode = true;
|
|
3426
3426
|
if (!parent.regions) parent.regions = [];
|
|
3427
|
-
const lastIdx = parent.regions.reduce((s,
|
|
3427
|
+
const lastIdx = parent.regions.reduce((s, r7) => s + r7.length, 0);
|
|
3428
3428
|
const slice = parent.children.slice(lastIdx);
|
|
3429
3429
|
parent.regions.push(slice);
|
|
3430
3430
|
i++;
|
|
@@ -3628,7 +3628,7 @@ function parseStateDiagram(src) {
|
|
|
3628
3628
|
}
|
|
3629
3629
|
function finalizeRegions(node) {
|
|
3630
3630
|
if (node.regions) {
|
|
3631
|
-
const consumed = node.regions.reduce((s,
|
|
3631
|
+
const consumed = node.regions.reduce((s, r7) => s + r7.length, 0);
|
|
3632
3632
|
if (node.children.length > consumed) {
|
|
3633
3633
|
node.regions.push(node.children.slice(consumed));
|
|
3634
3634
|
}
|
|
@@ -4073,33 +4073,33 @@ function pointsToPath(pts) {
|
|
|
4073
4073
|
const rest = pts.slice(1).map((p) => `L ${p.x} ${p.y}`).join(" ");
|
|
4074
4074
|
return rest ? `${head} ${rest}` : head;
|
|
4075
4075
|
}
|
|
4076
|
-
function trimPathStart(d, cx, cy,
|
|
4076
|
+
function trimPathStart(d, cx, cy, r7) {
|
|
4077
4077
|
const pts = parsePathPoints(d);
|
|
4078
4078
|
if (!pts || pts.length < 2) return d;
|
|
4079
4079
|
const p0 = pts[0];
|
|
4080
4080
|
const p1 = pts[1];
|
|
4081
|
-
const newP0 = projectOnPerimeter(p0, p1, cx, cy,
|
|
4081
|
+
const newP0 = projectOnPerimeter(p0, p1, cx, cy, r7);
|
|
4082
4082
|
pts[0] = newP0;
|
|
4083
4083
|
return pointsToPath(pts);
|
|
4084
4084
|
}
|
|
4085
|
-
function trimPathEnd(d, cx, cy,
|
|
4085
|
+
function trimPathEnd(d, cx, cy, r7) {
|
|
4086
4086
|
const pts = parsePathPoints(d);
|
|
4087
4087
|
if (!pts || pts.length < 2) return d;
|
|
4088
4088
|
const last = pts[pts.length - 1];
|
|
4089
4089
|
const prev = pts[pts.length - 2];
|
|
4090
|
-
const newLast = projectOnPerimeter(last, prev, cx, cy,
|
|
4090
|
+
const newLast = projectOnPerimeter(last, prev, cx, cy, r7);
|
|
4091
4091
|
pts[pts.length - 1] = newLast;
|
|
4092
4092
|
return pointsToPath(pts);
|
|
4093
4093
|
}
|
|
4094
|
-
function projectOnPerimeter(endpoint, neighbor, cx, cy,
|
|
4094
|
+
function projectOnPerimeter(endpoint, neighbor, cx, cy, r7) {
|
|
4095
4095
|
const dx = endpoint.x - neighbor.x;
|
|
4096
4096
|
const dy = endpoint.y - neighbor.y;
|
|
4097
4097
|
if (Math.abs(dx) > Math.abs(dy)) {
|
|
4098
4098
|
const sign2 = dx >= 0 ? 1 : -1;
|
|
4099
|
-
return { x: cx - sign2 *
|
|
4099
|
+
return { x: cx - sign2 * r7, y: cy };
|
|
4100
4100
|
}
|
|
4101
4101
|
const sign = dy >= 0 ? 1 : -1;
|
|
4102
|
-
return { x: cx, y: cy - sign *
|
|
4102
|
+
return { x: cx, y: cy - sign * r7 };
|
|
4103
4103
|
}
|
|
4104
4104
|
function shiftPathX(d, dx) {
|
|
4105
4105
|
return d.replace(/([MLCQ])\s*((?:-?\d+(?:\.\d+)?\s+){1,5}-?\d+(?:\.\d+)?)/g, (_, cmd, args) => {
|
|
@@ -4277,12 +4277,12 @@ function renderPseudo(node) {
|
|
|
4277
4277
|
]
|
|
4278
4278
|
);
|
|
4279
4279
|
case "choice": {
|
|
4280
|
-
const
|
|
4280
|
+
const r7 = 14;
|
|
4281
4281
|
return group(
|
|
4282
4282
|
{ class: "lt-state lt-pseudo", "data-id": node.id, "data-kind": "choice" },
|
|
4283
4283
|
[
|
|
4284
4284
|
polygon({
|
|
4285
|
-
points: `${cx},${cy -
|
|
4285
|
+
points: `${cx},${cy - r7} ${cx + r7},${cy} ${cx},${cy + r7} ${cx - r7},${cy}`,
|
|
4286
4286
|
class: "lt-ps-choice"
|
|
4287
4287
|
})
|
|
4288
4288
|
]
|
|
@@ -5280,27 +5280,27 @@ function renderEquip(type, label, rawType) {
|
|
|
5280
5280
|
]);
|
|
5281
5281
|
}
|
|
5282
5282
|
case "pump_centrifugal": {
|
|
5283
|
-
const
|
|
5283
|
+
const r7 = 22;
|
|
5284
5284
|
return group({}, [
|
|
5285
|
-
circle({ cx: 0, cy: 0, r:
|
|
5285
|
+
circle({ cx: 0, cy: 0, r: r7, class: "lt-pid-equip" }),
|
|
5286
5286
|
polygon({
|
|
5287
|
-
points: `${
|
|
5287
|
+
points: `${r7 * 0.4},${-r7 * 0.9} ${r7 + 6},${-r7 * 0.9} ${r7 * 0.4},${0}`,
|
|
5288
5288
|
class: "lt-pid-equip"
|
|
5289
5289
|
}),
|
|
5290
5290
|
text(
|
|
5291
|
-
{ x: 0, y:
|
|
5291
|
+
{ x: 0, y: r7 + 14, "text-anchor": "middle", class: "lt-pid-equip-tag" },
|
|
5292
5292
|
label
|
|
5293
5293
|
)
|
|
5294
5294
|
]);
|
|
5295
5295
|
}
|
|
5296
5296
|
case "pump_pd": {
|
|
5297
|
-
const
|
|
5297
|
+
const r7 = 22;
|
|
5298
5298
|
return group({}, [
|
|
5299
|
-
circle({ cx: 0, cy: 0, r:
|
|
5299
|
+
circle({ cx: 0, cy: 0, r: r7, class: "lt-pid-equip" }),
|
|
5300
5300
|
circle({ cx: -8, cy: 0, r: 6, class: "lt-pid-tray-line", fill: "none" }),
|
|
5301
5301
|
circle({ cx: 8, cy: 0, r: 6, class: "lt-pid-tray-line", fill: "none" }),
|
|
5302
5302
|
text(
|
|
5303
|
-
{ x: 0, y:
|
|
5303
|
+
{ x: 0, y: r7 + 14, "text-anchor": "middle", class: "lt-pid-equip-tag" },
|
|
5304
5304
|
label
|
|
5305
5305
|
)
|
|
5306
5306
|
]);
|
|
@@ -5315,14 +5315,14 @@ function renderEquip(type, label, rawType) {
|
|
|
5315
5315
|
]);
|
|
5316
5316
|
}
|
|
5317
5317
|
case "blower": {
|
|
5318
|
-
const
|
|
5318
|
+
const r7 = 22;
|
|
5319
5319
|
return group({}, [
|
|
5320
|
-
circle({ cx: 0, cy: 0, r:
|
|
5320
|
+
circle({ cx: 0, cy: 0, r: r7, class: "lt-pid-equip" }),
|
|
5321
5321
|
path({
|
|
5322
|
-
d: `M 0 0 L ${
|
|
5322
|
+
d: `M 0 0 L ${r7 * 0.8} ${-r7 * 0.5} M 0 0 L ${-r7 * 0.6} ${-r7 * 0.6} M 0 0 L 0 ${r7 * 0.8}`,
|
|
5323
5323
|
class: "lt-pid-tray-line"
|
|
5324
5324
|
}),
|
|
5325
|
-
text({ x: 0, y:
|
|
5325
|
+
text({ x: 0, y: r7 + 14, "text-anchor": "middle", class: "lt-pid-equip-tag" }, label)
|
|
5326
5326
|
]);
|
|
5327
5327
|
}
|
|
5328
5328
|
case "reactor_cstr": {
|
|
@@ -5498,7 +5498,7 @@ function renderEquip(type, label, rawType) {
|
|
|
5498
5498
|
}
|
|
5499
5499
|
}
|
|
5500
5500
|
function renderInstrument(category, letterCode, loopNumber) {
|
|
5501
|
-
const
|
|
5501
|
+
const r7 = 14;
|
|
5502
5502
|
const isComputer = category.endsWith("computer");
|
|
5503
5503
|
const isPlc = category.endsWith("plc");
|
|
5504
5504
|
const isShared = category.endsWith("shared");
|
|
@@ -5506,17 +5506,17 @@ function renderInstrument(category, letterCode, loopNumber) {
|
|
|
5506
5506
|
const isLocal = category.startsWith("local_");
|
|
5507
5507
|
const parts = [];
|
|
5508
5508
|
if (isComputer) {
|
|
5509
|
-
parts.push(circle({ cx: 0, cy: 0, r:
|
|
5509
|
+
parts.push(circle({ cx: 0, cy: 0, r: r7, class: "lt-inst-body" }));
|
|
5510
5510
|
parts.push(
|
|
5511
5511
|
polygon({
|
|
5512
|
-
points: `0,${-
|
|
5512
|
+
points: `0,${-r7 + 1} ${r7 - 1},0 0,${r7 - 1} ${ -13},0`,
|
|
5513
5513
|
class: "lt-inst-body",
|
|
5514
5514
|
fill: "none"
|
|
5515
5515
|
})
|
|
5516
5516
|
);
|
|
5517
5517
|
} else if (isPlc) {
|
|
5518
|
-
parts.push(circle({ cx: 0, cy: 0, r:
|
|
5519
|
-
const side =
|
|
5518
|
+
parts.push(circle({ cx: 0, cy: 0, r: r7, class: "lt-inst-body" }));
|
|
5519
|
+
const side = r7 * Math.SQRT1_2 * 2 - 2;
|
|
5520
5520
|
parts.push(
|
|
5521
5521
|
rect({
|
|
5522
5522
|
x: -side / 2,
|
|
@@ -5528,11 +5528,11 @@ function renderInstrument(category, letterCode, loopNumber) {
|
|
|
5528
5528
|
})
|
|
5529
5529
|
);
|
|
5530
5530
|
} else if (isShared) {
|
|
5531
|
-
parts.push(circle({ cx: 0, cy: 0, r:
|
|
5531
|
+
parts.push(circle({ cx: 0, cy: 0, r: r7, class: "lt-inst-body" }));
|
|
5532
5532
|
const hex = [];
|
|
5533
5533
|
for (let i = 0; i < 6; i++) {
|
|
5534
5534
|
const a = Math.PI / 3 * i - Math.PI / 2;
|
|
5535
|
-
hex.push(`${(
|
|
5535
|
+
hex.push(`${(r7 - 2) * Math.cos(a)},${(r7 - 2) * Math.sin(a)}`);
|
|
5536
5536
|
}
|
|
5537
5537
|
parts.push(
|
|
5538
5538
|
polygon({
|
|
@@ -5542,12 +5542,12 @@ function renderInstrument(category, letterCode, loopNumber) {
|
|
|
5542
5542
|
})
|
|
5543
5543
|
);
|
|
5544
5544
|
} else {
|
|
5545
|
-
parts.push(circle({ cx: 0, cy: 0, r:
|
|
5545
|
+
parts.push(circle({ cx: 0, cy: 0, r: r7, class: "lt-inst-body" }));
|
|
5546
5546
|
}
|
|
5547
5547
|
if (isControlRoom) {
|
|
5548
|
-
parts.push(line({ x1: -
|
|
5548
|
+
parts.push(line({ x1: -r7, y1: 0, x2: r7, y2: 0, class: "lt-inst-cr-line" }));
|
|
5549
5549
|
} else if (isLocal) {
|
|
5550
|
-
parts.push(line({ x1: -
|
|
5550
|
+
parts.push(line({ x1: -r7, y1: 0, x2: r7, y2: 0, class: "lt-inst-local-line" }));
|
|
5551
5551
|
}
|
|
5552
5552
|
parts.push(
|
|
5553
5553
|
text(
|
|
@@ -6299,19 +6299,19 @@ function readScalar(map, key) {
|
|
|
6299
6299
|
return { value, line: entry.header.line };
|
|
6300
6300
|
}
|
|
6301
6301
|
function readInt(map, key) {
|
|
6302
|
-
const
|
|
6303
|
-
if (
|
|
6304
|
-
return parseInt10(
|
|
6302
|
+
const r7 = readScalar(map, key);
|
|
6303
|
+
if (r7 === void 0) return void 0;
|
|
6304
|
+
return parseInt10(r7.value, r7.line);
|
|
6305
6305
|
}
|
|
6306
6306
|
function readSources(map, key) {
|
|
6307
|
-
const
|
|
6308
|
-
if (
|
|
6309
|
-
return parsePairs(
|
|
6307
|
+
const r7 = readScalar(map, key);
|
|
6308
|
+
if (r7 === void 0) return void 0;
|
|
6309
|
+
return parsePairs(r7.value, r7.line);
|
|
6310
6310
|
}
|
|
6311
6311
|
function readReasons(map, key) {
|
|
6312
|
-
const
|
|
6313
|
-
if (
|
|
6314
|
-
return parsePairs(
|
|
6312
|
+
const r7 = readScalar(map, key);
|
|
6313
|
+
if (r7 === void 0) return void 0;
|
|
6314
|
+
return parsePairs(r7.value, r7.line);
|
|
6315
6315
|
}
|
|
6316
6316
|
function readBlock(map, key) {
|
|
6317
6317
|
const entry = map.get(key);
|
|
@@ -6639,7 +6639,7 @@ function runArithmeticValidation(ast) {
|
|
|
6639
6639
|
}
|
|
6640
6640
|
}
|
|
6641
6641
|
if (ast.screening.excluded.reasons && ast.screening.excluded.reasons.length > 0) {
|
|
6642
|
-
const sum = ast.screening.excluded.reasons.reduce((a,
|
|
6642
|
+
const sum = ast.screening.excluded.reasons.reduce((a, r7) => a + r7.count, 0);
|
|
6643
6643
|
if (sum !== screenedExcluded) {
|
|
6644
6644
|
issues.push(
|
|
6645
6645
|
`screening.excluded reasons sum to ${formatN(sum)} but n = ${formatN(screenedExcluded)}`
|
|
@@ -6647,7 +6647,7 @@ function runArithmeticValidation(ast) {
|
|
|
6647
6647
|
}
|
|
6648
6648
|
}
|
|
6649
6649
|
if (ast.eligibility.excluded.reasons && ast.eligibility.excluded.reasons.length > 0) {
|
|
6650
|
-
const sum = ast.eligibility.excluded.reasons.reduce((a,
|
|
6650
|
+
const sum = ast.eligibility.excluded.reasons.reduce((a, r7) => a + r7.count, 0);
|
|
6651
6651
|
if (sum !== eligExcluded) {
|
|
6652
6652
|
issues.push(
|
|
6653
6653
|
`eligibility.excluded reasons sum to ${formatN(sum)} but n = ${formatN(eligExcluded)}`
|
|
@@ -6740,7 +6740,7 @@ function aggregateReasons(reasons) {
|
|
|
6740
6740
|
const sorted = [...reasons].sort((a, b) => b.count - a.count);
|
|
6741
6741
|
const head = sorted.slice(0, PRISMA_CONST.MAX_REASON_LINES - 1);
|
|
6742
6742
|
const tail = sorted.slice(PRISMA_CONST.MAX_REASON_LINES - 1);
|
|
6743
|
-
const otherSum = tail.reduce((a,
|
|
6743
|
+
const otherSum = tail.reduce((a, r7) => a + r7.count, 0);
|
|
6744
6744
|
return {
|
|
6745
6745
|
lines: [...head, { name: `Other (${tail.length} reasons)`, count: otherSum }],
|
|
6746
6746
|
truncated: tail.length
|
|
@@ -6797,8 +6797,8 @@ function buildIdentificationRemovedBox(id, kind) {
|
|
|
6797
6797
|
}
|
|
6798
6798
|
if (removed.length === 0) return null;
|
|
6799
6799
|
const lines = [{ text: v.recordsRemovedLabel, style: "label" }];
|
|
6800
|
-
for (const
|
|
6801
|
-
lines.push({ text:
|
|
6800
|
+
for (const r7 of removed) {
|
|
6801
|
+
lines.push({ text: r7, style: "reason", indent: 1 });
|
|
6802
6802
|
}
|
|
6803
6803
|
return {
|
|
6804
6804
|
role: "id-removed",
|
|
@@ -6854,8 +6854,8 @@ function buildScreeningExcludedBox(n, reasons, kind) {
|
|
|
6854
6854
|
{ text: v.recordsExcluded, style: "label" },
|
|
6855
6855
|
{ text: `n = ${nFmt(n)}`, style: "count" }
|
|
6856
6856
|
];
|
|
6857
|
-
for (const
|
|
6858
|
-
out.push({ text: `${
|
|
6857
|
+
for (const r7 of items) {
|
|
6858
|
+
out.push({ text: `${r7.name} (n = ${nFmt(r7.count)})`, style: "reason", indent: 1 });
|
|
6859
6859
|
}
|
|
6860
6860
|
return {
|
|
6861
6861
|
role: "screening-excluded",
|
|
@@ -6885,8 +6885,8 @@ function buildEligibilityExcludedBox(n, reasons, kind) {
|
|
|
6885
6885
|
{ text: v.reportsExcluded, style: "label" },
|
|
6886
6886
|
{ text: `n = ${nFmt(n)}`, style: "count" }
|
|
6887
6887
|
];
|
|
6888
|
-
for (const
|
|
6889
|
-
out.push({ text: `${
|
|
6888
|
+
for (const r7 of items) {
|
|
6889
|
+
out.push({ text: `${r7.name} (n = ${nFmt(r7.count)})`, style: "reason", indent: 1 });
|
|
6890
6890
|
}
|
|
6891
6891
|
return {
|
|
6892
6892
|
role: "eligibility-excluded",
|
|
@@ -7487,7 +7487,7 @@ function classForEdge(kind) {
|
|
|
7487
7487
|
}
|
|
7488
7488
|
}
|
|
7489
7489
|
function renderBand(band) {
|
|
7490
|
-
const
|
|
7490
|
+
const r7 = rect({
|
|
7491
7491
|
x: band.x,
|
|
7492
7492
|
y: band.y,
|
|
7493
7493
|
width: band.width,
|
|
@@ -7510,10 +7510,10 @@ function renderBand(band) {
|
|
|
7510
7510
|
},
|
|
7511
7511
|
band.label
|
|
7512
7512
|
);
|
|
7513
|
-
return group({ "data-band": band.stage }, [
|
|
7513
|
+
return group({ "data-band": band.stage }, [r7, txt]);
|
|
7514
7514
|
}
|
|
7515
7515
|
function renderHeader(h) {
|
|
7516
|
-
const
|
|
7516
|
+
const r7 = rect({
|
|
7517
7517
|
x: h.x,
|
|
7518
7518
|
y: h.y,
|
|
7519
7519
|
width: h.width,
|
|
@@ -7538,10 +7538,10 @@ function renderHeader(h) {
|
|
|
7538
7538
|
ln
|
|
7539
7539
|
)
|
|
7540
7540
|
);
|
|
7541
|
-
return group({ "data-header": h.column }, [
|
|
7541
|
+
return group({ "data-header": h.column }, [r7, ...lines]);
|
|
7542
7542
|
}
|
|
7543
7543
|
function renderBox(box2) {
|
|
7544
|
-
const
|
|
7544
|
+
const r7 = rect({
|
|
7545
7545
|
x: box2.x,
|
|
7546
7546
|
y: box2.y,
|
|
7547
7547
|
width: box2.width,
|
|
@@ -7599,7 +7599,7 @@ function renderBox(box2) {
|
|
|
7599
7599
|
"data-prisma-variant": box2.variant,
|
|
7600
7600
|
"data-prisma-stage": box2.stage
|
|
7601
7601
|
},
|
|
7602
|
-
[
|
|
7602
|
+
[r7, ...textEls]
|
|
7603
7603
|
);
|
|
7604
7604
|
}
|
|
7605
7605
|
function approxLineWidth(line2) {
|
|
@@ -8308,14 +8308,14 @@ function sizeEllipse(uc) {
|
|
|
8308
8308
|
}
|
|
8309
8309
|
function buildDeepEdges(ast, ucIds) {
|
|
8310
8310
|
const edges = [];
|
|
8311
|
-
for (const
|
|
8312
|
-
if (!ucIds.has(
|
|
8313
|
-
if (
|
|
8314
|
-
edges.push({ from:
|
|
8315
|
-
} else if (
|
|
8316
|
-
edges.push({ from:
|
|
8317
|
-
} else if (
|
|
8318
|
-
edges.push({ from:
|
|
8311
|
+
for (const r7 of ast.relations) {
|
|
8312
|
+
if (!ucIds.has(r7.source) || !ucIds.has(r7.target)) continue;
|
|
8313
|
+
if (r7.kind === "include") {
|
|
8314
|
+
edges.push({ from: r7.source, to: r7.target });
|
|
8315
|
+
} else if (r7.kind === "extend") {
|
|
8316
|
+
edges.push({ from: r7.target, to: r7.source });
|
|
8317
|
+
} else if (r7.kind === "generalization") {
|
|
8318
|
+
edges.push({ from: r7.source, to: r7.target });
|
|
8319
8319
|
}
|
|
8320
8320
|
}
|
|
8321
8321
|
return edges;
|
|
@@ -8343,15 +8343,15 @@ function classifyActorSides(ast) {
|
|
|
8343
8343
|
ast.actors.forEach((a, i) => idx.set(a.id, i));
|
|
8344
8344
|
const parent = /* @__PURE__ */ new Map();
|
|
8345
8345
|
const find = (x) => {
|
|
8346
|
-
let
|
|
8347
|
-
while ((parent.get(
|
|
8346
|
+
let r7 = x;
|
|
8347
|
+
while ((parent.get(r7) ?? r7) !== r7) r7 = parent.get(r7) ?? r7;
|
|
8348
8348
|
let c = x;
|
|
8349
8349
|
while ((parent.get(c) ?? c) !== c) {
|
|
8350
8350
|
const next = parent.get(c) ?? c;
|
|
8351
|
-
parent.set(c,
|
|
8351
|
+
parent.set(c, r7);
|
|
8352
8352
|
c = next;
|
|
8353
8353
|
}
|
|
8354
|
-
return
|
|
8354
|
+
return r7;
|
|
8355
8355
|
};
|
|
8356
8356
|
const union = (a, b) => {
|
|
8357
8357
|
const ra = find(a);
|
|
@@ -8361,9 +8361,9 @@ function classifyActorSides(ast) {
|
|
|
8361
8361
|
else parent.set(ra, rb);
|
|
8362
8362
|
};
|
|
8363
8363
|
for (const a of ast.actors) parent.set(a.id, a.id);
|
|
8364
|
-
for (const
|
|
8365
|
-
if (
|
|
8366
|
-
union(
|
|
8364
|
+
for (const r7 of ast.relations) {
|
|
8365
|
+
if (r7.kind === "generalization" && actorIds.has(r7.source) && actorIds.has(r7.target)) {
|
|
8366
|
+
union(r7.source, r7.target);
|
|
8367
8367
|
}
|
|
8368
8368
|
}
|
|
8369
8369
|
const baseSide = (a, i) => a.side === "left" ? "left" : a.side === "right" ? "right" : i === 0 ? "left" : "right";
|
|
@@ -8398,10 +8398,10 @@ function layoutUsecase(ast) {
|
|
|
8398
8398
|
const sides = classifyActorSides(ast);
|
|
8399
8399
|
const connectedActors = /* @__PURE__ */ new Map();
|
|
8400
8400
|
for (const u of ast.usecases) connectedActors.set(u.id, []);
|
|
8401
|
-
for (const
|
|
8402
|
-
if (
|
|
8403
|
-
const aId = actorById.has(
|
|
8404
|
-
const uId = ucIds.has(
|
|
8401
|
+
for (const r7 of ast.relations) {
|
|
8402
|
+
if (r7.kind !== "association" && r7.kind !== "directed") continue;
|
|
8403
|
+
const aId = actorById.has(r7.source) ? r7.source : actorById.has(r7.target) ? r7.target : null;
|
|
8404
|
+
const uId = ucIds.has(r7.source) ? r7.source : ucIds.has(r7.target) ? r7.target : null;
|
|
8405
8405
|
if (aId && uId) connectedActors.get(uId).push(aId);
|
|
8406
8406
|
}
|
|
8407
8407
|
const columns = [];
|
|
@@ -8440,10 +8440,10 @@ function layoutUsecase(ast) {
|
|
|
8440
8440
|
});
|
|
8441
8441
|
let prev = -Infinity;
|
|
8442
8442
|
for (const u of col) {
|
|
8443
|
-
let
|
|
8444
|
-
if (
|
|
8445
|
-
rowPos.set(u.id,
|
|
8446
|
-
prev =
|
|
8443
|
+
let r7 = rowPos.get(u.id);
|
|
8444
|
+
if (r7 <= prev) r7 = prev + 1;
|
|
8445
|
+
rowPos.set(u.id, r7);
|
|
8446
|
+
prev = r7;
|
|
8447
8447
|
}
|
|
8448
8448
|
}
|
|
8449
8449
|
const colMaxRx = columns.map(
|
|
@@ -8589,10 +8589,10 @@ function layoutUsecase(ast) {
|
|
|
8589
8589
|
const edges = [];
|
|
8590
8590
|
const trees = [];
|
|
8591
8591
|
const genByParent = /* @__PURE__ */ new Map();
|
|
8592
|
-
for (const
|
|
8593
|
-
if (
|
|
8594
|
-
if (!genByParent.has(
|
|
8595
|
-
genByParent.get(
|
|
8592
|
+
for (const r7 of ast.relations) {
|
|
8593
|
+
if (r7.kind !== "generalization") continue;
|
|
8594
|
+
if (!genByParent.has(r7.target)) genByParent.set(r7.target, []);
|
|
8595
|
+
genByParent.get(r7.target).push(r7);
|
|
8596
8596
|
}
|
|
8597
8597
|
const handledGen = /* @__PURE__ */ new Set();
|
|
8598
8598
|
function nodeCenter(id) {
|
|
@@ -8626,11 +8626,11 @@ function layoutUsecase(ast) {
|
|
|
8626
8626
|
}
|
|
8627
8627
|
for (const [parentId, rels] of genByParent) {
|
|
8628
8628
|
const useTree = ast.generalizationTree && rels.length >= C2.GEN_TREE_THRESHOLD;
|
|
8629
|
-
const allActors = actorById2.has(parentId) && rels.every((
|
|
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";
|
|
8632
8632
|
const pAnchor = actorGenAnchor(parentId, side);
|
|
8633
|
-
const childAnchors = rels.map((
|
|
8633
|
+
const childAnchors = rels.map((r7) => ({ r: r7, p: actorGenAnchor(r7.source, side) }));
|
|
8634
8634
|
const xs = [pAnchor.x, ...childAnchors.map((c) => c.p.x)];
|
|
8635
8635
|
const ys = [pAnchor.y, ...childAnchors.map((c) => c.p.y)];
|
|
8636
8636
|
const busX = side === "left" ? Math.min(...xs) - 20 : Math.max(...xs) + 20;
|
|
@@ -8646,7 +8646,7 @@ function layoutUsecase(ast) {
|
|
|
8646
8646
|
}
|
|
8647
8647
|
trees.push({
|
|
8648
8648
|
parentId,
|
|
8649
|
-
childIds: rels.map((
|
|
8649
|
+
childIds: rels.map((r7) => r7.source),
|
|
8650
8650
|
stemX: busX,
|
|
8651
8651
|
stemTop: minY2,
|
|
8652
8652
|
stemBottom: maxY2,
|
|
@@ -8669,7 +8669,7 @@ function layoutUsecase(ast) {
|
|
|
8669
8669
|
if (!useTree) continue;
|
|
8670
8670
|
const parent = nodeCenter(parentId);
|
|
8671
8671
|
if (!parent) continue;
|
|
8672
|
-
const childCenters = rels.map((
|
|
8672
|
+
const childCenters = rels.map((r7) => nodeCenter(r7.source)).filter((c) => c !== null);
|
|
8673
8673
|
if (childCenters.length === 0) continue;
|
|
8674
8674
|
const avgX = childCenters.reduce((s, c) => s + c.cx, 0) / childCenters.length;
|
|
8675
8675
|
const avgY = childCenters.reduce((s, c) => s + c.cy, 0) / childCenters.length;
|
|
@@ -8680,14 +8680,14 @@ function layoutUsecase(ast) {
|
|
|
8680
8680
|
const jx = pPt.x + dirX / len * C2.GEN_JUNCTION_OFFSET;
|
|
8681
8681
|
const jy = pPt.y + dirY / len * C2.GEN_JUNCTION_OFFSET;
|
|
8682
8682
|
const legPaths = [];
|
|
8683
|
-
for (const
|
|
8684
|
-
const cPt = perimeter(
|
|
8683
|
+
for (const r7 of rels) {
|
|
8684
|
+
const cPt = perimeter(r7.source, jx, jy);
|
|
8685
8685
|
legPaths.push(`M ${round3(cPt.x)} ${round3(cPt.y)} L ${round3(jx)} ${round3(jy)}`);
|
|
8686
|
-
handledGen.add(
|
|
8686
|
+
handledGen.add(r7);
|
|
8687
8687
|
}
|
|
8688
8688
|
trees.push({
|
|
8689
8689
|
parentId,
|
|
8690
|
-
childIds: rels.map((
|
|
8690
|
+
childIds: rels.map((r7) => r7.source),
|
|
8691
8691
|
stemX: jx,
|
|
8692
8692
|
stemTop: jy,
|
|
8693
8693
|
stemBottom: jy,
|
|
@@ -8695,72 +8695,72 @@ function layoutUsecase(ast) {
|
|
|
8695
8695
|
legPaths
|
|
8696
8696
|
});
|
|
8697
8697
|
}
|
|
8698
|
-
for (const
|
|
8699
|
-
if (handledGen.has(
|
|
8700
|
-
const a = nodeCenter(
|
|
8701
|
-
const b = nodeCenter(
|
|
8698
|
+
for (const r7 of ast.relations) {
|
|
8699
|
+
if (handledGen.has(r7)) continue;
|
|
8700
|
+
const a = nodeCenter(r7.source);
|
|
8701
|
+
const b = nodeCenter(r7.target);
|
|
8702
8702
|
if (!a || !b) continue;
|
|
8703
|
-
if (
|
|
8704
|
-
const side = sides.get(
|
|
8705
|
-
const pAnchor = actorGenAnchor(
|
|
8706
|
-
const cAnchor = actorGenAnchor(
|
|
8703
|
+
if (r7.kind === "generalization" && actorById2.has(r7.source) && actorById2.has(r7.target)) {
|
|
8704
|
+
const side = sides.get(r7.target) ?? "left";
|
|
8705
|
+
const pAnchor = actorGenAnchor(r7.target, side);
|
|
8706
|
+
const cAnchor = actorGenAnchor(r7.source, side);
|
|
8707
8707
|
const busX = side === "left" ? Math.min(pAnchor.x, cAnchor.x) - 20 : Math.max(pAnchor.x, cAnchor.x) + 20;
|
|
8708
8708
|
edges.push({
|
|
8709
|
-
relation:
|
|
8709
|
+
relation: r7,
|
|
8710
8710
|
d: `M ${round3(cAnchor.x)} ${round3(cAnchor.y)} L ${round3(busX)} ${round3(cAnchor.y)} L ${round3(busX)} ${round3(pAnchor.y)} L ${round3(pAnchor.x)} ${round3(pAnchor.y)}`,
|
|
8711
8711
|
arrowKind: "hollow",
|
|
8712
8712
|
dashed: false
|
|
8713
8713
|
});
|
|
8714
8714
|
continue;
|
|
8715
8715
|
}
|
|
8716
|
-
const srcActor = actorById2.get(
|
|
8717
|
-
const tgtActor = actorById2.get(
|
|
8716
|
+
const srcActor = actorById2.get(r7.source);
|
|
8717
|
+
const tgtActor = actorById2.get(r7.target);
|
|
8718
8718
|
let pa;
|
|
8719
8719
|
let pb;
|
|
8720
8720
|
if (srcActor && !tgtActor) {
|
|
8721
8721
|
pa = { x: srcActor.anchorX, y: srcActor.anchorY };
|
|
8722
|
-
pb = perimeter(
|
|
8722
|
+
pb = perimeter(r7.target, pa.x, pa.y);
|
|
8723
8723
|
} else if (tgtActor && !srcActor) {
|
|
8724
8724
|
pb = { x: tgtActor.anchorX, y: tgtActor.anchorY };
|
|
8725
|
-
pa = perimeter(
|
|
8725
|
+
pa = perimeter(r7.source, pb.x, pb.y);
|
|
8726
8726
|
} else {
|
|
8727
|
-
pa = perimeter(
|
|
8728
|
-
pb = perimeter(
|
|
8727
|
+
pa = perimeter(r7.source, b.cx, b.cy);
|
|
8728
|
+
pb = perimeter(r7.target, a.cx, a.cy);
|
|
8729
8729
|
}
|
|
8730
|
-
const dashed =
|
|
8730
|
+
const dashed = r7.kind === "include" || r7.kind === "extend";
|
|
8731
8731
|
let arrowKind2 = "none";
|
|
8732
|
-
if (
|
|
8733
|
-
else if (
|
|
8732
|
+
if (r7.kind === "directed" || r7.kind === "include" || r7.kind === "extend") arrowKind2 = "open";
|
|
8733
|
+
else if (r7.kind === "generalization") arrowKind2 = "hollow";
|
|
8734
8734
|
const edge = {
|
|
8735
|
-
relation:
|
|
8735
|
+
relation: r7,
|
|
8736
8736
|
d: `M ${round3(pa.x)} ${round3(pa.y)} L ${round3(pb.x)} ${round3(pb.y)}`,
|
|
8737
8737
|
arrowKind: arrowKind2,
|
|
8738
8738
|
dashed
|
|
8739
8739
|
};
|
|
8740
|
-
if (
|
|
8740
|
+
if (r7.kind === "include" || r7.kind === "extend") {
|
|
8741
8741
|
const rows = [];
|
|
8742
|
-
const keyword =
|
|
8743
|
-
rows.push(`\xAB${
|
|
8744
|
-
if (
|
|
8745
|
-
if (
|
|
8742
|
+
const keyword = r7.kind === "include" ? "include" : "extend";
|
|
8743
|
+
rows.push(`\xAB${r7.stereotype ?? keyword}\xBB`);
|
|
8744
|
+
if (r7.condition) rows.push(`[${r7.condition}]`);
|
|
8745
|
+
if (r7.extensionPointRef) rows.push(`(extension point: ${r7.extensionPointRef})`);
|
|
8746
8746
|
const label = {
|
|
8747
8747
|
rows,
|
|
8748
8748
|
cx: (pa.x + pb.x) / 2,
|
|
8749
8749
|
cy: (pa.y + pb.y) / 2
|
|
8750
8750
|
};
|
|
8751
8751
|
edge.label = label;
|
|
8752
|
-
} else if ((
|
|
8752
|
+
} else if ((r7.kind === "association" || r7.kind === "directed") && r7.stereotype) {
|
|
8753
8753
|
edge.label = {
|
|
8754
|
-
rows: [`\xAB${
|
|
8754
|
+
rows: [`\xAB${r7.stereotype}\xBB`],
|
|
8755
8755
|
cx: (pa.x + pb.x) / 2,
|
|
8756
8756
|
cy: (pa.y + pb.y) / 2
|
|
8757
8757
|
};
|
|
8758
8758
|
}
|
|
8759
|
-
if (
|
|
8760
|
-
edge.multiplicityFrom = placeMultiplicity(pa, pb,
|
|
8759
|
+
if (r7.sourceMultiplicity) {
|
|
8760
|
+
edge.multiplicityFrom = placeMultiplicity(pa, pb, r7.sourceMultiplicity);
|
|
8761
8761
|
}
|
|
8762
|
-
if (
|
|
8763
|
-
edge.multiplicityTo = placeMultiplicity(pb, pa,
|
|
8762
|
+
if (r7.targetMultiplicity) {
|
|
8763
|
+
edge.multiplicityTo = placeMultiplicity(pb, pa, r7.targetMultiplicity);
|
|
8764
8764
|
}
|
|
8765
8765
|
edges.push(edge);
|
|
8766
8766
|
}
|
|
@@ -9015,7 +9015,7 @@ function renderEdgeLabel(e) {
|
|
|
9015
9015
|
const rows = e.label.rows;
|
|
9016
9016
|
const lineH = 12;
|
|
9017
9017
|
const totalH = rows.length * lineH;
|
|
9018
|
-
const widest = rows.reduce((m,
|
|
9018
|
+
const widest = rows.reduce((m, r7) => Math.max(m, r7.length), 0);
|
|
9019
9019
|
const pillW = widest * 6 + 8;
|
|
9020
9020
|
const pillH = totalH + 4;
|
|
9021
9021
|
const startY = e.label.cy - totalH / 2 + 9;
|
|
@@ -9031,7 +9031,7 @@ function renderEdgeLabel(e) {
|
|
|
9031
9031
|
ry: 4
|
|
9032
9032
|
})
|
|
9033
9033
|
];
|
|
9034
|
-
rows.forEach((
|
|
9034
|
+
rows.forEach((r7, i) => {
|
|
9035
9035
|
parts.push(
|
|
9036
9036
|
text(
|
|
9037
9037
|
{
|
|
@@ -9040,7 +9040,7 @@ function renderEdgeLabel(e) {
|
|
|
9040
9040
|
y: startY + i * lineH,
|
|
9041
9041
|
"text-anchor": "middle"
|
|
9042
9042
|
},
|
|
9043
|
-
|
|
9043
|
+
r7
|
|
9044
9044
|
)
|
|
9045
9045
|
);
|
|
9046
9046
|
});
|
|
@@ -9080,8 +9080,8 @@ function renderTree(tr) {
|
|
|
9080
9080
|
function renderUsecaseLayout(layout, config) {
|
|
9081
9081
|
const t = resolveBaseTheme(config?.theme ?? "default");
|
|
9082
9082
|
const children = [];
|
|
9083
|
-
const nInclude = layout.ast.relations.filter((
|
|
9084
|
-
const nExtend = layout.ast.relations.filter((
|
|
9083
|
+
const nInclude = layout.ast.relations.filter((r7) => r7.kind === "include").length;
|
|
9084
|
+
const nExtend = layout.ast.relations.filter((r7) => r7.kind === "extend").length;
|
|
9085
9085
|
children.push(title(`Use Case Diagram${layout.title ? " \u2014 " + layout.title : ""}`));
|
|
9086
9086
|
children.push(
|
|
9087
9087
|
desc(
|
|
@@ -9258,8 +9258,8 @@ function parseHeaderLine(ln, ast) {
|
|
|
9258
9258
|
}
|
|
9259
9259
|
case "layout": {
|
|
9260
9260
|
const l = value.toLowerCase();
|
|
9261
|
-
if (l !== "network" && l !== "timescaled" && l !== "aoa") {
|
|
9262
|
-
throw new PertParseError(`layout must be network, timescaled, or
|
|
9261
|
+
if (l !== "network" && l !== "timescaled" && l !== "aoa" && l !== "gantt") {
|
|
9262
|
+
throw new PertParseError(`layout must be network, timescaled, aoa, or gantt (got '${value}')`, ln.line);
|
|
9263
9263
|
}
|
|
9264
9264
|
ast.layout = l;
|
|
9265
9265
|
return true;
|
|
@@ -9270,6 +9270,26 @@ function parseHeaderLine(ln, ast) {
|
|
|
9270
9270
|
case "show-sentinels":
|
|
9271
9271
|
ast.showSentinels = /^(true|yes|on)$/i.test(value);
|
|
9272
9272
|
return true;
|
|
9273
|
+
case "start":
|
|
9274
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(value)) {
|
|
9275
|
+
throw new PertParseError(`start must be a date 'YYYY-MM-DD' (got '${value}')`, ln.line);
|
|
9276
|
+
}
|
|
9277
|
+
ast.start = value;
|
|
9278
|
+
return true;
|
|
9279
|
+
case "calendar": {
|
|
9280
|
+
const c = value.toLowerCase();
|
|
9281
|
+
if (c !== "continuous" && c !== "5day" && c !== "7day") {
|
|
9282
|
+
throw new PertParseError(`calendar must be continuous, 7day, or 5day (got '${value}')`, ln.line);
|
|
9283
|
+
}
|
|
9284
|
+
ast.calendar = c === "5day" ? "5day" : "continuous";
|
|
9285
|
+
return true;
|
|
9286
|
+
}
|
|
9287
|
+
case "today":
|
|
9288
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(value)) {
|
|
9289
|
+
throw new PertParseError(`today must be a date 'YYYY-MM-DD' (got '${value}')`, ln.line);
|
|
9290
|
+
}
|
|
9291
|
+
ast.today = value;
|
|
9292
|
+
return true;
|
|
9273
9293
|
default:
|
|
9274
9294
|
return false;
|
|
9275
9295
|
}
|
|
@@ -9334,7 +9354,7 @@ function parseDepRef(raw, unit, lineNo) {
|
|
|
9334
9354
|
}
|
|
9335
9355
|
throw new PertParseError(`cannot parse predecessor reference '${ref}'`, lineNo);
|
|
9336
9356
|
}
|
|
9337
|
-
var KEY_RE = /\b(duration|after|tags|class|lane)\s*:/gi;
|
|
9357
|
+
var KEY_RE = /\b(duration|after|tags|class|lane|progress|done)\s*:/gi;
|
|
9338
9358
|
function parseTaskLine(ln, ast) {
|
|
9339
9359
|
const head = ln.text.match(/^task\s+(\S+)\s*(.*)$/i);
|
|
9340
9360
|
if (!head) {
|
|
@@ -9409,6 +9429,13 @@ function parseTaskLine(ln, ast) {
|
|
|
9409
9429
|
const tags = values.tags ? values.tags.split(",").map((t) => t.trim()).filter(Boolean) : [];
|
|
9410
9430
|
const className = values.class ? values.class.trim() : void 0;
|
|
9411
9431
|
const lane = values.lane ? stripQuotes3(values.lane) : void 0;
|
|
9432
|
+
const progressRaw = values.progress ?? values.done;
|
|
9433
|
+
let progress;
|
|
9434
|
+
if (progressRaw !== void 0 && progressRaw !== "") {
|
|
9435
|
+
const pct = progressRaw.trim().replace(/%$/, "");
|
|
9436
|
+
const n = parseNumber(pct, ln.line, "progress");
|
|
9437
|
+
progress = Math.max(0, Math.min(100, n));
|
|
9438
|
+
}
|
|
9412
9439
|
const task = {
|
|
9413
9440
|
id,
|
|
9414
9441
|
label,
|
|
@@ -9422,6 +9449,7 @@ function parseTaskLine(ln, ast) {
|
|
|
9422
9449
|
if (variance !== void 0) task.variance = variance;
|
|
9423
9450
|
if (className) task.className = className;
|
|
9424
9451
|
if (lane) task.lane = lane;
|
|
9452
|
+
if (progress !== void 0) task.progress = progress;
|
|
9425
9453
|
ast.tasks.push(task);
|
|
9426
9454
|
}
|
|
9427
9455
|
function parsePert(src) {
|
|
@@ -9432,18 +9460,21 @@ function parsePert(src) {
|
|
|
9432
9460
|
layout: "network",
|
|
9433
9461
|
criticalTolerance: 0,
|
|
9434
9462
|
showSentinels: false,
|
|
9463
|
+
calendar: "continuous",
|
|
9435
9464
|
tasks: [],
|
|
9436
9465
|
warnings: []
|
|
9437
9466
|
};
|
|
9438
9467
|
const lines = preprocess8(src);
|
|
9439
9468
|
if (lines.length === 0) {
|
|
9440
|
-
throw new PertParseError("empty document \u2014 expected 'pert' header", 1);
|
|
9469
|
+
throw new PertParseError("empty document \u2014 expected 'pert' or 'gantt' header", 1);
|
|
9441
9470
|
}
|
|
9442
9471
|
const first = lines[0];
|
|
9443
|
-
if (!/^pert\b/i.test(first.text)) {
|
|
9444
|
-
throw new PertParseError(`first non-comment line must start with 'pert' (got: ${first.text})`, first.line);
|
|
9472
|
+
if (!/^(pert|gantt)\b/i.test(first.text)) {
|
|
9473
|
+
throw new PertParseError(`first non-comment line must start with 'pert' or 'gantt' (got: ${first.text})`, first.line);
|
|
9445
9474
|
}
|
|
9446
|
-
const
|
|
9475
|
+
const isGanttHeader = /^gantt\b/i.test(first.text);
|
|
9476
|
+
if (isGanttHeader) ast.layout = "gantt";
|
|
9477
|
+
const inlineTitle = first.text.replace(/^(pert|gantt)\b/i, "").trim();
|
|
9447
9478
|
if (inlineTitle) {
|
|
9448
9479
|
const m = inlineTitle.match(/^"([^"]+)"$/) || inlineTitle.match(/^'([^']+)'$/);
|
|
9449
9480
|
if (m) ast.title = m[1];
|
|
@@ -9829,12 +9860,12 @@ function layoutAoa(ast, schedule) {
|
|
|
9829
9860
|
const predEvents = (e) => inAdj[e].map((ai) => arcs[ai].from);
|
|
9830
9861
|
const succEvents = (e) => outAdj[e].map((ai) => arcs[ai].to);
|
|
9831
9862
|
for (let iter = 0; iter < 4; iter++) {
|
|
9832
|
-
for (let
|
|
9833
|
-
layers[
|
|
9863
|
+
for (let r7 = 1; r7 <= maxRank; r7++) {
|
|
9864
|
+
layers[r7] = sortByBary(layers[r7], predEvents, pos);
|
|
9834
9865
|
refresh(layers, pos);
|
|
9835
9866
|
}
|
|
9836
|
-
for (let
|
|
9837
|
-
layers[
|
|
9867
|
+
for (let r7 = maxRank - 1; r7 >= 0; r7--) {
|
|
9868
|
+
layers[r7] = sortByBary(layers[r7], succEvents, pos);
|
|
9838
9869
|
refresh(layers, pos);
|
|
9839
9870
|
}
|
|
9840
9871
|
}
|
|
@@ -9844,12 +9875,12 @@ function layoutAoa(ast, schedule) {
|
|
|
9844
9875
|
const contentH = (maxRows - 1) * AOA.VGAP + 2 * AOA.R;
|
|
9845
9876
|
const cx = new Array(nEvents).fill(0);
|
|
9846
9877
|
const cy = new Array(nEvents).fill(0);
|
|
9847
|
-
for (let
|
|
9848
|
-
const layer = layers[
|
|
9878
|
+
for (let r7 = 0; r7 <= maxRank; r7++) {
|
|
9879
|
+
const layer = layers[r7];
|
|
9849
9880
|
const colH = (layer.length - 1) * AOA.VGAP;
|
|
9850
9881
|
const y0 = topY + AOA.R + (contentH - 2 * AOA.R - colH) / 2;
|
|
9851
9882
|
layer.forEach((e, i) => {
|
|
9852
|
-
cx[e] = AOA.PAD + AOA.R +
|
|
9883
|
+
cx[e] = AOA.PAD + AOA.R + r7 * AOA.COL;
|
|
9853
9884
|
cy[e] = y0 + i * AOA.VGAP;
|
|
9854
9885
|
});
|
|
9855
9886
|
}
|
|
@@ -9911,16 +9942,16 @@ function sortByBary(layer, neighbors, pos) {
|
|
|
9911
9942
|
return { e, i, bary };
|
|
9912
9943
|
}).sort((a, b) => a.bary !== b.bary ? a.bary - b.bary : a.i - b.i).map((x) => x.e);
|
|
9913
9944
|
}
|
|
9914
|
-
function arcGeometry(tx, ty, hx, hy,
|
|
9945
|
+
function arcGeometry(tx, ty, hx, hy, r7) {
|
|
9915
9946
|
const dx = hx - tx;
|
|
9916
9947
|
const dy = hy - ty;
|
|
9917
9948
|
const len = Math.hypot(dx, dy) || 1;
|
|
9918
9949
|
const ux = dx / len;
|
|
9919
9950
|
const uy = dy / len;
|
|
9920
|
-
const sx = tx + ux *
|
|
9921
|
-
const sy = ty + uy *
|
|
9922
|
-
const ex = hx - ux *
|
|
9923
|
-
const ey = hy - uy *
|
|
9951
|
+
const sx = tx + ux * r7;
|
|
9952
|
+
const sy = ty + uy * r7;
|
|
9953
|
+
const ex = hx - ux * r7;
|
|
9954
|
+
const ey = hy - uy * r7;
|
|
9924
9955
|
return { d: `M ${round5(sx)} ${round5(sy)} L ${round5(ex)} ${round5(ey)}`, mx: (sx + ex) / 2, my: (sy + ey) / 2 };
|
|
9925
9956
|
}
|
|
9926
9957
|
function buildAoaSummary(ast, sched) {
|
|
@@ -9993,11 +10024,11 @@ function assignRanks(ast) {
|
|
|
9993
10024
|
if (visiting.has(id)) return 0;
|
|
9994
10025
|
visiting.add(id);
|
|
9995
10026
|
const t = byId.get(id);
|
|
9996
|
-
let
|
|
9997
|
-
for (const dep of t.deps)
|
|
10027
|
+
let r7 = 0;
|
|
10028
|
+
for (const dep of t.deps) r7 = Math.max(r7, compute(dep.pred) + 1);
|
|
9998
10029
|
visiting.delete(id);
|
|
9999
|
-
rank.set(id,
|
|
10000
|
-
return
|
|
10030
|
+
rank.set(id, r7);
|
|
10031
|
+
return r7;
|
|
10001
10032
|
};
|
|
10002
10033
|
let maxRank = 0;
|
|
10003
10034
|
for (const t of ast.tasks) maxRank = Math.max(maxRank, compute(t.id));
|
|
@@ -10043,15 +10074,15 @@ function orderLayers(ast, schedule, rank, maxRank) {
|
|
|
10043
10074
|
return s / neighbors.length;
|
|
10044
10075
|
};
|
|
10045
10076
|
for (let iter = 0; iter < 4; iter++) {
|
|
10046
|
-
for (let
|
|
10047
|
-
layers[
|
|
10077
|
+
for (let r7 = 1; r7 <= maxRank; r7++) {
|
|
10078
|
+
layers[r7] = stableSortByKey(layers[r7], (id) => {
|
|
10048
10079
|
const bc = barycenter(id, pred.get(id));
|
|
10049
10080
|
return crit(id) ? bc - 0.4 : bc;
|
|
10050
10081
|
});
|
|
10051
10082
|
refreshPos();
|
|
10052
10083
|
}
|
|
10053
|
-
for (let
|
|
10054
|
-
layers[
|
|
10084
|
+
for (let r7 = maxRank - 1; r7 >= 0; r7--) {
|
|
10085
|
+
layers[r7] = stableSortByKey(layers[r7], (id) => {
|
|
10055
10086
|
const bc = barycenter(id, succ.get(id));
|
|
10056
10087
|
return crit(id) ? bc - 0.4 : bc;
|
|
10057
10088
|
});
|
|
@@ -10103,9 +10134,9 @@ function layoutNetwork(ast, schedule) {
|
|
|
10103
10134
|
const originCross = dir === "TB" ? C2.PAD : C2.PAD + titleH;
|
|
10104
10135
|
const boxes = [];
|
|
10105
10136
|
const boxById = /* @__PURE__ */ new Map();
|
|
10106
|
-
for (let
|
|
10107
|
-
const layer = layers[
|
|
10108
|
-
const extent = colExtent[
|
|
10137
|
+
for (let r7 = 0; r7 <= maxRank; r7++) {
|
|
10138
|
+
const layer = layers[r7];
|
|
10139
|
+
const extent = colExtent[r7];
|
|
10109
10140
|
const crossStart = originCross + (maxExtent - extent) / 2;
|
|
10110
10141
|
let cursor = crossStart;
|
|
10111
10142
|
for (const id of layer) {
|
|
@@ -10116,12 +10147,12 @@ function layoutNetwork(ast, schedule) {
|
|
|
10116
10147
|
let x;
|
|
10117
10148
|
let y;
|
|
10118
10149
|
if (dir === "TB") {
|
|
10119
|
-
const rankPos = originPrimary +
|
|
10150
|
+
const rankPos = originPrimary + r7 * (C2.BOX_H + C2.H_GAP);
|
|
10120
10151
|
x = cursor + (C2.BOX_W - w) / 2;
|
|
10121
10152
|
y = rankPos;
|
|
10122
10153
|
cursor += C2.BOX_W + C2.H_GAP;
|
|
10123
10154
|
} else {
|
|
10124
|
-
const rankPos = originPrimary +
|
|
10155
|
+
const rankPos = originPrimary + r7 * (C2.BOX_W + C2.H_GAP);
|
|
10125
10156
|
x = rankPos + (C2.BOX_W - w) / 2;
|
|
10126
10157
|
y = cursor;
|
|
10127
10158
|
cursor += C2.BOX_H + C2.V_GAP;
|
|
@@ -10135,7 +10166,7 @@ function layoutNetwork(ast, schedule) {
|
|
|
10135
10166
|
width: w,
|
|
10136
10167
|
height: h,
|
|
10137
10168
|
milestone: t.milestone,
|
|
10138
|
-
rank:
|
|
10169
|
+
rank: r7
|
|
10139
10170
|
};
|
|
10140
10171
|
boxes.push(box2);
|
|
10141
10172
|
boxById.set(id, box2);
|
|
@@ -10295,7 +10326,7 @@ function layoutSwimlane2(ast, schedule) {
|
|
|
10295
10326
|
const crit = (id) => schedule.computed.get(id).critical;
|
|
10296
10327
|
const es = (id) => schedule.computed.get(id).es;
|
|
10297
10328
|
const cell = /* @__PURE__ */ new Map();
|
|
10298
|
-
const key = (lane,
|
|
10329
|
+
const key = (lane, r7) => `${lane}\0${r7}`;
|
|
10299
10330
|
for (const t of ast.tasks) {
|
|
10300
10331
|
const k = key(laneOf.get(t.id), rank.get(t.id));
|
|
10301
10332
|
if (!cell.has(k)) cell.set(k, []);
|
|
@@ -10312,15 +10343,15 @@ function layoutSwimlane2(ast, schedule) {
|
|
|
10312
10343
|
}
|
|
10313
10344
|
const titleH = ast.title ? C2.TITLE_H : 0;
|
|
10314
10345
|
const topY = C2.PAD + titleH;
|
|
10315
|
-
const colX = (
|
|
10346
|
+
const colX = (r7) => C2.LANE_LABEL_W + C2.PAD + r7 * (C2.BOX_W + C2.H_GAP);
|
|
10316
10347
|
const lanes = [];
|
|
10317
10348
|
const laneY = /* @__PURE__ */ new Map();
|
|
10318
10349
|
const laneH = /* @__PURE__ */ new Map();
|
|
10319
10350
|
let cursor = topY;
|
|
10320
10351
|
laneOrder.forEach((lane, i) => {
|
|
10321
10352
|
let stack = 1;
|
|
10322
|
-
for (let
|
|
10323
|
-
const arr = cell.get(key(lane,
|
|
10353
|
+
for (let r7 = 0; r7 <= maxRank; r7++) {
|
|
10354
|
+
const arr = cell.get(key(lane, r7));
|
|
10324
10355
|
if (arr) stack = Math.max(stack, arr.length);
|
|
10325
10356
|
}
|
|
10326
10357
|
const bandH = stack * C2.BOX_H + (stack - 1) * C2.V_GAP + 2 * C2.LANE_PAD;
|
|
@@ -10335,15 +10366,15 @@ function layoutSwimlane2(ast, schedule) {
|
|
|
10335
10366
|
for (const lane of laneOrder) {
|
|
10336
10367
|
const bandTop = laneY.get(lane);
|
|
10337
10368
|
const bandH = laneH.get(lane);
|
|
10338
|
-
for (let
|
|
10339
|
-
const arr = cell.get(key(lane,
|
|
10369
|
+
for (let r7 = 0; r7 <= maxRank; r7++) {
|
|
10370
|
+
const arr = cell.get(key(lane, r7));
|
|
10340
10371
|
if (!arr) continue;
|
|
10341
10372
|
const colInnerH = arr.length * C2.BOX_H + (arr.length - 1) * C2.V_GAP;
|
|
10342
10373
|
const y0 = bandTop + (bandH - colInnerH) / 2;
|
|
10343
10374
|
arr.forEach((id, idx) => {
|
|
10344
10375
|
const t = byId.get(id);
|
|
10345
10376
|
const w = t.milestone ? C2.MS_W : C2.BOX_W;
|
|
10346
|
-
const x = colX(
|
|
10377
|
+
const x = colX(r7) + (C2.BOX_W - w) / 2;
|
|
10347
10378
|
const y = y0 + idx * (C2.BOX_H + C2.V_GAP);
|
|
10348
10379
|
const box2 = {
|
|
10349
10380
|
id,
|
|
@@ -10354,7 +10385,7 @@ function layoutSwimlane2(ast, schedule) {
|
|
|
10354
10385
|
width: w,
|
|
10355
10386
|
height: C2.BOX_H,
|
|
10356
10387
|
milestone: t.milestone,
|
|
10357
|
-
rank:
|
|
10388
|
+
rank: r7
|
|
10358
10389
|
};
|
|
10359
10390
|
boxes.push(box2);
|
|
10360
10391
|
boxById.set(id, box2);
|
|
@@ -10523,10 +10554,381 @@ function layoutPert(ast, schedule) {
|
|
|
10523
10554
|
return layoutNetwork(ast, sched);
|
|
10524
10555
|
}
|
|
10525
10556
|
|
|
10526
|
-
// src/diagrams/pert/
|
|
10557
|
+
// src/diagrams/pert/gantt.ts
|
|
10558
|
+
var PALETTES = {
|
|
10559
|
+
default: {
|
|
10560
|
+
bar: "#cfe0f5",
|
|
10561
|
+
barStroke: "#5b85c0",
|
|
10562
|
+
barDone: "#5b85c0",
|
|
10563
|
+
critBar: "#fbe6e0",
|
|
10564
|
+
critStroke: "#d2604f",
|
|
10565
|
+
critDone: "#d2604f",
|
|
10566
|
+
milestone: "#3c5a80",
|
|
10567
|
+
text: "#234567",
|
|
10568
|
+
subtext: "#728198",
|
|
10569
|
+
axis: "#8497ad",
|
|
10570
|
+
grid: "#e3eaf3",
|
|
10571
|
+
sectionBand: "#eef3fa",
|
|
10572
|
+
sectionText: "#41597a",
|
|
10573
|
+
dep: "#9fb0c6",
|
|
10574
|
+
today: "#d2604f"
|
|
10575
|
+
},
|
|
10576
|
+
monochrome: {
|
|
10577
|
+
bar: "#ffffff",
|
|
10578
|
+
barStroke: "#000000",
|
|
10579
|
+
barDone: "#9a9a9a",
|
|
10580
|
+
critBar: "#ffffff",
|
|
10581
|
+
critStroke: "#000000",
|
|
10582
|
+
critDone: "#000000",
|
|
10583
|
+
milestone: "#000000",
|
|
10584
|
+
text: "#000000",
|
|
10585
|
+
subtext: "#555555",
|
|
10586
|
+
axis: "#000000",
|
|
10587
|
+
grid: "#dddddd",
|
|
10588
|
+
sectionBand: "#f2f2f2",
|
|
10589
|
+
sectionText: "#000000",
|
|
10590
|
+
dep: "#888888",
|
|
10591
|
+
today: "#000000"
|
|
10592
|
+
},
|
|
10593
|
+
dark: {
|
|
10594
|
+
bar: "#37506e",
|
|
10595
|
+
barStroke: "#89b4fa",
|
|
10596
|
+
barDone: "#89b4fa",
|
|
10597
|
+
critBar: "#5a3540",
|
|
10598
|
+
critStroke: "#f38ba8",
|
|
10599
|
+
critDone: "#f38ba8",
|
|
10600
|
+
milestone: "#bac2de",
|
|
10601
|
+
text: "#cdd6f4",
|
|
10602
|
+
subtext: "#9399b2",
|
|
10603
|
+
axis: "#7f849c",
|
|
10604
|
+
grid: "#313244",
|
|
10605
|
+
sectionBand: "#272838",
|
|
10606
|
+
sectionText: "#bac2de",
|
|
10607
|
+
dep: "#6c7086",
|
|
10608
|
+
today: "#f38ba8"
|
|
10609
|
+
}
|
|
10610
|
+
};
|
|
10611
|
+
function ymdToDays(y, m, d) {
|
|
10612
|
+
const yy = m <= 2 ? y - 1 : y;
|
|
10613
|
+
const era = Math.floor((yy >= 0 ? yy : yy - 399) / 400);
|
|
10614
|
+
const yoe = yy - era * 400;
|
|
10615
|
+
const doy = Math.floor((153 * (m > 2 ? m - 3 : m + 9) + 2) / 5) + d - 1;
|
|
10616
|
+
const doe = yoe * 365 + Math.floor(yoe / 4) - Math.floor(yoe / 100) + doy;
|
|
10617
|
+
return era * 146097 + doe - 719468;
|
|
10618
|
+
}
|
|
10619
|
+
function daysToYmd(z) {
|
|
10620
|
+
const zz = z + 719468;
|
|
10621
|
+
const era = Math.floor((zz >= 0 ? zz : zz - 146096) / 146097);
|
|
10622
|
+
const doe = zz - era * 146097;
|
|
10623
|
+
const yoe = Math.floor((doe - Math.floor(doe / 1460) + Math.floor(doe / 36524) - Math.floor(doe / 146096)) / 365);
|
|
10624
|
+
const y = yoe + era * 400;
|
|
10625
|
+
const doy = doe - (365 * yoe + Math.floor(yoe / 4) - Math.floor(yoe / 100));
|
|
10626
|
+
const mp = Math.floor((5 * doy + 2) / 153);
|
|
10627
|
+
const d = doy - Math.floor((153 * mp + 2) / 5) + 1;
|
|
10628
|
+
const m = mp < 10 ? mp + 3 : mp - 9;
|
|
10629
|
+
return { y: m <= 2 ? y + 1 : y, m, d };
|
|
10630
|
+
}
|
|
10631
|
+
function parseISODays(s) {
|
|
10632
|
+
const [y, m, d] = s.split("-").map(Number);
|
|
10633
|
+
return ymdToDays(y, m, d);
|
|
10634
|
+
}
|
|
10635
|
+
function dow(days) {
|
|
10636
|
+
return (days % 7 + 4 + 7e3) % 7;
|
|
10637
|
+
}
|
|
10638
|
+
function isWeekend(days) {
|
|
10639
|
+
const w = dow(days);
|
|
10640
|
+
return w === 0 || w === 6;
|
|
10641
|
+
}
|
|
10642
|
+
function advanceWorking(startDays, n) {
|
|
10643
|
+
let cur = startDays;
|
|
10644
|
+
let left = Math.round(n);
|
|
10645
|
+
const step = left >= 0 ? 1 : -1;
|
|
10646
|
+
left = Math.abs(left);
|
|
10647
|
+
while (left > 0) {
|
|
10648
|
+
cur += step;
|
|
10649
|
+
if (!isWeekend(cur)) left--;
|
|
10650
|
+
}
|
|
10651
|
+
return cur;
|
|
10652
|
+
}
|
|
10653
|
+
var MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
10654
|
+
function fmtDate(days) {
|
|
10655
|
+
const { m, d } = daysToYmd(days);
|
|
10656
|
+
return `${MONTHS[m - 1]} ${d}`;
|
|
10657
|
+
}
|
|
10658
|
+
var G = {
|
|
10659
|
+
PAD: 20,
|
|
10660
|
+
TITLE_H: 30,
|
|
10661
|
+
AXIS_H: 26,
|
|
10662
|
+
ROW_H: 28,
|
|
10663
|
+
BAR_H: 15,
|
|
10664
|
+
SECTION_H: 24,
|
|
10665
|
+
LABEL_MIN: 120,
|
|
10666
|
+
LABEL_MAX: 250,
|
|
10667
|
+
CHAR_W: 6.6,
|
|
10668
|
+
LABEL_PAD: 12,
|
|
10669
|
+
TARGET_CHART_W: 740,
|
|
10670
|
+
MIN_PX_UNIT: 5,
|
|
10671
|
+
MAX_PX_UNIT: 56,
|
|
10672
|
+
FOOTER_H: 28
|
|
10673
|
+
};
|
|
10674
|
+
function renderGantt2(ast, schedule, config) {
|
|
10675
|
+
const base = resolveBaseTheme(config?.theme ?? "default");
|
|
10676
|
+
const themeName = (config?.theme ?? "default") in PALETTES ? config.theme : "default";
|
|
10677
|
+
const P = PALETTES[themeName];
|
|
10678
|
+
const tasks = ast.tasks;
|
|
10679
|
+
const span = Math.max(schedule.projectDuration, 1);
|
|
10680
|
+
const unitToDay = ast.unit === "weeks" ? 7 : 1;
|
|
10681
|
+
const unitToWork = ast.unit === "weeks" ? 5 : 1;
|
|
10682
|
+
const pxUnit = Math.max(G.MIN_PX_UNIT, Math.min(G.MAX_PX_UNIT, G.TARGET_CHART_W / span));
|
|
10683
|
+
const longest = tasks.reduce((mx, t) => Math.max(mx, (t.label ?? t.id).length), 4);
|
|
10684
|
+
const labelW = Math.max(G.LABEL_MIN, Math.min(G.LABEL_MAX, Math.ceil(longest * G.CHAR_W) + 2 * G.LABEL_PAD));
|
|
10685
|
+
const chartX = G.PAD + labelW + 8;
|
|
10686
|
+
const chartW = Math.ceil(span * pxUnit);
|
|
10687
|
+
const hasTitle = !!ast.title;
|
|
10688
|
+
const topY = G.PAD + (hasTitle ? G.TITLE_H : 0);
|
|
10689
|
+
const axisBottom = topY + G.AXIS_H;
|
|
10690
|
+
const rows = [];
|
|
10691
|
+
let cursorY = axisBottom + 6;
|
|
10692
|
+
let lastLane = "\0";
|
|
10693
|
+
for (const t of tasks) {
|
|
10694
|
+
const lane = t.lane;
|
|
10695
|
+
if (lane !== lastLane && lane !== void 0) {
|
|
10696
|
+
rows.push({ kind: "section", y: cursorY, h: G.SECTION_H, label: lane });
|
|
10697
|
+
cursorY += G.SECTION_H;
|
|
10698
|
+
lastLane = lane;
|
|
10699
|
+
} else if (lane === void 0) {
|
|
10700
|
+
lastLane = void 0;
|
|
10701
|
+
}
|
|
10702
|
+
rows.push({ kind: "task", y: cursorY, h: G.ROW_H, task: t });
|
|
10703
|
+
cursorY += G.ROW_H;
|
|
10704
|
+
}
|
|
10705
|
+
const chartBottom = cursorY;
|
|
10706
|
+
const totalH = chartBottom + G.FOOTER_H + G.PAD;
|
|
10707
|
+
const totalW = chartX + chartW + G.PAD;
|
|
10708
|
+
const startDays = ast.start ? parseISODays(ast.start) : void 0;
|
|
10709
|
+
const xAt = (unitOffset) => chartX + unitOffset * pxUnit;
|
|
10710
|
+
const offsetToDate = (u) => {
|
|
10711
|
+
if (startDays === void 0) return void 0;
|
|
10712
|
+
return ast.calendar === "5day" ? advanceWorking(startDays, u * unitToWork) : startDays + Math.round(u * unitToDay);
|
|
10713
|
+
};
|
|
10714
|
+
const niceStep2 = (s) => {
|
|
10715
|
+
const raw = s / 9;
|
|
10716
|
+
const candidates = [1, 2, 5, 7, 10, 14, 20, 25, 50, 100];
|
|
10717
|
+
for (const c of candidates) if (c >= raw) return c;
|
|
10718
|
+
return Math.ceil(raw / 50) * 50;
|
|
10719
|
+
};
|
|
10720
|
+
const step = niceStep2(span);
|
|
10721
|
+
const styleBlock = el("style", {}, `
|
|
10722
|
+
.sx-gantt-bg { fill: ${base.bg}; }
|
|
10723
|
+
.sx-gantt-title { fill: ${P.text}; font-size: 15px; font-weight: 700; }
|
|
10724
|
+
.sx-gantt-grid { stroke: ${P.grid}; stroke-width: 1; }
|
|
10725
|
+
.sx-gantt-axis-tick { stroke: ${P.axis}; stroke-width: 1; }
|
|
10726
|
+
.sx-gantt-axis-text { fill: ${P.subtext}; font-size: 9.5px; }
|
|
10727
|
+
.sx-gantt-axis-base { stroke: ${P.axis}; stroke-width: 1.2; }
|
|
10728
|
+
.sx-gantt-section { fill: ${P.sectionBand}; }
|
|
10729
|
+
.sx-gantt-section-text { fill: ${P.sectionText}; font-size: 11px; font-weight: 700; }
|
|
10730
|
+
.sx-gantt-rowlabel { fill: ${P.text}; font-size: 11.5px; }
|
|
10731
|
+
.sx-gantt-rowlabel.crit { fill: ${P.critStroke}; font-weight: 600; }
|
|
10732
|
+
.sx-gantt-bar { fill: ${P.bar}; stroke: ${P.barStroke}; stroke-width: 1; }
|
|
10733
|
+
.sx-gantt-bar[data-critical="true"] { fill: ${P.critBar}; stroke: ${P.critStroke}; stroke-width: 1.4; }
|
|
10734
|
+
.sx-gantt-done { fill: ${P.barDone}; }
|
|
10735
|
+
.sx-gantt-done[data-critical="true"] { fill: ${P.critDone}; }
|
|
10736
|
+
.sx-gantt-ms { fill: ${P.milestone}; stroke: ${P.milestone}; }
|
|
10737
|
+
.sx-gantt-ms[data-critical="true"] { fill: ${P.critStroke}; stroke: ${P.critStroke}; }
|
|
10738
|
+
.sx-gantt-dep { fill: none; stroke: ${P.dep}; stroke-width: 1; }
|
|
10739
|
+
.sx-gantt-barlabel { fill: ${P.subtext}; font-size: 9.5px; }
|
|
10740
|
+
.sx-gantt-today { stroke: ${P.today}; stroke-width: 1.3; stroke-dasharray: 4 3; }
|
|
10741
|
+
.sx-gantt-today-text { fill: ${P.today}; font-size: 9.5px; font-weight: 700; }
|
|
10742
|
+
.sx-gantt-footer { fill: ${P.subtext}; font-size: 10px; }
|
|
10743
|
+
`.trim());
|
|
10744
|
+
const children = [
|
|
10745
|
+
title(`Gantt chart${ast.title ? " \u2014 " + ast.title : ""}`),
|
|
10746
|
+
desc(summarise(ast, schedule)),
|
|
10747
|
+
styleBlock,
|
|
10748
|
+
rect({ x: 0, y: 0, width: totalW, height: totalH, class: "sx-gantt-bg" })
|
|
10749
|
+
];
|
|
10750
|
+
if (hasTitle) {
|
|
10751
|
+
children.push(text({ x: G.PAD, y: G.PAD + 18, class: "sx-gantt-title" }, ast.title));
|
|
10752
|
+
}
|
|
10753
|
+
const bandEls = [];
|
|
10754
|
+
for (const r7 of rows) {
|
|
10755
|
+
if (r7.kind === "section") {
|
|
10756
|
+
bandEls.push(rect({ x: G.PAD, y: r7.y, width: totalW - 2 * G.PAD, height: r7.h, class: "sx-gantt-section" }));
|
|
10757
|
+
bandEls.push(text({ x: G.PAD + 8, y: r7.y + r7.h / 2 + 4, class: "sx-gantt-section-text" }, r7.label));
|
|
10758
|
+
}
|
|
10759
|
+
}
|
|
10760
|
+
children.push(group({ class: "sx-gantt-sections" }, bandEls));
|
|
10761
|
+
const axisEls = [];
|
|
10762
|
+
for (let u = 0; u <= span + 1e-4; u += step) {
|
|
10763
|
+
const x = xAt(u);
|
|
10764
|
+
axisEls.push(line({ class: "sx-gantt-grid", x1: x, y1: axisBottom, x2: x, y2: chartBottom }));
|
|
10765
|
+
axisEls.push(line({ class: "sx-gantt-axis-tick", x1: x, y1: axisBottom - 5, x2: x, y2: axisBottom }));
|
|
10766
|
+
const cal = offsetToDate(u);
|
|
10767
|
+
const label = cal !== void 0 ? fmtDate(cal) : fmtVal(u);
|
|
10768
|
+
axisEls.push(text({ x, y: axisBottom - 9, class: "sx-gantt-axis-text", "text-anchor": "middle" }, label));
|
|
10769
|
+
}
|
|
10770
|
+
axisEls.push(line({ class: "sx-gantt-axis-base", x1: chartX, y1: axisBottom, x2: chartX + chartW, y2: axisBottom }));
|
|
10771
|
+
children.push(group({ class: "sx-gantt-axis" }, axisEls));
|
|
10772
|
+
const labelEls = [];
|
|
10773
|
+
for (const r7 of rows) {
|
|
10774
|
+
if (r7.kind !== "task" || !r7.task) continue;
|
|
10775
|
+
const c = schedule.computed.get(r7.task.id);
|
|
10776
|
+
const crit = c?.critical ?? false;
|
|
10777
|
+
labelEls.push(
|
|
10778
|
+
text(
|
|
10779
|
+
{ x: G.PAD + 4, y: r7.y + r7.h / 2 + 4, class: `sx-gantt-rowlabel${crit ? " crit" : ""}` },
|
|
10780
|
+
clip(r7.task.label ?? r7.task.id, Math.floor(labelW / G.CHAR_W))
|
|
10781
|
+
)
|
|
10782
|
+
);
|
|
10783
|
+
}
|
|
10784
|
+
children.push(group({ class: "sx-gantt-rowlabels" }, labelEls));
|
|
10785
|
+
const rowOf = /* @__PURE__ */ new Map();
|
|
10786
|
+
for (const r7 of rows) if (r7.kind === "task" && r7.task) rowOf.set(r7.task.id, r7);
|
|
10787
|
+
const depEls = [];
|
|
10788
|
+
for (const t of tasks) {
|
|
10789
|
+
const tr = rowOf.get(t.id);
|
|
10790
|
+
const tc = schedule.computed.get(t.id);
|
|
10791
|
+
if (!tr || !tc) continue;
|
|
10792
|
+
const succMidY = tr.y + tr.h / 2;
|
|
10793
|
+
const succX = xAt(tc.es);
|
|
10794
|
+
for (const dep of t.deps) {
|
|
10795
|
+
const pr = rowOf.get(dep.pred);
|
|
10796
|
+
const pc2 = schedule.computed.get(dep.pred);
|
|
10797
|
+
if (!pr || !pc2) continue;
|
|
10798
|
+
const predMidY = pr.y + pr.h / 2;
|
|
10799
|
+
const predX = xAt(pc2.ef);
|
|
10800
|
+
const midX = Math.max(predX + 8, succX - 10);
|
|
10801
|
+
depEls.push(path({
|
|
10802
|
+
class: "sx-gantt-dep",
|
|
10803
|
+
d: `M ${r1(predX)} ${r1(predMidY)} H ${r1(midX)} V ${r1(succMidY)} H ${r1(succX - 3)}`
|
|
10804
|
+
}));
|
|
10805
|
+
}
|
|
10806
|
+
}
|
|
10807
|
+
children.push(group({ class: "sx-gantt-deps" }, depEls));
|
|
10808
|
+
const barEls = [];
|
|
10809
|
+
for (const r7 of rows) {
|
|
10810
|
+
if (r7.kind !== "task" || !r7.task) continue;
|
|
10811
|
+
const t = r7.task;
|
|
10812
|
+
const c = schedule.computed.get(t.id);
|
|
10813
|
+
if (!c) continue;
|
|
10814
|
+
const crit = c.critical;
|
|
10815
|
+
const cy = r7.y + r7.h / 2;
|
|
10816
|
+
if (t.milestone || t.duration === 0) {
|
|
10817
|
+
const x2 = xAt(c.es);
|
|
10818
|
+
const s = 7;
|
|
10819
|
+
barEls.push(group(
|
|
10820
|
+
{ class: "sx-gantt-task", "data-id": t.id, "data-critical": String(crit), "data-es": String(c.es) },
|
|
10821
|
+
[polygon({
|
|
10822
|
+
class: "sx-gantt-ms",
|
|
10823
|
+
"data-critical": String(crit),
|
|
10824
|
+
points: `${r1(x2)},${r1(cy - s)} ${r1(x2 + s)},${r1(cy)} ${r1(x2)},${r1(cy + s)} ${r1(x2 - s)},${r1(cy)}`
|
|
10825
|
+
})]
|
|
10826
|
+
));
|
|
10827
|
+
continue;
|
|
10828
|
+
}
|
|
10829
|
+
const x = xAt(c.es);
|
|
10830
|
+
const w = Math.max(2, (c.ef - c.es) * pxUnit);
|
|
10831
|
+
const by = cy - G.BAR_H / 2;
|
|
10832
|
+
const parts = [
|
|
10833
|
+
rect({ x: r1(x), y: r1(by), width: r1(w), height: G.BAR_H, rx: 3, class: "sx-gantt-bar", "data-critical": String(crit) })
|
|
10834
|
+
];
|
|
10835
|
+
if (t.progress !== void 0 && t.progress > 0) {
|
|
10836
|
+
parts.push(rect({
|
|
10837
|
+
x: r1(x),
|
|
10838
|
+
y: r1(by),
|
|
10839
|
+
width: r1(Math.max(2, w * t.progress / 100)),
|
|
10840
|
+
height: G.BAR_H,
|
|
10841
|
+
rx: 3,
|
|
10842
|
+
class: "sx-gantt-done",
|
|
10843
|
+
"data-critical": String(crit)
|
|
10844
|
+
}));
|
|
10845
|
+
}
|
|
10846
|
+
const cap2 = c.slack > 0 ? `${fmtVal(c.ef - c.es)}${unitSuffix2(ast.unit)} \xB7 slack ${fmtVal(c.slack)}` : `${fmtVal(c.ef - c.es)}${unitSuffix2(ast.unit)}`;
|
|
10847
|
+
parts.push(text({ x: r1(x + w + 5), y: r1(cy + 3.5), class: "sx-gantt-barlabel" }, cap2));
|
|
10848
|
+
barEls.push(group(
|
|
10849
|
+
{
|
|
10850
|
+
class: "sx-gantt-task",
|
|
10851
|
+
"data-id": t.id,
|
|
10852
|
+
"data-critical": String(crit),
|
|
10853
|
+
"data-es": String(c.es),
|
|
10854
|
+
"data-ef": String(c.ef),
|
|
10855
|
+
"data-slack": String(c.slack),
|
|
10856
|
+
...t.progress !== void 0 ? { "data-progress": String(t.progress) } : {}
|
|
10857
|
+
},
|
|
10858
|
+
parts
|
|
10859
|
+
));
|
|
10860
|
+
}
|
|
10861
|
+
children.push(group({ class: "sx-gantt-bars" }, barEls));
|
|
10862
|
+
if (ast.today && startDays !== void 0) {
|
|
10863
|
+
const todayDays = parseISODays(ast.today);
|
|
10864
|
+
let u;
|
|
10865
|
+
if (ast.calendar === "5day") {
|
|
10866
|
+
u = workingDaysBetween(startDays, todayDays) / unitToWork;
|
|
10867
|
+
} else {
|
|
10868
|
+
u = (todayDays - startDays) / unitToDay;
|
|
10869
|
+
}
|
|
10870
|
+
if (u >= 0 && u <= span) {
|
|
10871
|
+
const x = xAt(u);
|
|
10872
|
+
children.push(group({ class: "sx-gantt-today-g" }, [
|
|
10873
|
+
line({ class: "sx-gantt-today", x1: x, y1: axisBottom, x2: x, y2: chartBottom }),
|
|
10874
|
+
text({ x, y: chartBottom + 12, class: "sx-gantt-today-text", "text-anchor": "middle" }, "today")
|
|
10875
|
+
]));
|
|
10876
|
+
}
|
|
10877
|
+
}
|
|
10878
|
+
const footer = `${schedule.order.length} tasks \xB7 duration ${fmtVal(schedule.projectDuration)}${unitSuffix2(ast.unit)} \xB7 critical path: ${schedule.criticalPath.join(" \u2192 ") || "\u2014"}`;
|
|
10879
|
+
children.push(text({ x: G.PAD, y: totalH - 10, class: "sx-gantt-footer" }, clip(footer, Math.floor((totalW - 2 * G.PAD) / 5.4))));
|
|
10880
|
+
return svgRoot(
|
|
10881
|
+
{
|
|
10882
|
+
class: "sx-gantt",
|
|
10883
|
+
role: "img",
|
|
10884
|
+
"aria-label": escapeXml(ast.title ?? "Gantt chart"),
|
|
10885
|
+
width: totalW,
|
|
10886
|
+
height: totalH,
|
|
10887
|
+
viewBox: `0 0 ${totalW} ${totalH}`,
|
|
10888
|
+
"data-diagram-type": "pert",
|
|
10889
|
+
"data-layout": "gantt"
|
|
10890
|
+
},
|
|
10891
|
+
children
|
|
10892
|
+
);
|
|
10893
|
+
}
|
|
10894
|
+
function workingDaysBetween(a, b) {
|
|
10895
|
+
if (b < a) return -workingDaysBetween(b, a);
|
|
10896
|
+
let n = 0;
|
|
10897
|
+
for (let d = a; d < b; d++) if (!isWeekend(d)) n++;
|
|
10898
|
+
return n;
|
|
10899
|
+
}
|
|
10900
|
+
function unitSuffix2(unit) {
|
|
10901
|
+
switch (unit) {
|
|
10902
|
+
case "days":
|
|
10903
|
+
return "d";
|
|
10904
|
+
case "weeks":
|
|
10905
|
+
return "w";
|
|
10906
|
+
case "hours":
|
|
10907
|
+
return "h";
|
|
10908
|
+
default:
|
|
10909
|
+
return "";
|
|
10910
|
+
}
|
|
10911
|
+
}
|
|
10527
10912
|
function fmtVal(n) {
|
|
10528
10913
|
return String(parseFloat(n.toFixed(2)));
|
|
10529
10914
|
}
|
|
10915
|
+
function r1(n) {
|
|
10916
|
+
return Math.round(n * 10) / 10;
|
|
10917
|
+
}
|
|
10918
|
+
function clip(s, n) {
|
|
10919
|
+
return s.length <= n ? s : s.slice(0, Math.max(1, n - 1)) + "\u2026";
|
|
10920
|
+
}
|
|
10921
|
+
function summarise(ast, s) {
|
|
10922
|
+
const parts = [`Gantt chart: ${s.order.length} tasks, project duration ${fmtVal(s.projectDuration)}${unitSuffix2(ast.unit)}.`];
|
|
10923
|
+
if (ast.start) parts.push(`Starts ${ast.start} (${ast.calendar === "5day" ? "weekdays only" : "continuous"}).`);
|
|
10924
|
+
if (s.criticalPath.length) parts.push(`Critical path: ${s.criticalPath.join(" \u2192 ")}.`);
|
|
10925
|
+
return parts.join(" ");
|
|
10926
|
+
}
|
|
10927
|
+
|
|
10928
|
+
// src/diagrams/pert/renderer.ts
|
|
10929
|
+
function fmtVal2(n) {
|
|
10930
|
+
return String(parseFloat(n.toFixed(2)));
|
|
10931
|
+
}
|
|
10530
10932
|
function unitWord(unit) {
|
|
10531
10933
|
return unit === "abstract" ? "" : unit;
|
|
10532
10934
|
}
|
|
@@ -10630,19 +11032,19 @@ function dataAttrs(b) {
|
|
|
10630
11032
|
const attrs = {
|
|
10631
11033
|
class: `sx-pert-task${c.critical ? " critical" : ""}${b.task.className ? " " + b.task.className : ""}`,
|
|
10632
11034
|
"data-id": b.id,
|
|
10633
|
-
"data-es":
|
|
10634
|
-
"data-ef":
|
|
10635
|
-
"data-ls":
|
|
10636
|
-
"data-lf":
|
|
10637
|
-
"data-slack":
|
|
10638
|
-
"data-duration":
|
|
11035
|
+
"data-es": fmtVal2(c.es),
|
|
11036
|
+
"data-ef": fmtVal2(c.ef),
|
|
11037
|
+
"data-ls": fmtVal2(c.ls),
|
|
11038
|
+
"data-lf": fmtVal2(c.lf),
|
|
11039
|
+
"data-slack": fmtVal2(c.slack),
|
|
11040
|
+
"data-duration": fmtVal2(b.task.duration),
|
|
10639
11041
|
"data-critical": String(c.critical)
|
|
10640
11042
|
};
|
|
10641
11043
|
if (b.task.tags.length) attrs["data-tag"] = b.task.tags.join(" ");
|
|
10642
11044
|
if (b.task.threePoint) {
|
|
10643
11045
|
const tp = b.task.threePoint;
|
|
10644
|
-
attrs["data-pert-triple"] = `${
|
|
10645
|
-
if (b.task.variance !== void 0) attrs["data-pert-variance"] =
|
|
11046
|
+
attrs["data-pert-triple"] = `${fmtVal2(tp.o)}/${fmtVal2(tp.m)}/${fmtVal2(tp.p)}`;
|
|
11047
|
+
if (b.task.variance !== void 0) attrs["data-pert-variance"] = fmtVal2(b.task.variance);
|
|
10646
11048
|
}
|
|
10647
11049
|
return attrs;
|
|
10648
11050
|
}
|
|
@@ -10669,16 +11071,16 @@ function renderSixField(b) {
|
|
|
10669
11071
|
text({ class: "sx-pert-field-label", x: fx, y: y + 9, "text-anchor": "middle" }, label),
|
|
10670
11072
|
text({ class: cls, x: fx, y: y + 19, "text-anchor": "middle" }, value)
|
|
10671
11073
|
]);
|
|
10672
|
-
parts.push(field(x + col / 2, "ES",
|
|
10673
|
-
parts.push(field(x + col * 1.5, "DUR",
|
|
10674
|
-
parts.push(field(x + col * 2.5, "EF",
|
|
11074
|
+
parts.push(field(x + col / 2, "ES", fmtVal2(c.es)));
|
|
11075
|
+
parts.push(field(x + col * 1.5, "DUR", fmtVal2(b.task.duration)));
|
|
11076
|
+
parts.push(field(x + col * 2.5, "EF", fmtVal2(c.ef)));
|
|
10675
11077
|
const fieldBot = (fx, label, value, cls = "sx-pert-field") => group({}, [
|
|
10676
11078
|
text({ class: cls, x: fx, y: yBot + 13, "text-anchor": "middle" }, value),
|
|
10677
11079
|
text({ class: "sx-pert-field-label", x: fx, y: yBot + 21, "text-anchor": "middle" }, label)
|
|
10678
11080
|
]);
|
|
10679
|
-
parts.push(fieldBot(x + col / 2, "LS",
|
|
10680
|
-
parts.push(fieldBot(x + col * 1.5, "SLACK",
|
|
10681
|
-
parts.push(fieldBot(x + col * 2.5, "LF",
|
|
11081
|
+
parts.push(fieldBot(x + col / 2, "LS", fmtVal2(c.ls)));
|
|
11082
|
+
parts.push(fieldBot(x + col * 1.5, "SLACK", fmtVal2(c.slack), "sx-pert-field slack"));
|
|
11083
|
+
parts.push(fieldBot(x + col * 2.5, "LF", fmtVal2(c.lf)));
|
|
10682
11084
|
const hasSigma = b.task.variance !== void 0;
|
|
10683
11085
|
const nameY = hasSigma ? y + topH + 18 : y + topH + 19;
|
|
10684
11086
|
parts.push(text({ class: "sx-pert-name", x: cx, y: nameY, "text-anchor": "middle" }, b.task.label));
|
|
@@ -10687,7 +11089,7 @@ function renderSixField(b) {
|
|
|
10687
11089
|
parts.push(
|
|
10688
11090
|
text(
|
|
10689
11091
|
{ class: "sx-pert-sigma", x: cx, y: nameY + 27, "text-anchor": "middle" },
|
|
10690
|
-
`\u03C3=${
|
|
11092
|
+
`\u03C3=${fmtVal2(Math.sqrt(b.task.variance))}`
|
|
10691
11093
|
)
|
|
10692
11094
|
);
|
|
10693
11095
|
}
|
|
@@ -10701,7 +11103,7 @@ function renderMilestone(b) {
|
|
|
10701
11103
|
const parts = [
|
|
10702
11104
|
polygon({ class: "sx-pert-ms", points: pts }),
|
|
10703
11105
|
text({ class: "sx-pert-name", x: cx, y: cy - 2, "text-anchor": "middle" }, b.task.label),
|
|
10704
|
-
text({ class: "sx-pert-id", x: cx, y: cy + 12, "text-anchor": "middle" }, `@ ${
|
|
11106
|
+
text({ class: "sx-pert-id", x: cx, y: cy + 12, "text-anchor": "middle" }, `@ ${fmtVal2(b.computed.es)}`)
|
|
10705
11107
|
];
|
|
10706
11108
|
return group(dataAttrs(b), parts);
|
|
10707
11109
|
}
|
|
@@ -10714,12 +11116,12 @@ function renderTimescaledBar(b) {
|
|
|
10714
11116
|
parts.push(text({ class: "sx-pert-id", x: cx, y: y + h / 2 + 4, "text-anchor": "middle" }, b.id));
|
|
10715
11117
|
const wide = w >= 104;
|
|
10716
11118
|
if (wide) {
|
|
10717
|
-
parts.push(text({ class: "sx-pert-field-label", x: x + 7, y: y + 15, "text-anchor": "start" }, `ES ${
|
|
10718
|
-
parts.push(text({ class: "sx-pert-field-label", x: x + w - 7, y: y + 15, "text-anchor": "end" }, `EF ${
|
|
11119
|
+
parts.push(text({ class: "sx-pert-field-label", x: x + 7, y: y + 15, "text-anchor": "start" }, `ES ${fmtVal2(c.es)}`));
|
|
11120
|
+
parts.push(text({ class: "sx-pert-field-label", x: x + w - 7, y: y + 15, "text-anchor": "end" }, `EF ${fmtVal2(c.ef)}`));
|
|
10719
11121
|
parts.push(
|
|
10720
11122
|
text(
|
|
10721
11123
|
{ class: `sx-pert-field-label${c.critical ? " slack" : ""}`, x: cx, y: y + h - 8, "text-anchor": "middle" },
|
|
10722
|
-
`slack ${
|
|
11124
|
+
`slack ${fmtVal2(c.slack)}`
|
|
10723
11125
|
)
|
|
10724
11126
|
);
|
|
10725
11127
|
}
|
|
@@ -10804,7 +11206,7 @@ function renderAxis2(axis, gridTop) {
|
|
|
10804
11206
|
parts.push(line({ x1: tk.pos, y1: axis.baseline, x2: tk.pos, y2: axis.baseline + len }));
|
|
10805
11207
|
if (tk.major) {
|
|
10806
11208
|
parts.push(
|
|
10807
|
-
text({ x: tk.pos, y: axis.baseline + 18, "text-anchor": "middle" },
|
|
11209
|
+
text({ x: tk.pos, y: axis.baseline + 18, "text-anchor": "middle" }, fmtVal2(tk.value))
|
|
10808
11210
|
);
|
|
10809
11211
|
}
|
|
10810
11212
|
}
|
|
@@ -10830,7 +11232,7 @@ function renderAoa(aoa) {
|
|
|
10830
11232
|
);
|
|
10831
11233
|
if (!a.dummy && a.label) {
|
|
10832
11234
|
const critCls = a.critical ? " critical" : "";
|
|
10833
|
-
const durStr =
|
|
11235
|
+
const durStr = fmtVal2(a.duration ?? 0);
|
|
10834
11236
|
const w = Math.max(a.label.length * 6.2, durStr.length * 6) + 8;
|
|
10835
11237
|
labelEls.push(
|
|
10836
11238
|
rect({ class: "sx-pert-edge-halo", x: a.labelX - w / 2, y: a.labelY - 16, width: w, height: 31, rx: 3, ry: 3 })
|
|
@@ -10860,8 +11262,8 @@ function renderAoa(aoa) {
|
|
|
10860
11262
|
}
|
|
10861
11263
|
function summaryText(summary) {
|
|
10862
11264
|
const u = unitWord(summary.unit);
|
|
10863
|
-
const dur = `${
|
|
10864
|
-
const sigma = summary.projectStdDev !== void 0 ? ` \xB7 \u03C3 \u2248 ${
|
|
11265
|
+
const dur = `${fmtVal2(summary.projectDuration)}${u ? " " + u : ""}`;
|
|
11266
|
+
const sigma = summary.projectStdDev !== void 0 ? ` \xB7 \u03C3 \u2248 ${fmtVal2(summary.projectStdDev)}` : "";
|
|
10865
11267
|
const plain = `Project duration ${dur} \xB7 ${summary.taskCount} tasks \xB7 ${summary.depCount} dependencies \xB7 ${summary.criticalCount} critical${sigma}`;
|
|
10866
11268
|
const critPath = summary.criticalPath.map((id) => id).join(" \u2192 ");
|
|
10867
11269
|
return { plain, critPath };
|
|
@@ -10873,7 +11275,7 @@ function renderPertLayout(layout, config) {
|
|
|
10873
11275
|
children.push(title(`PERT network${layout.title ? " \u2014 " + layout.title : ""}`));
|
|
10874
11276
|
children.push(
|
|
10875
11277
|
desc(
|
|
10876
|
-
`${layout.summary.taskCount} activities, project duration ${
|
|
11278
|
+
`${layout.summary.taskCount} activities, project duration ${fmtVal2(layout.summary.projectDuration)} ${unitWord(layout.unit)}` + (cp.length ? `, critical path ${cp.join(" \u2192 ")}` : "") + "."
|
|
10877
11279
|
)
|
|
10878
11280
|
);
|
|
10879
11281
|
children.push(el("style", {}, buildCss5(t)));
|
|
@@ -10941,6 +11343,7 @@ var PERT_PAD = 24;
|
|
|
10941
11343
|
function renderPert(textOrAst, config) {
|
|
10942
11344
|
const ast = typeof textOrAst === "string" ? parsePert(textOrAst) : textOrAst;
|
|
10943
11345
|
const schedule = schedulePert(ast);
|
|
11346
|
+
if (ast.layout === "gantt") return renderGantt2(ast, schedule, config);
|
|
10944
11347
|
const layout = layoutPert(ast, schedule);
|
|
10945
11348
|
return renderPertLayout(layout, config);
|
|
10946
11349
|
}
|
|
@@ -10953,7 +11356,7 @@ var pert = {
|
|
|
10953
11356
|
const t = raw.trim();
|
|
10954
11357
|
if (!t) continue;
|
|
10955
11358
|
if (t.startsWith("#") || t.startsWith("//")) continue;
|
|
10956
|
-
return /^pert\b/i.test(t);
|
|
11359
|
+
return /^(pert|gantt)\b/i.test(t);
|
|
10957
11360
|
}
|
|
10958
11361
|
return false;
|
|
10959
11362
|
},
|
|
@@ -12021,18 +12424,18 @@ function renderFragmentTab(f) {
|
|
|
12021
12424
|
});
|
|
12022
12425
|
return group({ class: "sx-seq-fragment-tab-g", "data-op": f.op }, parts);
|
|
12023
12426
|
}
|
|
12024
|
-
function renderRef(
|
|
12427
|
+
function renderRef(r7) {
|
|
12025
12428
|
const tabW = 40;
|
|
12026
12429
|
const tabH = 18;
|
|
12027
12430
|
const fold = 6;
|
|
12028
|
-
const tab = `M ${
|
|
12431
|
+
const tab = `M ${r7.x} ${r7.y} H ${r7.x + tabW} V ${r7.y + tabH - fold} L ${r7.x + tabW - fold} ${r7.y + tabH} H ${r7.x} Z`;
|
|
12029
12432
|
return group({ class: "sx-seq-fragment", "data-op": "ref" }, [
|
|
12030
|
-
rect({ class: "sx-seq-frame", x:
|
|
12433
|
+
rect({ class: "sx-seq-frame", x: r7.x, y: r7.y, width: r7.width, height: r7.height, rx: 2, ry: 2 }),
|
|
12031
12434
|
path({ class: "sx-seq-frame-tab", d: tab }),
|
|
12032
|
-
text({ class: "sx-seq-frame-op", x:
|
|
12435
|
+
text({ class: "sx-seq-frame-op", x: r7.x + 8, y: r7.y + 13 }, "ref"),
|
|
12033
12436
|
text(
|
|
12034
|
-
{ class: "sx-seq-ref-name", x:
|
|
12035
|
-
|
|
12437
|
+
{ class: "sx-seq-ref-name", x: r7.x + r7.width / 2, y: r7.y + r7.height / 2 + 8, "text-anchor": "middle" },
|
|
12438
|
+
r7.text
|
|
12036
12439
|
)
|
|
12037
12440
|
]);
|
|
12038
12441
|
}
|
|
@@ -12069,10 +12472,10 @@ function renderInvariant(iv) {
|
|
|
12069
12472
|
]);
|
|
12070
12473
|
}
|
|
12071
12474
|
function renderDestroy(d) {
|
|
12072
|
-
const
|
|
12475
|
+
const r7 = 7;
|
|
12073
12476
|
return group({ class: "sx-seq-destroy-g" }, [
|
|
12074
|
-
line({ class: "sx-seq-destroy", x1: d.x -
|
|
12075
|
-
line({ class: "sx-seq-destroy", x1: d.x -
|
|
12477
|
+
line({ class: "sx-seq-destroy", x1: d.x - r7, y1: d.y - r7, x2: d.x + r7, y2: d.y + r7 }),
|
|
12478
|
+
line({ class: "sx-seq-destroy", x1: d.x - r7, y1: d.y + r7, x2: d.x + r7, y2: d.y - r7 })
|
|
12076
12479
|
]);
|
|
12077
12480
|
}
|
|
12078
12481
|
function renderSequenceLayout(layout, config) {
|
|
@@ -12915,10 +13318,10 @@ function renderArc2(ag) {
|
|
|
12915
13318
|
const dx = last.x - prev.x;
|
|
12916
13319
|
const dy = last.y - prev.y;
|
|
12917
13320
|
const len = Math.hypot(dx, dy) || 1;
|
|
12918
|
-
const
|
|
12919
|
-
const cx = last.x - dx / len *
|
|
12920
|
-
const cy = last.y - dy / len *
|
|
12921
|
-
parts.push(circle({ class: "sx-petri-inhibitor-dot", cx, cy, r:
|
|
13321
|
+
const r7 = 4;
|
|
13322
|
+
const cx = last.x - dx / len * r7;
|
|
13323
|
+
const cy = last.y - dy / len * r7;
|
|
13324
|
+
parts.push(circle({ class: "sx-petri-inhibitor-dot", cx, cy, r: r7 }));
|
|
12922
13325
|
}
|
|
12923
13326
|
if (ag.weight > 1) {
|
|
12924
13327
|
parts.push(
|
|
@@ -13316,10 +13719,10 @@ function parseNetwork(text2) {
|
|
|
13316
13719
|
if (rest[0]) ast.title = rest[0].value;
|
|
13317
13720
|
break;
|
|
13318
13721
|
case "spines":
|
|
13319
|
-
ast.spines.push(...rest.filter((
|
|
13722
|
+
ast.spines.push(...rest.filter((r7) => !r7.str).map((r7) => r7.value));
|
|
13320
13723
|
break;
|
|
13321
13724
|
case "leaves":
|
|
13322
|
-
ast.leaves.push(...rest.filter((
|
|
13725
|
+
ast.leaves.push(...rest.filter((r7) => !r7.str).map((r7) => r7.value));
|
|
13323
13726
|
break;
|
|
13324
13727
|
case "legend":
|
|
13325
13728
|
break;
|
|
@@ -13889,29 +14292,29 @@ function placeBanded(ast, ranks) {
|
|
|
13889
14292
|
const lr = ast.direction === "lr";
|
|
13890
14293
|
const byRank = /* @__PURE__ */ new Map();
|
|
13891
14294
|
for (const d of ast.devices) {
|
|
13892
|
-
const
|
|
13893
|
-
if (!byRank.has(
|
|
13894
|
-
byRank.get(
|
|
14295
|
+
const r7 = ranks.get(d.id) ?? 0;
|
|
14296
|
+
if (!byRank.has(r7)) byRank.set(r7, []);
|
|
14297
|
+
byRank.get(r7).push(d);
|
|
13895
14298
|
}
|
|
13896
14299
|
const rankValues = [...byRank.keys()].sort((a, b) => a - b);
|
|
13897
14300
|
const pos = /* @__PURE__ */ new Map();
|
|
13898
14301
|
let maxRowSpan = 0;
|
|
13899
14302
|
const rowSpans = /* @__PURE__ */ new Map();
|
|
13900
|
-
for (const
|
|
13901
|
-
const devs = byRank.get(
|
|
14303
|
+
for (const r7 of rankValues) {
|
|
14304
|
+
const devs = byRank.get(r7);
|
|
13902
14305
|
let span = 0;
|
|
13903
14306
|
devs.forEach((d, i) => {
|
|
13904
14307
|
const fp = deviceFootprint(d);
|
|
13905
14308
|
const cross = lr ? fp.h + labelExtra(d) : Math.max(fp.w, labelText(d).length * NET_CONST.CHAR_W + 6);
|
|
13906
14309
|
span += cross + (i > 0 ? NET_CONST.SIBLING_GAP : 0);
|
|
13907
14310
|
});
|
|
13908
|
-
rowSpans.set(
|
|
14311
|
+
rowSpans.set(r7, span);
|
|
13909
14312
|
maxRowSpan = Math.max(maxRowSpan, span);
|
|
13910
14313
|
}
|
|
13911
|
-
rankValues.forEach((
|
|
13912
|
-
const devs = byRank.get(
|
|
14314
|
+
rankValues.forEach((r7, rowIdx) => {
|
|
14315
|
+
const devs = byRank.get(r7);
|
|
13913
14316
|
const along = rowIdx * NET_CONST.TIER_BAND_GAP;
|
|
13914
|
-
let cursor = (maxRowSpan - rowSpans.get(
|
|
14317
|
+
let cursor = (maxRowSpan - rowSpans.get(r7)) / 2;
|
|
13915
14318
|
for (const d of devs) {
|
|
13916
14319
|
const fp = deviceFootprint(d);
|
|
13917
14320
|
const cross = lr ? fp.h + labelExtra(d) : Math.max(fp.w, labelText(d).length * NET_CONST.CHAR_W + 6);
|
|
@@ -13946,8 +14349,8 @@ function tieredRanks(ast, links) {
|
|
|
13946
14349
|
if (rank.has(d.id)) continue;
|
|
13947
14350
|
const known = [];
|
|
13948
14351
|
for (const n of adj.get(d.id) ?? []) {
|
|
13949
|
-
const
|
|
13950
|
-
if (
|
|
14352
|
+
const r7 = rank.get(n);
|
|
14353
|
+
if (r7 !== void 0) known.push(r7);
|
|
13951
14354
|
}
|
|
13952
14355
|
if (known.length === 0) continue;
|
|
13953
14356
|
const next = ENDPOINT_KINDS.has(d.kind) ? Math.max(...known) + 1 : Math.min(...known) + 1;
|
|
@@ -13981,10 +14384,10 @@ function treeRanks(ast, links) {
|
|
|
13981
14384
|
rank.set(root.id, 0);
|
|
13982
14385
|
while (queue.length) {
|
|
13983
14386
|
const id = queue.shift();
|
|
13984
|
-
const
|
|
14387
|
+
const r7 = rank.get(id);
|
|
13985
14388
|
for (const n of adj.get(id) ?? []) {
|
|
13986
14389
|
if (!rank.has(n)) {
|
|
13987
|
-
rank.set(n,
|
|
14390
|
+
rank.set(n, r7 + 1);
|
|
13988
14391
|
queue.push(n);
|
|
13989
14392
|
}
|
|
13990
14393
|
}
|
|
@@ -14168,11 +14571,11 @@ function layoutNetwork2(ast) {
|
|
|
14168
14571
|
};
|
|
14169
14572
|
const groupsByDepth = [...ast.groups].sort((a, b) => depthOf(b.id) - depthOf(a.id));
|
|
14170
14573
|
for (const g of groupsByDepth) {
|
|
14171
|
-
let l = Infinity, t = Infinity,
|
|
14574
|
+
let l = Infinity, t = Infinity, r7 = -Infinity, bm = -Infinity;
|
|
14172
14575
|
const addBox = (e) => {
|
|
14173
14576
|
l = Math.min(l, e.left);
|
|
14174
14577
|
t = Math.min(t, e.top);
|
|
14175
|
-
|
|
14578
|
+
r7 = Math.max(r7, e.right);
|
|
14176
14579
|
bm = Math.max(bm, e.bottom);
|
|
14177
14580
|
};
|
|
14178
14581
|
for (const mid of g.members) {
|
|
@@ -14189,7 +14592,7 @@ function layoutNetwork2(ast) {
|
|
|
14189
14592
|
groupBoxesRaw.set(g.id, {
|
|
14190
14593
|
left: l - pad,
|
|
14191
14594
|
top: t - pad - NET_CONST.GROUP_HEADER,
|
|
14192
|
-
right:
|
|
14595
|
+
right: r7 + pad,
|
|
14193
14596
|
bottom: bm + pad,
|
|
14194
14597
|
depth
|
|
14195
14598
|
});
|
|
@@ -14648,10 +15051,10 @@ function parseUmlClass(text2) {
|
|
|
14648
15051
|
}
|
|
14649
15052
|
const rels = tryParseRelationship(t, i + 1);
|
|
14650
15053
|
if (rels) {
|
|
14651
|
-
for (const
|
|
14652
|
-
ast.relationships.push(
|
|
14653
|
-
ensureClassifier(ast,
|
|
14654
|
-
ensureClassifier(ast,
|
|
15054
|
+
for (const r7 of rels) {
|
|
15055
|
+
ast.relationships.push(r7);
|
|
15056
|
+
ensureClassifier(ast, r7.from);
|
|
15057
|
+
ensureClassifier(ast, r7.to);
|
|
14655
15058
|
}
|
|
14656
15059
|
i++;
|
|
14657
15060
|
continue;
|
|
@@ -15206,11 +15609,11 @@ function findConnector(line2, glyph) {
|
|
|
15206
15609
|
}
|
|
15207
15610
|
function validateGeneralizationAcyclicity(ast) {
|
|
15208
15611
|
const adj = /* @__PURE__ */ new Map();
|
|
15209
|
-
for (const
|
|
15210
|
-
if (
|
|
15211
|
-
const list = adj.get(
|
|
15212
|
-
list.push(
|
|
15213
|
-
adj.set(
|
|
15612
|
+
for (const r7 of ast.relationships) {
|
|
15613
|
+
if (r7.kind === "generalization" || r7.kind === "realization") {
|
|
15614
|
+
const list = adj.get(r7.from) ?? [];
|
|
15615
|
+
list.push(r7.to);
|
|
15616
|
+
adj.set(r7.from, list);
|
|
15214
15617
|
}
|
|
15215
15618
|
}
|
|
15216
15619
|
const WHITE = 0, GREY = 1, BLACK = 2;
|
|
@@ -15243,12 +15646,12 @@ function validateGeneralizationAcyclicity(ast) {
|
|
|
15243
15646
|
}
|
|
15244
15647
|
}
|
|
15245
15648
|
function validateRealizationTargets(ast) {
|
|
15246
|
-
for (const
|
|
15247
|
-
if (
|
|
15248
|
-
const target = ast.classifiers.find((c) => c.id ===
|
|
15649
|
+
for (const r7 of ast.relationships) {
|
|
15650
|
+
if (r7.kind !== "realization") continue;
|
|
15651
|
+
const target = ast.classifiers.find((c) => c.id === r7.to);
|
|
15249
15652
|
if (target && target.kind !== "interface") {
|
|
15250
15653
|
ast.warnings.push(
|
|
15251
|
-
`Realization target "${
|
|
15654
|
+
`Realization target "${r7.to}" is not an \xABinterface\xBB \u2014 consider marking it so.`
|
|
15252
15655
|
);
|
|
15253
15656
|
}
|
|
15254
15657
|
}
|
|
@@ -15726,16 +16129,16 @@ function memberLineText(m) {
|
|
|
15726
16129
|
const props = m.properties && m.properties.length > 0 ? ` {${m.properties.join(", ")}}` : "";
|
|
15727
16130
|
return `${v}${m.name}(${params})${ret}${props}`;
|
|
15728
16131
|
}
|
|
15729
|
-
function rankEnds(
|
|
15730
|
-
switch (
|
|
16132
|
+
function rankEnds(r7) {
|
|
16133
|
+
switch (r7.kind) {
|
|
15731
16134
|
case "generalization":
|
|
15732
16135
|
case "realization":
|
|
15733
|
-
return { parent:
|
|
16136
|
+
return { parent: r7.to, child: r7.from };
|
|
15734
16137
|
case "composition":
|
|
15735
16138
|
case "aggregation":
|
|
15736
16139
|
case "directed":
|
|
15737
16140
|
case "dependency":
|
|
15738
|
-
return { parent:
|
|
16141
|
+
return { parent: r7.from, child: r7.to };
|
|
15739
16142
|
case "association":
|
|
15740
16143
|
return null;
|
|
15741
16144
|
}
|
|
@@ -15743,8 +16146,8 @@ function rankEnds(r6) {
|
|
|
15743
16146
|
function computeRanks(ast, boxes) {
|
|
15744
16147
|
const parentsOf = /* @__PURE__ */ new Map();
|
|
15745
16148
|
for (const b of boxes) parentsOf.set(b.classifier.id, /* @__PURE__ */ new Set());
|
|
15746
|
-
for (const
|
|
15747
|
-
const ends = rankEnds(
|
|
16149
|
+
for (const r7 of ast.relationships) {
|
|
16150
|
+
const ends = rankEnds(r7);
|
|
15748
16151
|
if (ends) parentsOf.get(ends.child)?.add(ends.parent);
|
|
15749
16152
|
}
|
|
15750
16153
|
const rank = /* @__PURE__ */ new Map();
|
|
@@ -15786,19 +16189,19 @@ function buildLayeredGraph(rels, boxes, rankByID) {
|
|
|
15786
16189
|
byID.set(n.id, n);
|
|
15787
16190
|
}
|
|
15788
16191
|
const chains = [];
|
|
15789
|
-
for (const
|
|
15790
|
-
const a = byID.get(
|
|
15791
|
-
const b = byID.get(
|
|
16192
|
+
for (const r7 of rels) {
|
|
16193
|
+
const a = byID.get(r7.from);
|
|
16194
|
+
const b = byID.get(r7.to);
|
|
15792
16195
|
if (!a || !b) continue;
|
|
15793
16196
|
if (a.rank === b.rank) {
|
|
15794
|
-
chains.push({ rel:
|
|
16197
|
+
chains.push({ rel: r7, chain: [a.id, b.id], sameRank: true });
|
|
15795
16198
|
continue;
|
|
15796
16199
|
}
|
|
15797
16200
|
const lo = a.rank < b.rank ? a : b;
|
|
15798
16201
|
const hi = a.rank < b.rank ? b : a;
|
|
15799
16202
|
const diff = hi.rank - lo.rank;
|
|
15800
16203
|
if (diff === 1) {
|
|
15801
|
-
chains.push({ rel:
|
|
16204
|
+
chains.push({ rel: r7, chain: [r7.from, r7.to], sameRank: false });
|
|
15802
16205
|
continue;
|
|
15803
16206
|
}
|
|
15804
16207
|
const innerDummies = [];
|
|
@@ -15819,7 +16222,7 @@ function buildLayeredGraph(rels, boxes, rankByID) {
|
|
|
15819
16222
|
}
|
|
15820
16223
|
const lowToHigh = [lo.id, ...innerDummies, hi.id];
|
|
15821
16224
|
const chain = a.rank < b.rank ? lowToHigh : [...lowToHigh].reverse();
|
|
15822
|
-
chains.push({ rel:
|
|
16225
|
+
chains.push({ rel: r7, chain, sameRank: false });
|
|
15823
16226
|
}
|
|
15824
16227
|
return { nodes, chains };
|
|
15825
16228
|
}
|
|
@@ -15859,12 +16262,12 @@ function orderRanks(ranks, chains) {
|
|
|
15859
16262
|
for (let iter = 0; iter < UMLCLASS_CONST.ORDER_ITERATIONS; iter++) {
|
|
15860
16263
|
const downward = iter % 2 === 0;
|
|
15861
16264
|
if (downward) {
|
|
15862
|
-
for (let
|
|
15863
|
-
applyBarycenter(ranks[
|
|
16265
|
+
for (let r7 = 1; r7 < ranks.length; r7++) {
|
|
16266
|
+
applyBarycenter(ranks[r7], ranks[r7 - 1], up);
|
|
15864
16267
|
}
|
|
15865
16268
|
} else {
|
|
15866
|
-
for (let
|
|
15867
|
-
applyBarycenter(ranks[
|
|
16269
|
+
for (let r7 = ranks.length - 2; r7 >= 0; r7--) {
|
|
16270
|
+
applyBarycenter(ranks[r7], ranks[r7 + 1], down);
|
|
15868
16271
|
}
|
|
15869
16272
|
}
|
|
15870
16273
|
}
|
|
@@ -16003,22 +16406,22 @@ function routeEdges(chains, nodes, boxByID, vertical) {
|
|
|
16003
16406
|
const handled = /* @__PURE__ */ new Set();
|
|
16004
16407
|
const groups = /* @__PURE__ */ new Map();
|
|
16005
16408
|
for (const c of chains) {
|
|
16006
|
-
const
|
|
16007
|
-
if (
|
|
16008
|
-
const k = `${
|
|
16009
|
-
if (!groups.has(k)) groups.set(k, { kind:
|
|
16010
|
-
groups.get(k).rels.push(
|
|
16409
|
+
const r7 = c.rel;
|
|
16410
|
+
if (r7.kind !== "generalization" && r7.kind !== "realization") continue;
|
|
16411
|
+
const k = `${r7.kind}::${r7.to}`;
|
|
16412
|
+
if (!groups.has(k)) groups.set(k, { kind: r7.kind, parentId: r7.to, rels: [] });
|
|
16413
|
+
groups.get(k).rels.push(r7);
|
|
16011
16414
|
}
|
|
16012
16415
|
for (const [, group2] of groups) {
|
|
16013
16416
|
if (group2.rels.length < UMLCLASS_CONST.TREE_MERGE_THRESHOLD) continue;
|
|
16014
16417
|
const parent = boxByID.get(group2.parentId);
|
|
16015
16418
|
if (!parent) continue;
|
|
16016
|
-
const children = group2.rels.map((
|
|
16419
|
+
const children = group2.rels.map((r7) => ({ r: r7, box: boxByID.get(r7.from) })).filter((c) => !!c.box);
|
|
16017
16420
|
if (children.length < UMLCLASS_CONST.TREE_MERGE_THRESHOLD) continue;
|
|
16018
16421
|
const tree = buildTree2(group2.kind, parent, children, vertical);
|
|
16019
16422
|
if (tree) {
|
|
16020
16423
|
trees.push(tree);
|
|
16021
|
-
for (const
|
|
16424
|
+
for (const r7 of group2.rels) handled.add(r7);
|
|
16022
16425
|
}
|
|
16023
16426
|
}
|
|
16024
16427
|
const liftLanes = /* @__PURE__ */ new Map();
|
|
@@ -16471,8 +16874,8 @@ function escapeXmlText(s) {
|
|
|
16471
16874
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
16472
16875
|
}
|
|
16473
16876
|
function renderEdge4(e) {
|
|
16474
|
-
const
|
|
16475
|
-
const dashed =
|
|
16877
|
+
const r7 = e.rel;
|
|
16878
|
+
const dashed = r7.kind === "realization" || r7.kind === "dependency";
|
|
16476
16879
|
const parts = [];
|
|
16477
16880
|
parts.push(
|
|
16478
16881
|
path({
|
|
@@ -16481,15 +16884,15 @@ function renderEdge4(e) {
|
|
|
16481
16884
|
"data-dashed": dashed ? "true" : void 0
|
|
16482
16885
|
})
|
|
16483
16886
|
);
|
|
16484
|
-
parts.push(renderTargetAdornment(
|
|
16485
|
-
if (
|
|
16486
|
-
parts.push(renderSourceDiamond(
|
|
16487
|
-
}
|
|
16488
|
-
if (
|
|
16489
|
-
if (
|
|
16490
|
-
if (
|
|
16491
|
-
if (
|
|
16492
|
-
if (
|
|
16887
|
+
parts.push(renderTargetAdornment(r7.kind, e.targetEnd));
|
|
16888
|
+
if (r7.kind === "composition" || r7.kind === "aggregation") {
|
|
16889
|
+
parts.push(renderSourceDiamond(r7.kind, e.sourceEnd));
|
|
16890
|
+
}
|
|
16891
|
+
if (r7.sourceMult) parts.push(renderEndLabel(e.sourceEnd, r7.sourceMult, false));
|
|
16892
|
+
if (r7.targetMult) parts.push(renderEndLabel(e.targetEnd, r7.targetMult, false));
|
|
16893
|
+
if (r7.sourceRole) parts.push(renderEndLabel(e.sourceEnd, r7.sourceRole, true));
|
|
16894
|
+
if (r7.targetRole) parts.push(renderEndLabel(e.targetEnd, r7.targetRole, true));
|
|
16895
|
+
if (r7.label && e.labelAnchor) {
|
|
16493
16896
|
parts.push(
|
|
16494
16897
|
text(
|
|
16495
16898
|
{
|
|
@@ -16498,7 +16901,7 @@ function renderEdge4(e) {
|
|
|
16498
16901
|
class: "sx-umlclass-edge-name sx-umlclass-edge-name-halo",
|
|
16499
16902
|
"text-anchor": "middle"
|
|
16500
16903
|
},
|
|
16501
|
-
|
|
16904
|
+
r7.label
|
|
16502
16905
|
)
|
|
16503
16906
|
);
|
|
16504
16907
|
parts.push(
|
|
@@ -16509,19 +16912,19 @@ function renderEdge4(e) {
|
|
|
16509
16912
|
class: "sx-umlclass-edge-name",
|
|
16510
16913
|
"text-anchor": "middle"
|
|
16511
16914
|
},
|
|
16512
|
-
|
|
16915
|
+
r7.label
|
|
16513
16916
|
)
|
|
16514
16917
|
);
|
|
16515
16918
|
}
|
|
16516
16919
|
return group(
|
|
16517
16920
|
{
|
|
16518
16921
|
class: "sx-umlclass-rel",
|
|
16519
|
-
"data-from":
|
|
16520
|
-
"data-to":
|
|
16521
|
-
"data-kind":
|
|
16522
|
-
"data-source-mult":
|
|
16523
|
-
"data-target-mult":
|
|
16524
|
-
"data-name":
|
|
16922
|
+
"data-from": r7.from,
|
|
16923
|
+
"data-to": r7.to,
|
|
16924
|
+
"data-kind": r7.kind,
|
|
16925
|
+
"data-source-mult": r7.sourceMult,
|
|
16926
|
+
"data-target-mult": r7.targetMult,
|
|
16927
|
+
"data-name": r7.label
|
|
16525
16928
|
},
|
|
16526
16929
|
parts
|
|
16527
16930
|
);
|
|
@@ -16676,8 +17079,8 @@ function summariseDiagram(ast, treeCount) {
|
|
|
16676
17079
|
byKind[k] = (byKind[k] ?? 0) + 1;
|
|
16677
17080
|
}
|
|
16678
17081
|
const relsByKind = {};
|
|
16679
|
-
for (const
|
|
16680
|
-
relsByKind[
|
|
17082
|
+
for (const r7 of ast.relationships) {
|
|
17083
|
+
relsByKind[r7.kind] = (relsByKind[r7.kind] ?? 0) + 1;
|
|
16681
17084
|
}
|
|
16682
17085
|
const classifierStr = Object.entries(byKind).map(([k, n]) => `${n} ${k}`).join(", ");
|
|
16683
17086
|
const relStr = Object.entries(relsByKind).map(([k, n]) => `${n} ${k}`).join(", ");
|
|
@@ -16909,9 +17312,9 @@ function validate(ast) {
|
|
|
16909
17312
|
if (!e.gate) continue;
|
|
16910
17313
|
const refs = [...e.gate.inputs];
|
|
16911
17314
|
if (e.gate.condition && isId(e.gate.condition)) refs.push(e.gate.condition);
|
|
16912
|
-
for (const
|
|
16913
|
-
if (!byId.has(
|
|
16914
|
-
throw new FaultTreeParseError(`gate ${e.id} references undefined event '${
|
|
17315
|
+
for (const r7 of refs) {
|
|
17316
|
+
if (!byId.has(r7)) {
|
|
17317
|
+
throw new FaultTreeParseError(`gate ${e.id} references undefined event '${r7}'`);
|
|
16915
17318
|
}
|
|
16916
17319
|
}
|
|
16917
17320
|
if (e.gate.kind === "voting") {
|
|
@@ -16983,9 +17386,9 @@ function parseProb(s, lineNo) {
|
|
|
16983
17386
|
return n;
|
|
16984
17387
|
}
|
|
16985
17388
|
function splitRefs(s, lineNo) {
|
|
16986
|
-
const refs = s.split(",").map((
|
|
16987
|
-
for (const
|
|
16988
|
-
if (!isId(
|
|
17389
|
+
const refs = s.split(",").map((r7) => r7.trim()).filter(Boolean);
|
|
17390
|
+
for (const r7 of refs) {
|
|
17391
|
+
if (!isId(r7)) throw new FaultTreeParseError(`invalid event reference "${r7}"`, lineNo);
|
|
16989
17392
|
}
|
|
16990
17393
|
if (refs.length === 0) throw new FaultTreeParseError(`empty input list`, lineNo);
|
|
16991
17394
|
return refs;
|
|
@@ -17627,7 +18030,7 @@ function renderFaultTreeLayout(layout, config) {
|
|
|
17627
18030
|
const instById = new Map(layout.events.map((e) => [e.instanceId, e]));
|
|
17628
18031
|
const children = [
|
|
17629
18032
|
title(a11y),
|
|
17630
|
-
desc(
|
|
18033
|
+
desc(summarise2(layout)),
|
|
17631
18034
|
styleBlock,
|
|
17632
18035
|
rect({ x: 0, y: 0, width, height, class: "sx-ft-bg" })
|
|
17633
18036
|
];
|
|
@@ -17703,10 +18106,10 @@ function renderEvent(e, showProb) {
|
|
|
17703
18106
|
parts.push(text({ x: e.cx, y: cy + 3, class: "sx-ft-id", "text-anchor": "middle" }, e.event.id));
|
|
17704
18107
|
parts.push(...leafCaption(e, cy + FAULTTREE_CONST.BASIC_R, label, showProb));
|
|
17705
18108
|
} else if (e.role === "undeveloped") {
|
|
17706
|
-
const
|
|
17707
|
-
parts.push(path({ d: `M ${e.cx} ${cy -
|
|
18109
|
+
const r7 = FAULTTREE_CONST.DIAMOND_W / 2;
|
|
18110
|
+
parts.push(path({ d: `M ${e.cx} ${cy - r7} L ${e.cx + r7} ${cy} L ${e.cx} ${cy + r7} L ${e.cx - r7} ${cy} Z`, class: "sx-ft-undeveloped" }));
|
|
17708
18111
|
parts.push(text({ x: e.cx, y: cy + 3, class: "sx-ft-id", "text-anchor": "middle" }, e.event.id));
|
|
17709
|
-
parts.push(...leafCaption(e, cy +
|
|
18112
|
+
parts.push(...leafCaption(e, cy + r7, label, showProb));
|
|
17710
18113
|
} else if (e.role === "house") {
|
|
17711
18114
|
const w = FAULTTREE_CONST.HOUSE_W, h = FAULTTREE_CONST.HOUSE_H, roofH = h * 0.34;
|
|
17712
18115
|
const top = cy - h / 2, bottom = cy + h / 2, L = e.cx - w / 2, R = e.cx + w / 2;
|
|
@@ -17730,7 +18133,7 @@ function leafCaption(e, shapeBottom, label, showProb) {
|
|
|
17730
18133
|
const out = [];
|
|
17731
18134
|
const hasOwnLabel = !!e.event.label && e.event.label !== e.event.id;
|
|
17732
18135
|
if (hasOwnLabel) {
|
|
17733
|
-
out.push(text({ x: e.cx, y: shapeBottom + FAULTTREE_CONST.CAP_GAP, class: "sx-ft-cap", "text-anchor": "middle" },
|
|
18136
|
+
out.push(text({ x: e.cx, y: shapeBottom + FAULTTREE_CONST.CAP_GAP, class: "sx-ft-cap", "text-anchor": "middle" }, clip2(label, 20)));
|
|
17734
18137
|
}
|
|
17735
18138
|
if (showProb && e.event.prob !== void 0) {
|
|
17736
18139
|
const y = shapeBottom + (hasOwnLabel ? FAULTTREE_CONST.CAP_GAP + FAULTTREE_CONST.CAP_LINE_H : FAULTTREE_CONST.CAP_GAP);
|
|
@@ -17788,7 +18191,7 @@ function topProbLabel(analysis) {
|
|
|
17788
18191
|
if (analysis.topProb === void 0) return "P(top) = n/a (missing p)";
|
|
17789
18192
|
return `P(top) = ${fmtProb(analysis.topProb)} (${analysis.method})`;
|
|
17790
18193
|
}
|
|
17791
|
-
function
|
|
18194
|
+
function summarise2(layout) {
|
|
17792
18195
|
const { ast, analysis } = layout;
|
|
17793
18196
|
const counts = {};
|
|
17794
18197
|
for (const e of ast.events) counts[e.kind] = (counts[e.kind] ?? 0) + 1;
|
|
@@ -17818,7 +18221,7 @@ function fmtProb(n) {
|
|
|
17818
18221
|
if (n >= 1e-3) return String(parseFloat(n.toPrecision(3)));
|
|
17819
18222
|
return n.toExponential(2);
|
|
17820
18223
|
}
|
|
17821
|
-
function
|
|
18224
|
+
function clip2(s, n) {
|
|
17822
18225
|
return s.length <= n ? s : s.slice(0, n - 1) + "\u2026";
|
|
17823
18226
|
}
|
|
17824
18227
|
function wrap2(s, perLine) {
|
|
@@ -17836,7 +18239,7 @@ function wrap2(s, perLine) {
|
|
|
17836
18239
|
if (cur) lines.push(cur);
|
|
17837
18240
|
if (lines.length > 2) {
|
|
17838
18241
|
lines.length = 2;
|
|
17839
|
-
lines[1] =
|
|
18242
|
+
lines[1] = clip2(lines[1], perLine);
|
|
17840
18243
|
}
|
|
17841
18244
|
return lines.join("<br/>");
|
|
17842
18245
|
}
|
|
@@ -18325,7 +18728,7 @@ function renderBowtieLayout(layout, config) {
|
|
|
18325
18728
|
);
|
|
18326
18729
|
const children = [
|
|
18327
18730
|
title(a11y),
|
|
18328
|
-
desc(
|
|
18731
|
+
desc(summarise3(layout)),
|
|
18329
18732
|
styleBlock,
|
|
18330
18733
|
rect({ x: 0, y: 0, width, height, class: "sx-bowtie-bg" })
|
|
18331
18734
|
];
|
|
@@ -18415,7 +18818,7 @@ function renderLegend2(layout, fontFamily) {
|
|
|
18415
18818
|
}
|
|
18416
18819
|
return group({ class: "sx-bowtie-legend", "data-role": "legend" }, parts);
|
|
18417
18820
|
}
|
|
18418
|
-
function
|
|
18821
|
+
function summarise3(layout) {
|
|
18419
18822
|
const { ast } = layout;
|
|
18420
18823
|
const barrierCount = layout.boxes.filter((b) => b.role === "barrier").length;
|
|
18421
18824
|
const escCount = layout.boxes.filter((b) => b.role === "escalation").length;
|
|
@@ -18443,11 +18846,11 @@ function wrap3(s, perLine, maxLines) {
|
|
|
18443
18846
|
}
|
|
18444
18847
|
}
|
|
18445
18848
|
if (cur && lines.length < maxLines) lines.push(cur);
|
|
18446
|
-
else if (cur && lines.length === maxLines) lines[maxLines - 1] =
|
|
18849
|
+
else if (cur && lines.length === maxLines) lines[maxLines - 1] = clip3(`${lines[maxLines - 1]} ${cur}`, perLine);
|
|
18447
18850
|
if (lines.length === 0) lines.push(s);
|
|
18448
18851
|
return lines;
|
|
18449
18852
|
}
|
|
18450
|
-
function
|
|
18853
|
+
function clip3(s, n) {
|
|
18451
18854
|
return s.length <= n ? s : s.slice(0, n - 1) + "\u2026";
|
|
18452
18855
|
}
|
|
18453
18856
|
function r4(n) {
|
|
@@ -18953,7 +19356,7 @@ function renderEventTreeLayout(layout, config) {
|
|
|
18953
19356
|
);
|
|
18954
19357
|
const children = [
|
|
18955
19358
|
title(a11y),
|
|
18956
|
-
desc(
|
|
19359
|
+
desc(summarise4(layout)),
|
|
18957
19360
|
styleBlock,
|
|
18958
19361
|
rect({ x: 0, y: 0, width, height, class: "sx-et-bg" })
|
|
18959
19362
|
];
|
|
@@ -19024,7 +19427,7 @@ function renderEventTreeLayout(layout, config) {
|
|
|
19024
19427
|
el("circle", { cx: leaf.x, cy: leaf.y, r: 3, class: "sx-et-dot", ...dom }),
|
|
19025
19428
|
text(
|
|
19026
19429
|
{ x: leaf.x + 10, y: leaf.y - 4, class: "sx-et-outcome", ...dom },
|
|
19027
|
-
|
|
19430
|
+
clip4(seq.outcome, 30)
|
|
19028
19431
|
),
|
|
19029
19432
|
text(
|
|
19030
19433
|
{ x: leaf.x + 10, y: leaf.y + EVENTTREE_CONST.LEAF_LINE_H - 2, class: "sx-et-freq", ...dom },
|
|
@@ -19049,7 +19452,7 @@ function renderEventTreeLayout(layout, config) {
|
|
|
19049
19452
|
children
|
|
19050
19453
|
);
|
|
19051
19454
|
}
|
|
19052
|
-
function
|
|
19455
|
+
function summarise4(layout) {
|
|
19053
19456
|
const { ast, analysis } = layout;
|
|
19054
19457
|
const parts = [
|
|
19055
19458
|
`Event tree for "${ast.initiating.label ?? ast.initiating.id}" (f\u2080 = ${fmtFreq(ast.initiating.freq)}): ${ast.functions.length} function${ast.functions.length === 1 ? "" : "s"}, ${analysis.sequences.length} sequence${analysis.sequences.length === 1 ? "" : "s"}.`
|
|
@@ -19082,7 +19485,7 @@ function fmtProb2(n) {
|
|
|
19082
19485
|
if (n >= 1e-3) return String(parseFloat(n.toPrecision(3)));
|
|
19083
19486
|
return n.toExponential(2);
|
|
19084
19487
|
}
|
|
19085
|
-
function
|
|
19488
|
+
function clip4(s, n) {
|
|
19086
19489
|
return s.length <= n ? s : s.slice(0, n - 1) + "\u2026";
|
|
19087
19490
|
}
|
|
19088
19491
|
|
|
@@ -19528,7 +19931,7 @@ function analyseFmea(ast) {
|
|
|
19528
19931
|
}
|
|
19529
19932
|
for (const act of ast.actions) {
|
|
19530
19933
|
const target = flat.find(
|
|
19531
|
-
(
|
|
19934
|
+
(r7) => r7.mode === act.mode && (act.cause === void 0 || r7.cause === act.cause)
|
|
19532
19935
|
);
|
|
19533
19936
|
if (!target) {
|
|
19534
19937
|
notes.push(`Action references unknown mode/cause "${act.mode}"${act.cause ? ` / "${act.cause}"` : ""}.`);
|
|
@@ -19551,41 +19954,41 @@ function analyseFmea(ast) {
|
|
|
19551
19954
|
rpnDelta: rpn(target.sev, target.occ, target.det) - afterRpn
|
|
19552
19955
|
};
|
|
19553
19956
|
}
|
|
19554
|
-
const rows = flat.map((
|
|
19555
|
-
const r0 = rpn(
|
|
19556
|
-
const ap = actionPriority(
|
|
19957
|
+
const rows = flat.map((r7) => {
|
|
19958
|
+
const r0 = rpn(r7.sev, r7.occ, r7.det);
|
|
19959
|
+
const ap = actionPriority(r7.sev, r7.occ, r7.det);
|
|
19557
19960
|
const flagged = ast.flag ? meetsThreshold(ast.flag, r0, ap) : false;
|
|
19558
19961
|
return {
|
|
19559
19962
|
index: 0,
|
|
19560
|
-
item:
|
|
19561
|
-
fn:
|
|
19562
|
-
mode:
|
|
19563
|
-
effect:
|
|
19564
|
-
effects:
|
|
19565
|
-
sev:
|
|
19566
|
-
cause:
|
|
19567
|
-
occ:
|
|
19568
|
-
det:
|
|
19569
|
-
controls:
|
|
19963
|
+
item: r7.item,
|
|
19964
|
+
fn: r7.fn,
|
|
19965
|
+
mode: r7.mode,
|
|
19966
|
+
effect: r7.effect,
|
|
19967
|
+
effects: r7.effects,
|
|
19968
|
+
sev: r7.sev,
|
|
19969
|
+
cause: r7.cause,
|
|
19970
|
+
occ: r7.occ,
|
|
19971
|
+
det: r7.det,
|
|
19972
|
+
controls: r7.controls,
|
|
19570
19973
|
rpn: r0,
|
|
19571
19974
|
ap,
|
|
19572
19975
|
flagged,
|
|
19573
|
-
action:
|
|
19976
|
+
action: r7.action,
|
|
19574
19977
|
itemFirst: false,
|
|
19575
19978
|
itemSpan: 1,
|
|
19576
19979
|
modeFirst: false,
|
|
19577
19980
|
modeSpan: 1
|
|
19578
19981
|
};
|
|
19579
19982
|
});
|
|
19580
|
-
const orig = new Map(rows.map((
|
|
19983
|
+
const orig = new Map(rows.map((r7, i) => [r7, i]));
|
|
19581
19984
|
rows.sort((a, b) => compareRows(a, b, ast.rank, orig));
|
|
19582
|
-
rows.forEach((
|
|
19583
|
-
|
|
19985
|
+
rows.forEach((r7, i) => {
|
|
19986
|
+
r7.index = i + 1;
|
|
19584
19987
|
});
|
|
19585
19988
|
computeSpans(rows);
|
|
19586
|
-
const flaggedCount = rows.filter((
|
|
19587
|
-
const maxRpn = rows.reduce((m,
|
|
19588
|
-
const hasActions = rows.some((
|
|
19989
|
+
const flaggedCount = rows.filter((r7) => r7.flagged).length;
|
|
19990
|
+
const maxRpn = rows.reduce((m, r7) => Math.max(m, r7.rpn), 0);
|
|
19991
|
+
const hasActions = rows.some((r7) => r7.action !== void 0);
|
|
19589
19992
|
return { rank: ast.rank, rows, flaggedCount, maxRpn, hasActions, notes };
|
|
19590
19993
|
}
|
|
19591
19994
|
function compareRows(a, b, rank, orig) {
|
|
@@ -19649,39 +20052,39 @@ var FMEA_CONST = {
|
|
|
19649
20052
|
function buildColumnSpecs(hasActions, rank) {
|
|
19650
20053
|
const C2 = FMEA_CONST;
|
|
19651
20054
|
const specs = [
|
|
19652
|
-
{ key: "no", label: "#", width: 28, align: "middle", numeric: true, field: (
|
|
20055
|
+
{ key: "no", label: "#", width: 28, align: "middle", numeric: true, field: (r7) => String(r7.index) },
|
|
19653
20056
|
{
|
|
19654
20057
|
key: "item",
|
|
19655
20058
|
label: "Item / Function",
|
|
19656
20059
|
width: 130,
|
|
19657
20060
|
align: "start",
|
|
19658
20061
|
numeric: false,
|
|
19659
|
-
field: (
|
|
19660
|
-
\u2014 ${
|
|
20062
|
+
field: (r7) => r7.fn ? `${r7.item}
|
|
20063
|
+
\u2014 ${r7.fn}` : r7.item
|
|
19661
20064
|
},
|
|
19662
|
-
{ key: "mode", label: "Failure Mode", width: 120, align: "start", numeric: false, field: (
|
|
20065
|
+
{ key: "mode", label: "Failure Mode", width: 120, align: "start", numeric: false, field: (r7) => r7.mode },
|
|
19663
20066
|
{
|
|
19664
20067
|
key: "effect",
|
|
19665
20068
|
label: "Effect(s)",
|
|
19666
20069
|
width: 120,
|
|
19667
20070
|
align: "start",
|
|
19668
20071
|
numeric: false,
|
|
19669
|
-
field: (
|
|
20072
|
+
field: (r7) => r7.effects.length > 1 ? r7.effects.join("; ") : r7.effect
|
|
19670
20073
|
},
|
|
19671
|
-
{ key: "sev", label: "S", width: C2.NUM_COL_W, align: "middle", band: "before", numeric: true, field: (
|
|
19672
|
-
{ key: "cause", label: "Cause(s)", width: 120, align: "start", numeric: false, field: (
|
|
19673
|
-
{ key: "occ", label: "O", width: C2.NUM_COL_W, align: "middle", band: "before", numeric: true, field: (
|
|
20074
|
+
{ key: "sev", label: "S", width: C2.NUM_COL_W, align: "middle", band: "before", numeric: true, field: (r7) => String(r7.sev) },
|
|
20075
|
+
{ key: "cause", label: "Cause(s)", width: 120, align: "start", numeric: false, field: (r7) => r7.cause },
|
|
20076
|
+
{ key: "occ", label: "O", width: C2.NUM_COL_W, align: "middle", band: "before", numeric: true, field: (r7) => String(r7.occ) },
|
|
19674
20077
|
{
|
|
19675
20078
|
key: "controls",
|
|
19676
20079
|
label: "Current Controls",
|
|
19677
20080
|
width: 120,
|
|
19678
20081
|
align: "start",
|
|
19679
20082
|
numeric: false,
|
|
19680
|
-
field: (
|
|
20083
|
+
field: (r7) => controlsText(r7)
|
|
19681
20084
|
},
|
|
19682
|
-
{ key: "det", label: "D", width: C2.NUM_COL_W, align: "middle", band: "before", numeric: true, field: (
|
|
19683
|
-
{ key: "rpn", label: "RPN", width: C2.RPN_COL_W, align: "middle", band: "before", numeric: true, field: (
|
|
19684
|
-
{ key: "ap", label: "AP", width: C2.AP_COL_W, align: "middle", band: "before", numeric: true, field: (
|
|
20085
|
+
{ key: "det", label: "D", width: C2.NUM_COL_W, align: "middle", band: "before", numeric: true, field: (r7) => String(r7.det) },
|
|
20086
|
+
{ key: "rpn", label: "RPN", width: C2.RPN_COL_W, align: "middle", band: "before", numeric: true, field: (r7) => String(r7.rpn) },
|
|
20087
|
+
{ key: "ap", label: "AP", width: C2.AP_COL_W, align: "middle", band: "before", numeric: true, field: (r7) => r7.ap }
|
|
19685
20088
|
];
|
|
19686
20089
|
if (hasActions) {
|
|
19687
20090
|
specs.push(
|
|
@@ -19692,7 +20095,7 @@ function buildColumnSpecs(hasActions, rank) {
|
|
|
19692
20095
|
align: "start",
|
|
19693
20096
|
numeric: false,
|
|
19694
20097
|
afterOnly: true,
|
|
19695
|
-
field: (
|
|
20098
|
+
field: (r7) => actionText(r7)
|
|
19696
20099
|
},
|
|
19697
20100
|
{
|
|
19698
20101
|
key: "rsev",
|
|
@@ -19702,7 +20105,7 @@ function buildColumnSpecs(hasActions, rank) {
|
|
|
19702
20105
|
band: "after",
|
|
19703
20106
|
numeric: true,
|
|
19704
20107
|
afterOnly: true,
|
|
19705
|
-
field: (
|
|
20108
|
+
field: (r7) => r7.action ? String(r7.action.sev) : ""
|
|
19706
20109
|
},
|
|
19707
20110
|
{
|
|
19708
20111
|
key: "rocc",
|
|
@@ -19712,7 +20115,7 @@ function buildColumnSpecs(hasActions, rank) {
|
|
|
19712
20115
|
band: "after",
|
|
19713
20116
|
numeric: true,
|
|
19714
20117
|
afterOnly: true,
|
|
19715
|
-
field: (
|
|
20118
|
+
field: (r7) => r7.action ? String(r7.action.occ) : ""
|
|
19716
20119
|
},
|
|
19717
20120
|
{
|
|
19718
20121
|
key: "rdet",
|
|
@@ -19722,7 +20125,7 @@ function buildColumnSpecs(hasActions, rank) {
|
|
|
19722
20125
|
band: "after",
|
|
19723
20126
|
numeric: true,
|
|
19724
20127
|
afterOnly: true,
|
|
19725
|
-
field: (
|
|
20128
|
+
field: (r7) => r7.action ? String(r7.action.det) : ""
|
|
19726
20129
|
},
|
|
19727
20130
|
{
|
|
19728
20131
|
key: "rrpn",
|
|
@@ -19732,7 +20135,7 @@ function buildColumnSpecs(hasActions, rank) {
|
|
|
19732
20135
|
band: "after",
|
|
19733
20136
|
numeric: true,
|
|
19734
20137
|
afterOnly: true,
|
|
19735
|
-
field: (
|
|
20138
|
+
field: (r7) => r7.action ? String(r7.action.rpn) : ""
|
|
19736
20139
|
},
|
|
19737
20140
|
{
|
|
19738
20141
|
key: "rap",
|
|
@@ -19742,26 +20145,26 @@ function buildColumnSpecs(hasActions, rank) {
|
|
|
19742
20145
|
band: "after",
|
|
19743
20146
|
numeric: true,
|
|
19744
20147
|
afterOnly: true,
|
|
19745
|
-
field: (
|
|
20148
|
+
field: (r7) => r7.action ? r7.action.ap : ""
|
|
19746
20149
|
}
|
|
19747
20150
|
);
|
|
19748
20151
|
}
|
|
19749
20152
|
return specs;
|
|
19750
20153
|
}
|
|
19751
|
-
function controlsText(
|
|
20154
|
+
function controlsText(r7) {
|
|
19752
20155
|
const parts = [];
|
|
19753
|
-
if (
|
|
19754
|
-
if (
|
|
20156
|
+
if (r7.controls?.prevention) parts.push(`P: ${r7.controls.prevention}`);
|
|
20157
|
+
if (r7.controls?.detection) parts.push(`D: ${r7.controls.detection}`);
|
|
19755
20158
|
return parts.join("\n");
|
|
19756
20159
|
}
|
|
19757
|
-
function actionText(
|
|
19758
|
-
if (!
|
|
20160
|
+
function actionText(r7) {
|
|
20161
|
+
if (!r7.action) return "";
|
|
19759
20162
|
const parts = [];
|
|
19760
|
-
if (
|
|
20163
|
+
if (r7.action.recommendation) parts.push(r7.action.recommendation);
|
|
19761
20164
|
const meta = [];
|
|
19762
|
-
if (
|
|
19763
|
-
if (
|
|
19764
|
-
if (
|
|
20165
|
+
if (r7.action.owner) meta.push(r7.action.owner);
|
|
20166
|
+
if (r7.action.target) meta.push(r7.action.target);
|
|
20167
|
+
if (r7.action.status) meta.push(`[${r7.action.status}]`);
|
|
19765
20168
|
if (meta.length) parts.push(meta.join(" \xB7 "));
|
|
19766
20169
|
return parts.join("\n");
|
|
19767
20170
|
}
|
|
@@ -20031,7 +20434,7 @@ function renderFmeaLayout(layout, config) {
|
|
|
20031
20434
|
const style = el("style", {}, buildCss9(p));
|
|
20032
20435
|
const children = [
|
|
20033
20436
|
title(a11y),
|
|
20034
|
-
desc(
|
|
20437
|
+
desc(summarise5(layout)),
|
|
20035
20438
|
style,
|
|
20036
20439
|
rect({ x: 0, y: 0, width, height, class: "sx-fmea-bg" })
|
|
20037
20440
|
];
|
|
@@ -20183,7 +20586,7 @@ function renderHeaderBlock(layout) {
|
|
|
20183
20586
|
function capitalise(s) {
|
|
20184
20587
|
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
20185
20588
|
}
|
|
20186
|
-
function
|
|
20589
|
+
function summarise5(layout) {
|
|
20187
20590
|
const { ast, analysis } = layout;
|
|
20188
20591
|
const top = analysis.rows[0];
|
|
20189
20592
|
const parts = [
|
|
@@ -20235,6 +20638,658 @@ var fmea = {
|
|
|
20235
20638
|
}
|
|
20236
20639
|
};
|
|
20237
20640
|
|
|
20641
|
+
// src/diagrams/rbd/parser.ts
|
|
20642
|
+
function normalizeQuotes2(text2) {
|
|
20643
|
+
return text2.replace(/[“”„«»「」『』"]/g, '"').replace(/[‘’‚']/g, "'");
|
|
20644
|
+
}
|
|
20645
|
+
var RbdParseError = class extends Error {
|
|
20646
|
+
constructor(message) {
|
|
20647
|
+
super(message);
|
|
20648
|
+
this.name = "RbdParseError";
|
|
20649
|
+
}
|
|
20650
|
+
};
|
|
20651
|
+
var HEADER_RE = /^\s*(rbd|reliability(?:blockdiagram)?|reliability-block-diagram)\b/i;
|
|
20652
|
+
var GROUP_KW = /* @__PURE__ */ new Set(["series", "parallel", "kofn", "k-of-n", "voting"]);
|
|
20653
|
+
function parseRbd(text2) {
|
|
20654
|
+
const normalized = normalizeQuotes2(text2);
|
|
20655
|
+
const lines = normalized.split("\n");
|
|
20656
|
+
let headerIdx = -1;
|
|
20657
|
+
for (let i = 0; i < lines.length; i++) {
|
|
20658
|
+
if (lines[i].trim() === "") continue;
|
|
20659
|
+
if (!HEADER_RE.test(lines[i])) {
|
|
20660
|
+
throw new RbdParseError(
|
|
20661
|
+
`RBD must start with 'rbd' (or 'reliability'). Example: rbd "My System"`
|
|
20662
|
+
);
|
|
20663
|
+
}
|
|
20664
|
+
headerIdx = i;
|
|
20665
|
+
break;
|
|
20666
|
+
}
|
|
20667
|
+
if (headerIdx < 0) throw new RbdParseError("Empty RBD input.");
|
|
20668
|
+
const warnings = [];
|
|
20669
|
+
const metadata = {};
|
|
20670
|
+
const headerRest = lines[headerIdx].replace(HEADER_RE, "").trim();
|
|
20671
|
+
const title2 = extractQuoted(headerRest);
|
|
20672
|
+
const body = lines.slice(headerIdx + 1).join("\n");
|
|
20673
|
+
const tokens = tokenize6(stripBodyDirectives(body, metadata));
|
|
20674
|
+
const seenIds = /* @__PURE__ */ new Set();
|
|
20675
|
+
let pos = 0;
|
|
20676
|
+
const peek = () => tokens[pos];
|
|
20677
|
+
const parseBlock = () => {
|
|
20678
|
+
const idTok = tokens[pos++];
|
|
20679
|
+
if (idTok.t !== "word") throw new RbdParseError("Expected a block id.");
|
|
20680
|
+
const id = idTok.v;
|
|
20681
|
+
if (seenIds.has(id)) warnings.push(`Duplicate block id "${id}" \u2014 later definition rendered, ids should be unique.`);
|
|
20682
|
+
seenIds.add(id);
|
|
20683
|
+
let label;
|
|
20684
|
+
let R;
|
|
20685
|
+
if (peek()?.t === "string") {
|
|
20686
|
+
label = tokens[pos++].v;
|
|
20687
|
+
}
|
|
20688
|
+
while (peek()?.t === "word") {
|
|
20689
|
+
const w = peek().v;
|
|
20690
|
+
const attr = parseAttr(w);
|
|
20691
|
+
if (!attr) break;
|
|
20692
|
+
pos++;
|
|
20693
|
+
if (attr.key === "p") R = clamp01(1 - attr.value, w, warnings);
|
|
20694
|
+
else R = clamp01(attr.value, w, warnings);
|
|
20695
|
+
}
|
|
20696
|
+
return { kind: "block", id, ...label !== void 0 ? { label } : {}, ...R !== void 0 ? { R } : {} };
|
|
20697
|
+
};
|
|
20698
|
+
const parseGroup = (kwRaw) => {
|
|
20699
|
+
const kw = kwRaw.toLowerCase();
|
|
20700
|
+
let k;
|
|
20701
|
+
let n;
|
|
20702
|
+
if (kw === "kofn" || kw === "k-of-n" || kw === "voting") {
|
|
20703
|
+
const spec = peek();
|
|
20704
|
+
if (spec?.t === "word" && /^\d+\s*\/\s*\d+$/.test(spec.v)) {
|
|
20705
|
+
pos++;
|
|
20706
|
+
const [ks, ns] = spec.v.split("/");
|
|
20707
|
+
k = parseInt(ks, 10);
|
|
20708
|
+
n = parseInt(ns, 10);
|
|
20709
|
+
} else {
|
|
20710
|
+
throw new RbdParseError(`'${kwRaw}' needs a k/n threshold, e.g. 'kofn 2/3 { \u2026 }'.`);
|
|
20711
|
+
}
|
|
20712
|
+
}
|
|
20713
|
+
if (peek()?.t !== "lbrace") throw new RbdParseError(`Expected '{' after '${kwRaw}'.`);
|
|
20714
|
+
pos++;
|
|
20715
|
+
const children = parseList();
|
|
20716
|
+
if (peek()?.t !== "rbrace") throw new RbdParseError(`Unclosed '${kwRaw}' group \u2014 missing '}'.`);
|
|
20717
|
+
pos++;
|
|
20718
|
+
if (children.length === 0) warnings.push(`Empty '${kwRaw}' group ignored.`);
|
|
20719
|
+
const kind = kw === "series" ? "series" : "parallel";
|
|
20720
|
+
const isKofn = kw === "kofn" || kw === "k-of-n" || kw === "voting";
|
|
20721
|
+
if (isKofn) {
|
|
20722
|
+
const total = n ?? children.length;
|
|
20723
|
+
let thr = k ?? total;
|
|
20724
|
+
if (thr > total) {
|
|
20725
|
+
warnings.push(`k-of-n threshold k=${thr} exceeds n=${total} \u2014 clamped to ${total}.`);
|
|
20726
|
+
thr = total;
|
|
20727
|
+
}
|
|
20728
|
+
if (thr < 1) {
|
|
20729
|
+
warnings.push(`k-of-n threshold k=${thr} < 1 \u2014 clamped to 1.`);
|
|
20730
|
+
thr = 1;
|
|
20731
|
+
}
|
|
20732
|
+
return { kind: "kofn", k: thr, n: total, children };
|
|
20733
|
+
}
|
|
20734
|
+
return { kind, children };
|
|
20735
|
+
};
|
|
20736
|
+
const parseStructure = () => {
|
|
20737
|
+
const tok = peek();
|
|
20738
|
+
if (!tok) throw new RbdParseError("Unexpected end of input.");
|
|
20739
|
+
if (tok.t === "rbrace") throw new RbdParseError("Unexpected '}'.");
|
|
20740
|
+
if (tok.t === "string") throw new RbdParseError(`Unexpected quoted text "${tok.v}" \u2014 labels attach to a block.`);
|
|
20741
|
+
if (tok.t === "lbrace") throw new RbdParseError("Unexpected '{' \u2014 a group keyword (series/parallel/kofn) must precede it.");
|
|
20742
|
+
const w = tok.v;
|
|
20743
|
+
if (GROUP_KW.has(w.toLowerCase())) {
|
|
20744
|
+
pos++;
|
|
20745
|
+
return parseGroup(w);
|
|
20746
|
+
}
|
|
20747
|
+
if (w.toLowerCase() === "block") {
|
|
20748
|
+
pos++;
|
|
20749
|
+
return parseBlock();
|
|
20750
|
+
}
|
|
20751
|
+
return parseBlock();
|
|
20752
|
+
};
|
|
20753
|
+
function parseList() {
|
|
20754
|
+
const items = [];
|
|
20755
|
+
while (pos < tokens.length && peek()?.t !== "rbrace") {
|
|
20756
|
+
items.push(parseStructure());
|
|
20757
|
+
}
|
|
20758
|
+
return items;
|
|
20759
|
+
}
|
|
20760
|
+
const top = parseList();
|
|
20761
|
+
if (pos < tokens.length) throw new RbdParseError("Unbalanced '}' in RBD body.");
|
|
20762
|
+
let root;
|
|
20763
|
+
if (top.length === 0) {
|
|
20764
|
+
throw new RbdParseError("RBD has no blocks. Add at least one `block ID R=\u2026`.");
|
|
20765
|
+
} else if (top.length === 1 && top[0].kind !== "block") {
|
|
20766
|
+
root = top[0];
|
|
20767
|
+
} else {
|
|
20768
|
+
root = { kind: "series", children: top };
|
|
20769
|
+
}
|
|
20770
|
+
return {
|
|
20771
|
+
type: "rbd",
|
|
20772
|
+
...title2 ? { title: title2 } : {},
|
|
20773
|
+
root,
|
|
20774
|
+
warnings,
|
|
20775
|
+
...Object.keys(metadata).length > 0 ? { metadata } : {}
|
|
20776
|
+
};
|
|
20777
|
+
}
|
|
20778
|
+
function tokenize6(src) {
|
|
20779
|
+
const out = [];
|
|
20780
|
+
let i = 0;
|
|
20781
|
+
const n = src.length;
|
|
20782
|
+
const isQuote2 = (c) => c === '"' || c === "'";
|
|
20783
|
+
while (i < n) {
|
|
20784
|
+
const c = src[i];
|
|
20785
|
+
if (c === "#") {
|
|
20786
|
+
while (i < n && src[i] !== "\n") i++;
|
|
20787
|
+
continue;
|
|
20788
|
+
}
|
|
20789
|
+
if (/\s/.test(c)) {
|
|
20790
|
+
i++;
|
|
20791
|
+
continue;
|
|
20792
|
+
}
|
|
20793
|
+
if (c === "{") {
|
|
20794
|
+
out.push({ t: "lbrace" });
|
|
20795
|
+
i++;
|
|
20796
|
+
continue;
|
|
20797
|
+
}
|
|
20798
|
+
if (c === "}") {
|
|
20799
|
+
out.push({ t: "rbrace" });
|
|
20800
|
+
i++;
|
|
20801
|
+
continue;
|
|
20802
|
+
}
|
|
20803
|
+
if (isQuote2(c)) {
|
|
20804
|
+
const close = c;
|
|
20805
|
+
let v2 = "";
|
|
20806
|
+
i++;
|
|
20807
|
+
while (i < n && src[i] !== close) {
|
|
20808
|
+
v2 += src[i];
|
|
20809
|
+
i++;
|
|
20810
|
+
}
|
|
20811
|
+
i++;
|
|
20812
|
+
out.push({ t: "string", v: v2.trim() });
|
|
20813
|
+
continue;
|
|
20814
|
+
}
|
|
20815
|
+
let v = "";
|
|
20816
|
+
while (i < n && !/\s/.test(src[i]) && src[i] !== "{" && src[i] !== "}" && !isQuote2(src[i])) {
|
|
20817
|
+
v += src[i];
|
|
20818
|
+
i++;
|
|
20819
|
+
}
|
|
20820
|
+
out.push({ t: "word", v });
|
|
20821
|
+
}
|
|
20822
|
+
return out;
|
|
20823
|
+
}
|
|
20824
|
+
function stripBodyDirectives(body, metadata) {
|
|
20825
|
+
return body.split("\n").filter((line2) => {
|
|
20826
|
+
const m = line2.match(/^\s*(title|standard|note)\s*:\s*(.+)$/i);
|
|
20827
|
+
if (m) {
|
|
20828
|
+
const key = m[1].toLowerCase();
|
|
20829
|
+
if (key !== "title") metadata[key] = m[2].trim();
|
|
20830
|
+
else metadata.title = m[2].trim();
|
|
20831
|
+
return false;
|
|
20832
|
+
}
|
|
20833
|
+
return true;
|
|
20834
|
+
}).join("\n");
|
|
20835
|
+
}
|
|
20836
|
+
function extractQuoted(s) {
|
|
20837
|
+
const m = s.match(/^["']([^"']*)["']/);
|
|
20838
|
+
if (m) return m[1].trim();
|
|
20839
|
+
return s.length > 0 ? s.trim() : void 0;
|
|
20840
|
+
}
|
|
20841
|
+
function parseAttr(w) {
|
|
20842
|
+
const m = w.match(/^(R|r|p|prob|q)\s*[=:]\s*(.+)$/);
|
|
20843
|
+
if (m) {
|
|
20844
|
+
const key = m[1].toLowerCase();
|
|
20845
|
+
const value = parseNum(m[2]);
|
|
20846
|
+
if (value === void 0) return null;
|
|
20847
|
+
return { key: key === "p" || key === "q" ? "p" : "R", value };
|
|
20848
|
+
}
|
|
20849
|
+
const bare = parseNum(w);
|
|
20850
|
+
if (bare !== void 0) return { key: "R", value: bare };
|
|
20851
|
+
return null;
|
|
20852
|
+
}
|
|
20853
|
+
function parseNum(s) {
|
|
20854
|
+
const t = s.trim();
|
|
20855
|
+
if (/%$/.test(t)) {
|
|
20856
|
+
const v2 = parseFloat(t.slice(0, -1));
|
|
20857
|
+
return Number.isFinite(v2) ? v2 / 100 : void 0;
|
|
20858
|
+
}
|
|
20859
|
+
const v = parseFloat(t);
|
|
20860
|
+
return Number.isFinite(v) ? v : void 0;
|
|
20861
|
+
}
|
|
20862
|
+
function clamp01(v, raw, warnings) {
|
|
20863
|
+
if (v < 0) {
|
|
20864
|
+
warnings.push(`Reliability ${raw} < 0 \u2014 clamped to 0.`);
|
|
20865
|
+
return 0;
|
|
20866
|
+
}
|
|
20867
|
+
if (v > 1) {
|
|
20868
|
+
warnings.push(`Reliability ${raw} > 1 \u2014 clamped to 1.`);
|
|
20869
|
+
return 1;
|
|
20870
|
+
}
|
|
20871
|
+
return v;
|
|
20872
|
+
}
|
|
20873
|
+
|
|
20874
|
+
// src/diagrams/rbd/analysis.ts
|
|
20875
|
+
var KOFN_ENUM_CAP = 18;
|
|
20876
|
+
function analyseRbd(ast) {
|
|
20877
|
+
const notes = [];
|
|
20878
|
+
const warnings = [...ast.warnings];
|
|
20879
|
+
const blocks = [];
|
|
20880
|
+
collectBlocks(ast.root, blocks);
|
|
20881
|
+
const missing = blocks.filter((b) => b.R === void 0).map((b) => b.id);
|
|
20882
|
+
const baseEnv = new Map(blocks.map((b) => [b.id, b.R]));
|
|
20883
|
+
const systemReliability = evalStructure(ast.root, baseEnv, notes);
|
|
20884
|
+
const results = blocks.map((b) => {
|
|
20885
|
+
if (systemReliability === void 0) {
|
|
20886
|
+
return { id: b.id, ...b.R !== void 0 ? { R: b.R } : {}, isSpof: false };
|
|
20887
|
+
}
|
|
20888
|
+
const up = new Map(baseEnv);
|
|
20889
|
+
up.set(b.id, 1);
|
|
20890
|
+
const down = new Map(baseEnv);
|
|
20891
|
+
down.set(b.id, 0);
|
|
20892
|
+
const rUp = evalStructure(ast.root, up, notes);
|
|
20893
|
+
const rDown = evalStructure(ast.root, down, notes);
|
|
20894
|
+
const importance = rUp !== void 0 && rDown !== void 0 ? rUp - rDown : void 0;
|
|
20895
|
+
const isSpof = rDown === 0;
|
|
20896
|
+
return {
|
|
20897
|
+
id: b.id,
|
|
20898
|
+
...b.R !== void 0 ? { R: b.R } : {},
|
|
20899
|
+
...importance !== void 0 ? { importance } : {},
|
|
20900
|
+
isSpof
|
|
20901
|
+
};
|
|
20902
|
+
});
|
|
20903
|
+
let criticalBlock;
|
|
20904
|
+
let best = -Infinity;
|
|
20905
|
+
for (const r7 of results) {
|
|
20906
|
+
if (r7.importance !== void 0 && r7.importance > best) {
|
|
20907
|
+
best = r7.importance;
|
|
20908
|
+
criticalBlock = r7.id;
|
|
20909
|
+
}
|
|
20910
|
+
}
|
|
20911
|
+
if (systemReliability !== void 0) {
|
|
20912
|
+
const spofs = results.filter((r7) => r7.isSpof).map((r7) => r7.id);
|
|
20913
|
+
if (spofs.length === 0) notes.push("No single point of failure \u2014 every block has redundancy in the success path.");
|
|
20914
|
+
}
|
|
20915
|
+
return {
|
|
20916
|
+
...systemReliability !== void 0 ? { systemReliability } : {},
|
|
20917
|
+
blocks: results,
|
|
20918
|
+
missing,
|
|
20919
|
+
...criticalBlock ? { criticalBlock } : {},
|
|
20920
|
+
warnings,
|
|
20921
|
+
notes
|
|
20922
|
+
};
|
|
20923
|
+
}
|
|
20924
|
+
function collectBlocks(s, out) {
|
|
20925
|
+
if (s.kind === "block") {
|
|
20926
|
+
out.push({ id: s.id, ...s.R !== void 0 ? { R: s.R } : {} });
|
|
20927
|
+
return;
|
|
20928
|
+
}
|
|
20929
|
+
for (const c of s.children) collectBlocks(c, out);
|
|
20930
|
+
}
|
|
20931
|
+
function evalStructure(s, env, notes) {
|
|
20932
|
+
if (s.kind === "block") return env.get(s.id);
|
|
20933
|
+
const childR = s.children.map((c) => evalStructure(c, env, notes));
|
|
20934
|
+
if (childR.some((r7) => r7 === void 0)) return void 0;
|
|
20935
|
+
const rs = childR;
|
|
20936
|
+
if (rs.length === 0) return 1;
|
|
20937
|
+
if (s.kind === "series") {
|
|
20938
|
+
return rs.reduce((p, r7) => p * r7, 1);
|
|
20939
|
+
}
|
|
20940
|
+
if (s.kind === "parallel") {
|
|
20941
|
+
return 1 - rs.reduce((p, r7) => p * (1 - r7), 1);
|
|
20942
|
+
}
|
|
20943
|
+
const n = rs.length;
|
|
20944
|
+
const k = Math.min(Math.max(s.k ?? n, 1), n);
|
|
20945
|
+
if (n > KOFN_ENUM_CAP) {
|
|
20946
|
+
notes.push(`k-of-n group with n=${n} exceeds the exact-enumeration cap (${KOFN_ENUM_CAP}); reported as a parallel bound.`);
|
|
20947
|
+
return 1 - rs.reduce((p, r7) => p * (1 - r7), 1);
|
|
20948
|
+
}
|
|
20949
|
+
return kofnReliability(rs, k);
|
|
20950
|
+
}
|
|
20951
|
+
function kofnReliability(rs, k) {
|
|
20952
|
+
const n = rs.length;
|
|
20953
|
+
let total = 0;
|
|
20954
|
+
for (let mask = 0; mask < 1 << n; mask++) {
|
|
20955
|
+
let working = 0;
|
|
20956
|
+
let prob = 1;
|
|
20957
|
+
for (let i = 0; i < n; i++) {
|
|
20958
|
+
if (mask & 1 << i) {
|
|
20959
|
+
working++;
|
|
20960
|
+
prob *= rs[i];
|
|
20961
|
+
} else prob *= 1 - rs[i];
|
|
20962
|
+
}
|
|
20963
|
+
if (working >= k) total += prob;
|
|
20964
|
+
}
|
|
20965
|
+
return total;
|
|
20966
|
+
}
|
|
20967
|
+
|
|
20968
|
+
// src/diagrams/rbd/layout.ts
|
|
20969
|
+
var RBD_CONST = {
|
|
20970
|
+
BLOCK_H: 46,
|
|
20971
|
+
BLOCK_MIN_W: 96,
|
|
20972
|
+
BLOCK_MAX_W: 200,
|
|
20973
|
+
BLOCK_RX: 5,
|
|
20974
|
+
CHAR_W: 6.9,
|
|
20975
|
+
PAD_X: 14,
|
|
20976
|
+
/** Horizontal wire length between series members. */
|
|
20977
|
+
H_GAP: 44,
|
|
20978
|
+
/** Vertical gap between parallel rails. */
|
|
20979
|
+
V_GAP: 26,
|
|
20980
|
+
/** Fan-out / merge horizontal stub flanking a parallel group. */
|
|
20981
|
+
SPLIT_STUB: 30,
|
|
20982
|
+
NODE_R: 3.5,
|
|
20983
|
+
/** Input/output terminal stub at the network ends. */
|
|
20984
|
+
TERM_STUB: 30,
|
|
20985
|
+
CAP_GAP: 15,
|
|
20986
|
+
CAP_LINE_H: 13,
|
|
20987
|
+
CANVAS_PAD: 28,
|
|
20988
|
+
TITLE_H: 32,
|
|
20989
|
+
HEADER_H: 26
|
|
20990
|
+
};
|
|
20991
|
+
function blockWidth(label) {
|
|
20992
|
+
const C2 = RBD_CONST;
|
|
20993
|
+
return Math.min(C2.BLOCK_MAX_W, Math.max(C2.BLOCK_MIN_W, Math.ceil(label.length * C2.CHAR_W) + 2 * C2.PAD_X));
|
|
20994
|
+
}
|
|
20995
|
+
function layoutRbd(ast) {
|
|
20996
|
+
const C2 = RBD_CONST;
|
|
20997
|
+
const analysis = analyseRbd(ast);
|
|
20998
|
+
const spof = new Set(analysis.blocks.filter((b) => b.isSpof).map((b) => b.id));
|
|
20999
|
+
const rById = new Map(analysis.blocks.map((b) => [b.id, b.R]));
|
|
21000
|
+
const blocks = [];
|
|
21001
|
+
const nodes = [];
|
|
21002
|
+
const wires = [];
|
|
21003
|
+
const marks = [];
|
|
21004
|
+
const measure = (s) => {
|
|
21005
|
+
if (s.kind === "block") {
|
|
21006
|
+
return { s, w: blockWidth(s.label ?? s.id), h: C2.BLOCK_H, children: [] };
|
|
21007
|
+
}
|
|
21008
|
+
const children = s.children.map(measure);
|
|
21009
|
+
if (children.length === 0) return { s, w: C2.BLOCK_MIN_W, h: C2.BLOCK_H, children };
|
|
21010
|
+
if (s.kind === "series") {
|
|
21011
|
+
const w2 = children.reduce((acc, c) => acc + c.w, 0) + C2.H_GAP * (children.length - 1);
|
|
21012
|
+
const h2 = Math.max(...children.map((c) => c.h));
|
|
21013
|
+
return { s, w: w2, h: h2, children };
|
|
21014
|
+
}
|
|
21015
|
+
const innerW = Math.max(...children.map((c) => c.w));
|
|
21016
|
+
const w = innerW + 2 * C2.SPLIT_STUB;
|
|
21017
|
+
const h = children.reduce((acc, c) => acc + c.h, 0) + C2.V_GAP * (children.length - 1);
|
|
21018
|
+
return { s, w, h, children };
|
|
21019
|
+
};
|
|
21020
|
+
const place = (m, x, yc2) => {
|
|
21021
|
+
const s = m.s;
|
|
21022
|
+
if (s.kind === "block") {
|
|
21023
|
+
const r7 = rById.get(s.id);
|
|
21024
|
+
blocks.push({
|
|
21025
|
+
block: s,
|
|
21026
|
+
x,
|
|
21027
|
+
y: yc2 - C2.BLOCK_H / 2,
|
|
21028
|
+
width: m.w,
|
|
21029
|
+
height: C2.BLOCK_H,
|
|
21030
|
+
...r7 !== void 0 ? { R: r7 } : {},
|
|
21031
|
+
isSpof: spof.has(s.id),
|
|
21032
|
+
critical: analysis.criticalBlock === s.id
|
|
21033
|
+
});
|
|
21034
|
+
return { entryX: x, exitX: x + m.w };
|
|
21035
|
+
}
|
|
21036
|
+
if (s.kind === "series") {
|
|
21037
|
+
let cursor = x;
|
|
21038
|
+
let prevExit = null;
|
|
21039
|
+
let firstEntry = x;
|
|
21040
|
+
let lastExit = x;
|
|
21041
|
+
m.children.forEach((cm, i) => {
|
|
21042
|
+
const ep2 = place(cm, cursor, yc2);
|
|
21043
|
+
if (i === 0) firstEntry = ep2.entryX;
|
|
21044
|
+
if (prevExit !== null) wires.push({ path: `M ${r6(prevExit)} ${r6(yc2)} L ${r6(ep2.entryX)} ${r6(yc2)}` });
|
|
21045
|
+
prevExit = ep2.exitX;
|
|
21046
|
+
lastExit = ep2.exitX;
|
|
21047
|
+
cursor = ep2.exitX + C2.H_GAP;
|
|
21048
|
+
});
|
|
21049
|
+
return { entryX: firstEntry, exitX: lastExit };
|
|
21050
|
+
}
|
|
21051
|
+
const innerW = Math.max(...m.children.map((c) => c.w));
|
|
21052
|
+
const splitX = x + C2.NODE_R;
|
|
21053
|
+
const mergeX = x + m.w - C2.NODE_R;
|
|
21054
|
+
const childBandX = x + C2.SPLIT_STUB;
|
|
21055
|
+
nodes.push({ kind: "split", x: splitX, y: yc2 });
|
|
21056
|
+
nodes.push({ kind: "join", x: mergeX, y: yc2 });
|
|
21057
|
+
let runY = yc2 - m.h / 2;
|
|
21058
|
+
for (const cm of m.children) {
|
|
21059
|
+
const childYc = runY + cm.h / 2;
|
|
21060
|
+
const childStartX = childBandX + (innerW - cm.w) / 2;
|
|
21061
|
+
const ep2 = place(cm, childStartX, childYc);
|
|
21062
|
+
wires.push({ path: `M ${r6(splitX)} ${r6(yc2)} L ${r6(splitX)} ${r6(childYc)} L ${r6(ep2.entryX)} ${r6(childYc)}` });
|
|
21063
|
+
wires.push({ path: `M ${r6(ep2.exitX)} ${r6(childYc)} L ${r6(mergeX)} ${r6(childYc)} L ${r6(mergeX)} ${r6(yc2)}` });
|
|
21064
|
+
runY += cm.h + C2.V_GAP;
|
|
21065
|
+
}
|
|
21066
|
+
if (s.kind === "kofn") {
|
|
21067
|
+
marks.push({ x: mergeX + 6, y: yc2 - m.h / 2 - 6, text: `${s.k}/${s.n ?? m.children.length}` });
|
|
21068
|
+
}
|
|
21069
|
+
return { entryX: splitX, exitX: mergeX };
|
|
21070
|
+
};
|
|
21071
|
+
const rootM = measure(ast.root);
|
|
21072
|
+
const headerH = (ast.title ? C2.TITLE_H : 0) + C2.HEADER_H;
|
|
21073
|
+
const yc = C2.CANVAS_PAD + headerH + rootM.h / 2;
|
|
21074
|
+
const originX = C2.CANVAS_PAD + C2.TERM_STUB;
|
|
21075
|
+
const ep = place(rootM, originX, yc);
|
|
21076
|
+
const inX = C2.CANVAS_PAD;
|
|
21077
|
+
const outX = ep.exitX + C2.TERM_STUB;
|
|
21078
|
+
nodes.push({ kind: "in", x: inX, y: yc });
|
|
21079
|
+
nodes.push({ kind: "out", x: outX, y: yc });
|
|
21080
|
+
wires.push({ path: `M ${r6(inX)} ${r6(yc)} L ${r6(ep.entryX)} ${r6(yc)}` });
|
|
21081
|
+
wires.push({ path: `M ${r6(ep.exitX)} ${r6(yc)} L ${r6(outX)} ${r6(yc)}` });
|
|
21082
|
+
let maxX = outX;
|
|
21083
|
+
let maxY = yc + rootM.h / 2;
|
|
21084
|
+
for (const b of blocks) {
|
|
21085
|
+
maxX = Math.max(maxX, b.x + b.width);
|
|
21086
|
+
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 ? C2.CAP_GAP + capLines * C2.CAP_LINE_H : 0));
|
|
21088
|
+
}
|
|
21089
|
+
for (const mk of marks) maxX = Math.max(maxX, mk.x + 24);
|
|
21090
|
+
return {
|
|
21091
|
+
ast,
|
|
21092
|
+
analysis,
|
|
21093
|
+
blocks,
|
|
21094
|
+
nodes,
|
|
21095
|
+
wires,
|
|
21096
|
+
marks,
|
|
21097
|
+
width: Math.ceil(maxX + C2.CANVAS_PAD),
|
|
21098
|
+
height: Math.ceil(maxY + C2.CANVAS_PAD)
|
|
21099
|
+
};
|
|
21100
|
+
}
|
|
21101
|
+
function r6(n) {
|
|
21102
|
+
return Math.round(n * 10) / 10;
|
|
21103
|
+
}
|
|
21104
|
+
|
|
21105
|
+
// src/diagrams/rbd/renderer.ts
|
|
21106
|
+
function renderRbd(text2, config) {
|
|
21107
|
+
const ast = parseRbd(text2);
|
|
21108
|
+
const layout = layoutRbd(ast);
|
|
21109
|
+
return renderRbdLayout(layout, config);
|
|
21110
|
+
}
|
|
21111
|
+
function renderRbdLayout(layout, config) {
|
|
21112
|
+
const theme = resolveReliabilityTheme(config?.theme ?? "default");
|
|
21113
|
+
const fontFamily = config?.fontFamily ?? DEFAULT_FONT_FAMILY;
|
|
21114
|
+
const pad = config?.padding ?? 0;
|
|
21115
|
+
const { ast, analysis } = layout;
|
|
21116
|
+
const width = layout.width + pad * 2;
|
|
21117
|
+
const height = layout.height + pad * 2;
|
|
21118
|
+
const a11y = ast.title ?? "Reliability block diagram";
|
|
21119
|
+
const styleBlock = el(
|
|
21120
|
+
"style",
|
|
21121
|
+
{},
|
|
21122
|
+
`
|
|
21123
|
+
.sx-rbd-bg { fill: ${theme.bg}; }
|
|
21124
|
+
.sx-rbd-wire { fill: none; stroke: ${theme.edgeStroke}; stroke-width: ${STROKE_WIDTH.normal}; }
|
|
21125
|
+
.sx-rbd-node { fill: ${theme.edgeStroke}; stroke: none; }
|
|
21126
|
+
.sx-rbd-term { fill: ${theme.eventFill}; stroke: ${theme.eventStroke}; stroke-width: ${STROKE_WIDTH.normal}; }
|
|
21127
|
+
.sx-rbd-block { fill: ${theme.eventFill}; stroke: ${theme.eventStroke}; stroke-width: ${STROKE_WIDTH.normal}; }
|
|
21128
|
+
.sx-rbd-block[data-spof="true"] { stroke: ${theme.spofStroke}; stroke-width: ${STROKE_WIDTH.thick}; }
|
|
21129
|
+
.sx-rbd-block[data-critical="true"] { stroke: ${theme.gateStroke}; stroke-width: 2.25; }
|
|
21130
|
+
.sx-rbd-label { fill: ${theme.eventStroke}; font-size: ${FONT_SIZE.label}px; font-weight: 600; }
|
|
21131
|
+
.sx-rbd-r { fill: ${theme.probText}; font-size: ${FONT_SIZE.small}px; font-weight: 600; }
|
|
21132
|
+
.sx-rbd-mark { fill: ${theme.gateStroke}; font-size: ${FONT_SIZE.small}px; font-weight: 700; }
|
|
21133
|
+
.sx-rbd-rsys { fill: ${theme.probText}; font-size: ${FONT_SIZE.label + 1}px; font-weight: 700; }
|
|
21134
|
+
.sx-rbd-title { fill: ${theme.eventStroke}; font-size: ${FONT_SIZE.title}px; font-weight: 700; }
|
|
21135
|
+
`.trim()
|
|
21136
|
+
);
|
|
21137
|
+
const children = [
|
|
21138
|
+
title(a11y),
|
|
21139
|
+
desc(summarise6(layout)),
|
|
21140
|
+
styleBlock,
|
|
21141
|
+
rect({ x: 0, y: 0, width, height, class: "sx-rbd-bg" })
|
|
21142
|
+
];
|
|
21143
|
+
const inner = [];
|
|
21144
|
+
if (ast.title) {
|
|
21145
|
+
inner.push(
|
|
21146
|
+
text(
|
|
21147
|
+
{ x: RBD_CONST.CANVAS_PAD, y: 22, class: "sx-rbd-title", "font-family": fontFamily },
|
|
21148
|
+
ast.title
|
|
21149
|
+
)
|
|
21150
|
+
);
|
|
21151
|
+
}
|
|
21152
|
+
inner.push(
|
|
21153
|
+
text(
|
|
21154
|
+
{
|
|
21155
|
+
x: layout.width / 2,
|
|
21156
|
+
y: (ast.title ? RBD_CONST.TITLE_H : 0) + 18,
|
|
21157
|
+
class: "sx-rbd-rsys",
|
|
21158
|
+
"text-anchor": "middle"
|
|
21159
|
+
},
|
|
21160
|
+
systemLabel(analysis)
|
|
21161
|
+
)
|
|
21162
|
+
);
|
|
21163
|
+
for (const w of layout.wires) inner.push(path({ d: w.path, class: "sx-rbd-wire" }));
|
|
21164
|
+
for (const n of layout.nodes) {
|
|
21165
|
+
if (n.kind === "in" || n.kind === "out") {
|
|
21166
|
+
inner.push(circle({ cx: n.x, cy: n.y, r: 6, class: "sx-rbd-term", "data-node": n.kind }));
|
|
21167
|
+
} else {
|
|
21168
|
+
inner.push(circle({ cx: n.x, cy: n.y, r: RBD_CONST.NODE_R, class: "sx-rbd-node", "data-node": n.kind }));
|
|
21169
|
+
}
|
|
21170
|
+
}
|
|
21171
|
+
for (const mk of layout.marks) {
|
|
21172
|
+
inner.push(text({ x: mk.x, y: mk.y, class: "sx-rbd-mark" }, mk.text));
|
|
21173
|
+
}
|
|
21174
|
+
for (const b of layout.blocks) inner.push(renderBlock(b));
|
|
21175
|
+
children.push(
|
|
21176
|
+
group({ transform: pad ? `translate(${pad}, ${pad})` : void 0, "font-family": fontFamily }, inner)
|
|
21177
|
+
);
|
|
21178
|
+
return svgRoot(
|
|
21179
|
+
{
|
|
21180
|
+
width,
|
|
21181
|
+
height,
|
|
21182
|
+
viewBox: `0 0 ${width} ${height}`,
|
|
21183
|
+
role: "img",
|
|
21184
|
+
"aria-label": a11y,
|
|
21185
|
+
"data-diagram-type": "rbd"
|
|
21186
|
+
},
|
|
21187
|
+
children
|
|
21188
|
+
);
|
|
21189
|
+
}
|
|
21190
|
+
function renderBlock(b) {
|
|
21191
|
+
const cx = b.x + b.width / 2;
|
|
21192
|
+
const cy = b.y + b.height / 2;
|
|
21193
|
+
const label = b.block.label ?? b.block.id;
|
|
21194
|
+
const parts = [
|
|
21195
|
+
rect({
|
|
21196
|
+
x: b.x,
|
|
21197
|
+
y: b.y,
|
|
21198
|
+
width: b.width,
|
|
21199
|
+
height: b.height,
|
|
21200
|
+
rx: RBD_CONST.BLOCK_RX,
|
|
21201
|
+
class: "sx-rbd-block",
|
|
21202
|
+
...b.isSpof ? { "data-spof": "true" } : {},
|
|
21203
|
+
...b.critical && !b.isSpof ? { "data-critical": "true" } : {}
|
|
21204
|
+
}),
|
|
21205
|
+
multilineText(
|
|
21206
|
+
{ x: cx, y: cy, class: "sx-rbd-label", "text-anchor": "middle", "dominant-baseline": "middle" },
|
|
21207
|
+
wrap4(label, 18),
|
|
21208
|
+
13
|
|
21209
|
+
)
|
|
21210
|
+
];
|
|
21211
|
+
if (b.R !== void 0) {
|
|
21212
|
+
parts.push(
|
|
21213
|
+
text(
|
|
21214
|
+
{ x: cx, y: b.y + b.height + RBD_CONST.CAP_GAP, class: "sx-rbd-r", "text-anchor": "middle" },
|
|
21215
|
+
`R=${fmtR(b.R)}`
|
|
21216
|
+
)
|
|
21217
|
+
);
|
|
21218
|
+
}
|
|
21219
|
+
return group(
|
|
21220
|
+
{
|
|
21221
|
+
class: "sx-rbd-block-g",
|
|
21222
|
+
"data-id": b.block.id,
|
|
21223
|
+
...b.R !== void 0 ? { "data-r": String(b.R) } : {},
|
|
21224
|
+
...b.isSpof ? { "data-spof": "true" } : {},
|
|
21225
|
+
...b.critical ? { "data-critical": "true" } : {}
|
|
21226
|
+
},
|
|
21227
|
+
parts
|
|
21228
|
+
);
|
|
21229
|
+
}
|
|
21230
|
+
function systemLabel(analysis) {
|
|
21231
|
+
if (analysis.systemReliability === void 0) {
|
|
21232
|
+
const miss = analysis.missing.length > 0 ? ` \u2014 missing R on ${analysis.missing.join(", ")}` : "";
|
|
21233
|
+
return `System reliability: n/a${miss}`;
|
|
21234
|
+
}
|
|
21235
|
+
return `System reliability R = ${fmtR(analysis.systemReliability)}`;
|
|
21236
|
+
}
|
|
21237
|
+
function fmtR(n) {
|
|
21238
|
+
if (n >= 1) return "1";
|
|
21239
|
+
if (n <= 0) return "0";
|
|
21240
|
+
for (let p = 5; p <= 9; p++) {
|
|
21241
|
+
const s = parseFloat(n.toPrecision(p));
|
|
21242
|
+
if (s < 1) return String(s);
|
|
21243
|
+
}
|
|
21244
|
+
return String(parseFloat(n.toPrecision(9)));
|
|
21245
|
+
}
|
|
21246
|
+
function summarise6(layout) {
|
|
21247
|
+
const { analysis } = layout;
|
|
21248
|
+
const n = layout.blocks.length;
|
|
21249
|
+
const parts = [`Reliability block diagram: ${n} block${n === 1 ? "" : "s"}.`];
|
|
21250
|
+
if (analysis.systemReliability !== void 0) {
|
|
21251
|
+
parts.push(`System reliability R = ${fmtR(analysis.systemReliability)}.`);
|
|
21252
|
+
} else if (analysis.missing.length > 0) {
|
|
21253
|
+
parts.push(`System reliability n/a \u2014 missing R on ${analysis.missing.join(", ")}.`);
|
|
21254
|
+
}
|
|
21255
|
+
const spofs = analysis.blocks.filter((b) => b.isSpof).map((b) => b.id);
|
|
21256
|
+
if (spofs.length > 0) parts.push(`Single point${spofs.length > 1 ? "s" : ""} of failure: ${spofs.join(", ")}.`);
|
|
21257
|
+
if (analysis.criticalBlock) parts.push(`Highest reliability-importance block: ${analysis.criticalBlock}.`);
|
|
21258
|
+
for (const note of analysis.notes) parts.push(note);
|
|
21259
|
+
for (const w of analysis.warnings) parts.push(w);
|
|
21260
|
+
return parts.join(" ");
|
|
21261
|
+
}
|
|
21262
|
+
function wrap4(s, perLine) {
|
|
21263
|
+
if (s.length <= perLine) return s;
|
|
21264
|
+
const words = s.split(/\s+/);
|
|
21265
|
+
const lines = [];
|
|
21266
|
+
let cur = "";
|
|
21267
|
+
for (const w of words) {
|
|
21268
|
+
if (cur && cur.length + 1 + w.length > perLine) {
|
|
21269
|
+
lines.push(cur);
|
|
21270
|
+
cur = w;
|
|
21271
|
+
} else cur = cur ? `${cur} ${w}` : w;
|
|
21272
|
+
}
|
|
21273
|
+
if (cur) lines.push(cur);
|
|
21274
|
+
if (lines.length > 2) {
|
|
21275
|
+
lines.length = 2;
|
|
21276
|
+
lines[1] = lines[1].slice(0, perLine - 1) + "\u2026";
|
|
21277
|
+
}
|
|
21278
|
+
return lines.join("<br/>");
|
|
21279
|
+
}
|
|
21280
|
+
|
|
21281
|
+
// src/diagrams/rbd/index.ts
|
|
21282
|
+
var rbd = {
|
|
21283
|
+
type: "rbd",
|
|
21284
|
+
detect(text2) {
|
|
21285
|
+
return /^\s*(rbd|reliability(?:blockdiagram)?|reliability-block-diagram)\b/i.test(text2);
|
|
21286
|
+
},
|
|
21287
|
+
parse: parseRbd,
|
|
21288
|
+
render(text2, config) {
|
|
21289
|
+
return renderRbd(text2, config);
|
|
21290
|
+
}
|
|
21291
|
+
};
|
|
21292
|
+
|
|
20238
21293
|
// src/diagrams/causalloop/parser.ts
|
|
20239
21294
|
var CausalLoopParseError = class extends Error {
|
|
20240
21295
|
constructor(message, line2) {
|
|
@@ -20928,7 +21983,7 @@ function renderCausalLoopLayout(layout, config) {
|
|
|
20928
21983
|
);
|
|
20929
21984
|
const children = [
|
|
20930
21985
|
title(a11y),
|
|
20931
|
-
desc(
|
|
21986
|
+
desc(summarise7(layout)),
|
|
20932
21987
|
styleBlock,
|
|
20933
21988
|
el("rect", { x: 0, y: 0, width, height, class: "sx-cld-bg" })
|
|
20934
21989
|
];
|
|
@@ -21042,17 +22097,17 @@ function arrowhead(x, y, tx, ty) {
|
|
|
21042
22097
|
return polygon({ points: `${tip} ${p1} ${p2}`, class: "sx-cld-arrow" });
|
|
21043
22098
|
}
|
|
21044
22099
|
function renderGlyph(g) {
|
|
21045
|
-
const
|
|
22100
|
+
const r7 = g.r;
|
|
21046
22101
|
const startAng = -Math.PI / 2;
|
|
21047
22102
|
const sweep = 300 * Math.PI / 180;
|
|
21048
22103
|
const endAng = g.clockwise ? startAng + sweep : startAng - sweep;
|
|
21049
|
-
const sx = g.cx +
|
|
21050
|
-
const sy = g.cy +
|
|
21051
|
-
const ex = g.cx +
|
|
21052
|
-
const ey = g.cy +
|
|
22104
|
+
const sx = g.cx + r7 * Math.cos(startAng);
|
|
22105
|
+
const sy = g.cy + r7 * Math.sin(startAng);
|
|
22106
|
+
const ex = g.cx + r7 * Math.cos(endAng);
|
|
22107
|
+
const ey = g.cy + r7 * Math.sin(endAng);
|
|
21053
22108
|
const largeArc = 1;
|
|
21054
22109
|
const sweepFlag = g.clockwise ? 1 : 0;
|
|
21055
|
-
const arc = `M ${fmt4(sx)} ${fmt4(sy)} A ${
|
|
22110
|
+
const arc = `M ${fmt4(sx)} ${fmt4(sy)} A ${r7} ${r7} 0 ${largeArc} ${sweepFlag} ${fmt4(ex)} ${fmt4(ey)}`;
|
|
21056
22111
|
const dir = g.clockwise ? 1 : -1;
|
|
21057
22112
|
const tx = -Math.sin(endAng) * dir;
|
|
21058
22113
|
const ty = Math.cos(endAng) * dir;
|
|
@@ -21097,7 +22152,7 @@ function glyphArrow(x, y, tx, ty) {
|
|
|
21097
22152
|
const p2 = `${fmt4(bx - px * wide)},${fmt4(by - py * wide)}`;
|
|
21098
22153
|
return polygon({ points: `${fmt4(x)},${fmt4(y)} ${p1} ${p2}`, class: "sx-cld-glyph-head" });
|
|
21099
22154
|
}
|
|
21100
|
-
function
|
|
22155
|
+
function summarise7(layout) {
|
|
21101
22156
|
const { ast, analysis } = layout;
|
|
21102
22157
|
const parts = [
|
|
21103
22158
|
`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"}.`
|
|
@@ -21146,7 +22201,7 @@ var MarkovParseError = class extends Error {
|
|
|
21146
22201
|
};
|
|
21147
22202
|
var OPENERS2 = ['"', "\u201C", "\u300C", "\u300E", "\xAB"];
|
|
21148
22203
|
var CLOSERS2 = ['"', "\u201D", "\u300D", "\u300F", "\xBB"];
|
|
21149
|
-
function
|
|
22204
|
+
function tokenize7(s) {
|
|
21150
22205
|
const out = [];
|
|
21151
22206
|
let i = 0;
|
|
21152
22207
|
while (i < s.length) {
|
|
@@ -21231,7 +22286,7 @@ function parseMarkov(text2) {
|
|
|
21231
22286
|
if (trimmed.startsWith("#") || trimmed.startsWith("//")) continue;
|
|
21232
22287
|
if (!sawHeader && /^(markov|markovchain)\b/i.test(trimmed)) {
|
|
21233
22288
|
sawHeader = true;
|
|
21234
|
-
const toks =
|
|
22289
|
+
const toks = tokenize7(trimmed);
|
|
21235
22290
|
const titleTok = toks.find((t, idx) => idx > 0 && t.quoted);
|
|
21236
22291
|
if (titleTok) ast.title = titleTok.text;
|
|
21237
22292
|
else if (toks[1] && !toks[1].quoted) ast.title = toks.slice(1).map((t) => t.text).join(" ");
|
|
@@ -21289,7 +22344,7 @@ function parseMarkov(text2) {
|
|
|
21289
22344
|
return ast;
|
|
21290
22345
|
}
|
|
21291
22346
|
function parseStateDecl(line2, lineNo, ensureState) {
|
|
21292
|
-
const toks =
|
|
22347
|
+
const toks = tokenize7(normalizeKeyNums2(line2));
|
|
21293
22348
|
const idTok = toks[1];
|
|
21294
22349
|
if (!idTok || idTok.quoted) throw new MarkovParseError(`state is missing an id`, lineNo);
|
|
21295
22350
|
const id = idTok.text;
|
|
@@ -21563,22 +22618,22 @@ function computeAbsorbing(P, order, classification) {
|
|
|
21563
22618
|
const absorbing = order.filter((id) => absorbingSet.has(id));
|
|
21564
22619
|
const pos = new Map(order.map((id, i) => [id, i]));
|
|
21565
22620
|
const t = transient.length;
|
|
21566
|
-
const
|
|
22621
|
+
const r7 = absorbing.length;
|
|
21567
22622
|
const Q = Array.from({ length: t }, () => new Array(t).fill(0));
|
|
21568
|
-
const R = Array.from({ length: t }, () => new Array(
|
|
22623
|
+
const R = Array.from({ length: t }, () => new Array(r7).fill(0));
|
|
21569
22624
|
for (let a = 0; a < t; a++) {
|
|
21570
22625
|
const fi = pos.get(transient[a]);
|
|
21571
22626
|
for (let b = 0; b < t; b++) Q[a][b] = P[fi][pos.get(transient[b])];
|
|
21572
|
-
for (let b = 0; b <
|
|
22627
|
+
for (let b = 0; b < r7; b++) R[a][b] = P[fi][pos.get(absorbing[b])];
|
|
21573
22628
|
}
|
|
21574
22629
|
const ImQ = Array.from(
|
|
21575
22630
|
{ length: t },
|
|
21576
22631
|
(_, a) => Array.from({ length: t }, (_2, b) => (a === b ? 1 : 0) - Q[a][b])
|
|
21577
22632
|
);
|
|
21578
22633
|
const N = invert(ImQ);
|
|
21579
|
-
const B = Array.from({ length: t }, () => new Array(
|
|
22634
|
+
const B = Array.from({ length: t }, () => new Array(r7).fill(0));
|
|
21580
22635
|
for (let a = 0; a < t; a++) {
|
|
21581
|
-
for (let b = 0; b <
|
|
22636
|
+
for (let b = 0; b < r7; b++) {
|
|
21582
22637
|
let s = 0;
|
|
21583
22638
|
for (let c = 0; c < t; c++) s += N[a][c] * R[c][b];
|
|
21584
22639
|
B[a][b] = s;
|
|
@@ -21850,11 +22905,11 @@ function curvedArcGeom(tr, a, b, bow, C2) {
|
|
|
21850
22905
|
labelY: mid.y
|
|
21851
22906
|
};
|
|
21852
22907
|
}
|
|
21853
|
-
function aimToBoundary(centre, target,
|
|
22908
|
+
function aimToBoundary(centre, target, r7) {
|
|
21854
22909
|
const dx = target.x - centre.x;
|
|
21855
22910
|
const dy = target.y - centre.y;
|
|
21856
22911
|
const len = Math.hypot(dx, dy) || 1;
|
|
21857
|
-
return { x: centre.x + dx / len *
|
|
22912
|
+
return { x: centre.x + dx / len * r7, y: centre.y + dy / len * r7 };
|
|
21858
22913
|
}
|
|
21859
22914
|
function selfLoopGeom(tr, c, ringCenter, layout, C2) {
|
|
21860
22915
|
let ox = c.x - ringCenter.x;
|
|
@@ -22088,8 +23143,8 @@ function renderMarkov(textOrAst, config) {
|
|
|
22088
23143
|
}
|
|
22089
23144
|
function fmt5(x) {
|
|
22090
23145
|
if (!Number.isFinite(x)) return String(x);
|
|
22091
|
-
const
|
|
22092
|
-
return String(
|
|
23146
|
+
const r7 = Math.round(x * 1e3) / 1e3;
|
|
23147
|
+
return String(r7);
|
|
22093
23148
|
}
|
|
22094
23149
|
function num(x) {
|
|
22095
23150
|
return Math.round(x * 100) / 100;
|
|
@@ -22766,7 +23821,7 @@ function renderGitGraphLayout(layout, config) {
|
|
|
22766
23821
|
const styleBlock = buildStyle2(pal, ast.showBranches);
|
|
22767
23822
|
const children = [
|
|
22768
23823
|
title(a11y),
|
|
22769
|
-
desc(
|
|
23824
|
+
desc(summarise8(layout)),
|
|
22770
23825
|
styleBlock,
|
|
22771
23826
|
rect({ x: 0, y: 0, width, height, class: "sx-gg-bg" })
|
|
22772
23827
|
];
|
|
@@ -22889,13 +23944,13 @@ function renderCommit(lc, ast, pal, fontFamily) {
|
|
|
22889
23944
|
if (node.commitType !== "NORMAL") dataAttrs2["data-type"] = node.commitType;
|
|
22890
23945
|
if (node.tag) dataAttrs2["data-tag"] = node.tag;
|
|
22891
23946
|
if (node.commitType === "HIGHLIGHT") {
|
|
22892
|
-
const
|
|
23947
|
+
const r7 = GITGRAPH_CONST.SQUARE_R;
|
|
22893
23948
|
parts.push(
|
|
22894
23949
|
rect({
|
|
22895
|
-
x: x -
|
|
22896
|
-
y: y -
|
|
22897
|
-
width:
|
|
22898
|
-
height:
|
|
23950
|
+
x: x - r7,
|
|
23951
|
+
y: y - r7,
|
|
23952
|
+
width: r7 * 2,
|
|
23953
|
+
height: r7 * 2,
|
|
22899
23954
|
rx: 2,
|
|
22900
23955
|
class: `sx-gg-node sx-gg-highlight sx-gg-stroke-c${ci}`
|
|
22901
23956
|
})
|
|
@@ -23016,7 +24071,7 @@ ${laneRules}
|
|
|
23016
24071
|
function num2(n) {
|
|
23017
24072
|
return Number.isInteger(n) ? String(n) : n.toFixed(2);
|
|
23018
24073
|
}
|
|
23019
|
-
function
|
|
24074
|
+
function summarise8(layout) {
|
|
23020
24075
|
const c = layout.replay.commits.length;
|
|
23021
24076
|
const b = layout.replay.branches.length;
|
|
23022
24077
|
const merges = layout.replay.commits.filter((n) => n.isMerge).length;
|
|
@@ -23573,33 +24628,33 @@ function layoutEpc(ast) {
|
|
|
23573
24628
|
const isLR = ast.direction === "lr";
|
|
23574
24629
|
const layerCenter = [];
|
|
23575
24630
|
let primary = EPC_CONST.CANVAS_PAD + (ast.title ? EPC_CONST.TITLE_H : 0);
|
|
23576
|
-
for (let
|
|
24631
|
+
for (let r7 = 0; r7 <= maxLayer; r7++) {
|
|
23577
24632
|
const bandThickness = Math.max(
|
|
23578
24633
|
0,
|
|
23579
|
-
...ranks[
|
|
24634
|
+
...ranks[r7].map((id) => isLR ? sized.get(id).w : sized.get(id).h)
|
|
23580
24635
|
);
|
|
23581
|
-
layerCenter[
|
|
24636
|
+
layerCenter[r7] = primary + bandThickness / 2;
|
|
23582
24637
|
primary += bandThickness + EPC_CONST.LAYER_GAP;
|
|
23583
24638
|
}
|
|
23584
24639
|
const primaryExtent = primary - EPC_CONST.LAYER_GAP + EPC_CONST.CANVAS_PAD;
|
|
23585
24640
|
const crossPos = /* @__PURE__ */ new Map();
|
|
23586
24641
|
let maxCrossExtent = 0;
|
|
23587
24642
|
const rankWidths = [];
|
|
23588
|
-
for (let
|
|
24643
|
+
for (let r7 = 0; r7 <= maxLayer; r7++) {
|
|
23589
24644
|
let cursor = 0;
|
|
23590
|
-
for (const id of ranks[
|
|
24645
|
+
for (const id of ranks[r7]) {
|
|
23591
24646
|
const s = sized.get(id);
|
|
23592
24647
|
const span = isLR ? s.h : s.w;
|
|
23593
24648
|
crossPos.set(id, cursor + span / 2);
|
|
23594
24649
|
cursor += span + EPC_CONST.NODE_GAP;
|
|
23595
24650
|
}
|
|
23596
24651
|
const total = Math.max(0, cursor - EPC_CONST.NODE_GAP);
|
|
23597
|
-
rankWidths[
|
|
24652
|
+
rankWidths[r7] = total;
|
|
23598
24653
|
maxCrossExtent = Math.max(maxCrossExtent, total);
|
|
23599
24654
|
}
|
|
23600
|
-
for (let
|
|
23601
|
-
const shift = (maxCrossExtent - rankWidths[
|
|
23602
|
-
for (const id of ranks[
|
|
24655
|
+
for (let r7 = 0; r7 <= maxLayer; r7++) {
|
|
24656
|
+
const shift = (maxCrossExtent - rankWidths[r7]) / 2 + EPC_CONST.CANVAS_PAD;
|
|
24657
|
+
for (const id of ranks[r7]) crossPos.set(id, crossPos.get(id) + shift);
|
|
23603
24658
|
}
|
|
23604
24659
|
const backMargin = backSet.size > 0 ? EPC_CONST.BACK_MARGIN : 0;
|
|
23605
24660
|
const crossExtent = maxCrossExtent + EPC_CONST.CANVAS_PAD * 2 + backMargin;
|
|
@@ -23677,15 +24732,15 @@ function longestPathLayers(ast, dagOut, dagIn) {
|
|
|
23677
24732
|
}
|
|
23678
24733
|
function orderRanks2(ranks, dagIn, ast) {
|
|
23679
24734
|
const declIndex = new Map(ast.nodes.map((n, i) => [n.id, i]));
|
|
23680
|
-
for (let
|
|
24735
|
+
for (let r7 = 1; r7 < ranks.length; r7++) {
|
|
23681
24736
|
const prevIndex = /* @__PURE__ */ new Map();
|
|
23682
|
-
ranks[
|
|
24737
|
+
ranks[r7 - 1].forEach((id, i) => prevIndex.set(id, i));
|
|
23683
24738
|
const bary = /* @__PURE__ */ new Map();
|
|
23684
|
-
for (const id of ranks[
|
|
24739
|
+
for (const id of ranks[r7]) {
|
|
23685
24740
|
const preds = (dagIn.get(id) ?? []).map((p) => prevIndex.get(p)).filter((v) => v !== void 0);
|
|
23686
24741
|
bary.set(id, preds.length ? preds.reduce((a, b) => a + b, 0) / preds.length : declIndex.get(id) ?? 0);
|
|
23687
24742
|
}
|
|
23688
|
-
ranks[
|
|
24743
|
+
ranks[r7].sort((a, b) => {
|
|
23689
24744
|
const d = (bary.get(a) ?? 0) - (bary.get(b) ?? 0);
|
|
23690
24745
|
if (Math.abs(d) > 1e-9) return d;
|
|
23691
24746
|
return (declIndex.get(a) ?? 0) - (declIndex.get(b) ?? 0);
|
|
@@ -23716,7 +24771,7 @@ function detectBackEdges(ast, out) {
|
|
|
23716
24771
|
}
|
|
23717
24772
|
colour.set(id, BLACK);
|
|
23718
24773
|
};
|
|
23719
|
-
for (const
|
|
24774
|
+
for (const r7 of visitOrder) if ((colour.get(r7) ?? WHITE) === WHITE) dfs(r7);
|
|
23720
24775
|
return back;
|
|
23721
24776
|
}
|
|
23722
24777
|
function routeEdge3(e, nodePos, crossExtent, back, isLR) {
|
|
@@ -23753,9 +24808,9 @@ function borderPoint(from, to, _isLR) {
|
|
|
23753
24808
|
const dx = to.cx - from.cx;
|
|
23754
24809
|
const dy = to.cy - from.cy;
|
|
23755
24810
|
if (from.node.kind === "connector") {
|
|
23756
|
-
const
|
|
24811
|
+
const r7 = EPC_CONST.CONN_R;
|
|
23757
24812
|
const len = Math.hypot(dx, dy) || 1;
|
|
23758
|
-
return { x: from.cx + dx / len *
|
|
24813
|
+
return { x: from.cx + dx / len * r7, y: from.cy + dy / len * r7 };
|
|
23759
24814
|
}
|
|
23760
24815
|
const hw = from.width / 2;
|
|
23761
24816
|
const hh = from.height / 2;
|
|
@@ -23857,7 +24912,7 @@ function renderEpcLayout(layout, config) {
|
|
|
23857
24912
|
);
|
|
23858
24913
|
const children = [
|
|
23859
24914
|
title(a11y),
|
|
23860
|
-
desc(
|
|
24915
|
+
desc(summarise9(layout)),
|
|
23861
24916
|
styleBlock,
|
|
23862
24917
|
defs([
|
|
23863
24918
|
el("marker", {
|
|
@@ -23910,7 +24965,7 @@ function renderNode3(n) {
|
|
|
23910
24965
|
parts.push(hexagon(n.cx, n.cy, n.width, n.height, "sx-epc-event"));
|
|
23911
24966
|
parts.push(multilineText(
|
|
23912
24967
|
{ x: n.cx, y: n.cy, class: "sx-epc-label", "text-anchor": "middle", "dominant-baseline": "middle" },
|
|
23913
|
-
|
|
24968
|
+
wrap5(label, 18),
|
|
23914
24969
|
14
|
|
23915
24970
|
));
|
|
23916
24971
|
} else if (node.kind === "function") {
|
|
@@ -23925,7 +24980,7 @@ function renderNode3(n) {
|
|
|
23925
24980
|
}));
|
|
23926
24981
|
parts.push(multilineText(
|
|
23927
24982
|
{ x: n.cx, y: n.cy, class: "sx-epc-label", "text-anchor": "middle", "dominant-baseline": "middle" },
|
|
23928
|
-
|
|
24983
|
+
wrap5(label, 18),
|
|
23929
24984
|
14
|
|
23930
24985
|
));
|
|
23931
24986
|
} else {
|
|
@@ -23936,9 +24991,9 @@ function renderNode3(n) {
|
|
|
23936
24991
|
));
|
|
23937
24992
|
}
|
|
23938
24993
|
if (n.flagged) {
|
|
23939
|
-
const
|
|
24994
|
+
const r7 = node.kind === "connector" ? EPC_CONST.CONN_R + 5 : 0;
|
|
23940
24995
|
if (node.kind === "connector") {
|
|
23941
|
-
parts.push(circle({ cx: n.cx, cy: n.cy, r:
|
|
24996
|
+
parts.push(circle({ cx: n.cx, cy: n.cy, r: r7, class: "sx-epc-flagring" }));
|
|
23942
24997
|
} else {
|
|
23943
24998
|
parts.push(rect({
|
|
23944
24999
|
x: n.cx - n.width / 2 - 5,
|
|
@@ -23993,7 +25048,7 @@ function renderEdge6(e) {
|
|
|
23993
25048
|
if (e.edge.label) {
|
|
23994
25049
|
parts.push(text(
|
|
23995
25050
|
{ x: e.mid.x, y: e.mid.y - 4, class: "sx-epc-edge-label", "text-anchor": "middle" },
|
|
23996
|
-
|
|
25051
|
+
clip5(e.edge.label, 24)
|
|
23997
25052
|
));
|
|
23998
25053
|
}
|
|
23999
25054
|
return group(
|
|
@@ -24001,7 +25056,7 @@ function renderEdge6(e) {
|
|
|
24001
25056
|
parts
|
|
24002
25057
|
);
|
|
24003
25058
|
}
|
|
24004
|
-
function
|
|
25059
|
+
function summarise9(layout) {
|
|
24005
25060
|
const { ast, analysis } = layout;
|
|
24006
25061
|
const counts = { event: 0, function: 0, connector: 0 };
|
|
24007
25062
|
for (const n of ast.nodes) counts[n.kind]++;
|
|
@@ -24021,10 +25076,10 @@ function describeWellFormed(analysis) {
|
|
|
24021
25076
|
if (warns) bits.push(`${warns} warning${warns > 1 ? "s" : ""}`);
|
|
24022
25077
|
return `${bits.join(", ")}.`;
|
|
24023
25078
|
}
|
|
24024
|
-
function
|
|
25079
|
+
function clip5(s, n) {
|
|
24025
25080
|
return s.length <= n ? s : s.slice(0, n - 1) + "\u2026";
|
|
24026
25081
|
}
|
|
24027
|
-
function
|
|
25082
|
+
function wrap5(s, perLine) {
|
|
24028
25083
|
if (s.length <= perLine) return s;
|
|
24029
25084
|
const words = s.split(/\s+/);
|
|
24030
25085
|
const lines = [];
|
|
@@ -24038,7 +25093,7 @@ function wrap4(s, perLine) {
|
|
|
24038
25093
|
if (cur) lines.push(cur);
|
|
24039
25094
|
if (lines.length > 3) {
|
|
24040
25095
|
lines.length = 3;
|
|
24041
|
-
lines[2] =
|
|
25096
|
+
lines[2] = clip5(lines[2], perLine);
|
|
24042
25097
|
}
|
|
24043
25098
|
return lines.join("<br/>");
|
|
24044
25099
|
}
|
|
@@ -24614,7 +25669,7 @@ function renderIdef0Layout(layout, config) {
|
|
|
24614
25669
|
);
|
|
24615
25670
|
const children = [
|
|
24616
25671
|
title(a11y),
|
|
24617
|
-
desc(
|
|
25672
|
+
desc(summarise10(layout)),
|
|
24618
25673
|
styleBlock,
|
|
24619
25674
|
rect({ x: 0, y: 0, width, height, class: "sx-idef0-bg" })
|
|
24620
25675
|
];
|
|
@@ -24665,7 +25720,7 @@ function renderBox5(b) {
|
|
|
24665
25720
|
"text-anchor": "middle",
|
|
24666
25721
|
"dominant-baseline": "middle"
|
|
24667
25722
|
},
|
|
24668
|
-
|
|
25723
|
+
wrap6(b.box.name, 18),
|
|
24669
25724
|
14
|
|
24670
25725
|
),
|
|
24671
25726
|
// Box number in the lower-right interior corner.
|
|
@@ -24768,11 +25823,11 @@ function renderTitleBlock(width, height, node, title2) {
|
|
|
24768
25823
|
text({ x: x0 + 6, y: y + 13, class: "sx-idef0-tb-key" }, "NODE"),
|
|
24769
25824
|
text({ x: x0 + 6, y: y + 27, class: "sx-idef0-tb-text" }, node),
|
|
24770
25825
|
text({ x: c1 + 6, y: y + 13, class: "sx-idef0-tb-key" }, "TITLE"),
|
|
24771
|
-
text({ x: c1 + 6, y: y + 27, class: "sx-idef0-tb-text" },
|
|
25826
|
+
text({ x: c1 + 6, y: y + 27, class: "sx-idef0-tb-text" }, clip6(title2 || "\u2014", 60)),
|
|
24772
25827
|
text({ x: c2 + 6, y: y + 13, class: "sx-idef0-tb-key" }, "NUMBER")
|
|
24773
25828
|
]);
|
|
24774
25829
|
}
|
|
24775
|
-
function
|
|
25830
|
+
function summarise10(layout) {
|
|
24776
25831
|
const { ast } = layout;
|
|
24777
25832
|
const counts = {};
|
|
24778
25833
|
for (const a of ast.arrows) counts[a.role] = (counts[a.role] ?? 0) + 1;
|
|
@@ -24787,10 +25842,10 @@ function summarise8(layout) {
|
|
|
24787
25842
|
for (const w of ast.warnings) parts.push(w);
|
|
24788
25843
|
return parts.join(" ");
|
|
24789
25844
|
}
|
|
24790
|
-
function
|
|
25845
|
+
function clip6(s, n) {
|
|
24791
25846
|
return s.length <= n ? s : s.slice(0, n - 1) + "\u2026";
|
|
24792
25847
|
}
|
|
24793
|
-
function
|
|
25848
|
+
function wrap6(s, perLine) {
|
|
24794
25849
|
if (s.length <= perLine) return s;
|
|
24795
25850
|
const words = s.split(/\s+/);
|
|
24796
25851
|
const lines = [];
|
|
@@ -24806,7 +25861,7 @@ function wrap5(s, perLine) {
|
|
|
24806
25861
|
if (cur) lines.push(cur);
|
|
24807
25862
|
if (lines.length > 3) {
|
|
24808
25863
|
lines.length = 3;
|
|
24809
|
-
lines[2] =
|
|
25864
|
+
lines[2] = clip6(lines[2], perLine);
|
|
24810
25865
|
}
|
|
24811
25866
|
return lines.join("<br/>");
|
|
24812
25867
|
}
|
|
@@ -24837,7 +25892,7 @@ for (const [open, close] of Object.entries(QUOTE_PAIRS)) {
|
|
|
24837
25892
|
QUOTE_FOLD.set(close, '"');
|
|
24838
25893
|
}
|
|
24839
25894
|
}
|
|
24840
|
-
function
|
|
25895
|
+
function normalizeQuotes3(text2) {
|
|
24841
25896
|
let out = "";
|
|
24842
25897
|
for (const ch of text2) out += QUOTE_FOLD.get(ch) ?? ch;
|
|
24843
25898
|
return out;
|
|
@@ -24868,7 +25923,7 @@ function parseThreatModel(text2) {
|
|
|
24868
25923
|
flows: [],
|
|
24869
25924
|
boundaries: []
|
|
24870
25925
|
};
|
|
24871
|
-
const rawLines =
|
|
25926
|
+
const rawLines = normalizeQuotes3(text2).split(/\r?\n/);
|
|
24872
25927
|
const byId = /* @__PURE__ */ new Map();
|
|
24873
25928
|
const declareNode = (id, kind, label, lineNo, logStore) => {
|
|
24874
25929
|
if (byId.has(id)) {
|
|
@@ -25327,13 +26382,13 @@ function layoutThreatModel(ast) {
|
|
|
25327
26382
|
}
|
|
25328
26383
|
const boundaries = [];
|
|
25329
26384
|
for (const b of ast.boundaries) {
|
|
25330
|
-
let l = Infinity, t = Infinity,
|
|
26385
|
+
let l = Infinity, t = Infinity, r7 = -Infinity, bm = -Infinity;
|
|
25331
26386
|
for (const m of b.members) {
|
|
25332
26387
|
const mn = nodeMap.get(m);
|
|
25333
26388
|
if (!mn) continue;
|
|
25334
26389
|
l = Math.min(l, mn.x);
|
|
25335
26390
|
t = Math.min(t, mn.y);
|
|
25336
|
-
|
|
26391
|
+
r7 = Math.max(r7, mn.x + mn.w);
|
|
25337
26392
|
bm = Math.max(bm, mn.y + mn.h);
|
|
25338
26393
|
}
|
|
25339
26394
|
if (!Number.isFinite(l)) continue;
|
|
@@ -25342,7 +26397,7 @@ function layoutThreatModel(ast) {
|
|
|
25342
26397
|
name: b.name,
|
|
25343
26398
|
x: l - p,
|
|
25344
26399
|
y: t - p - TM_CONST.BOUNDARY_HEADER,
|
|
25345
|
-
w:
|
|
26400
|
+
w: r7 - l + p * 2,
|
|
25346
26401
|
h: bm - t + p * 2 + TM_CONST.BOUNDARY_HEADER
|
|
25347
26402
|
});
|
|
25348
26403
|
}
|
|
@@ -25376,9 +26431,9 @@ function edgePoint2(n, tx, ty) {
|
|
|
25376
26431
|
const dy = ty - n.cy;
|
|
25377
26432
|
if (dx === 0 && dy === 0) return { x: n.cx, y: n.cy };
|
|
25378
26433
|
if (n.kind === "process") {
|
|
25379
|
-
const
|
|
26434
|
+
const r7 = TM_CONST.PROCESS_R;
|
|
25380
26435
|
const len = Math.hypot(dx, dy);
|
|
25381
|
-
return { x: n.cx + dx / len *
|
|
26436
|
+
return { x: n.cx + dx / len * r7, y: n.cy + dy / len * r7 };
|
|
25382
26437
|
}
|
|
25383
26438
|
const hw = n.w / 2;
|
|
25384
26439
|
const hh = n.h / 2;
|
|
@@ -25433,7 +26488,7 @@ function renderThreatModelLayout(layout, config) {
|
|
|
25433
26488
|
]);
|
|
25434
26489
|
const children = [
|
|
25435
26490
|
title(a11y),
|
|
25436
|
-
desc(
|
|
26491
|
+
desc(summarise11(layout)),
|
|
25437
26492
|
styleBlock,
|
|
25438
26493
|
markerDefs,
|
|
25439
26494
|
rect({ x: 0, y: 0, width, height, class: "sx-tm-bg" })
|
|
@@ -25650,7 +26705,7 @@ function arrowMarker2(id, cls, crossing) {
|
|
|
25650
26705
|
function round8(n) {
|
|
25651
26706
|
return Math.round(n * 100) / 100;
|
|
25652
26707
|
}
|
|
25653
|
-
function
|
|
26708
|
+
function summarise11(layout) {
|
|
25654
26709
|
const a = layout.analysis;
|
|
25655
26710
|
const counts = {
|
|
25656
26711
|
external: layout.nodes.filter((n) => n.kind === "external").length,
|
|
@@ -26028,9 +27083,9 @@ function weldGlyph(type, cx, y, dir, cls) {
|
|
|
26028
27083
|
return [path({ d: `M ${round9(cx - rr)} ${round9(y)} A ${round9(rr)} ${round9(rr)} 0 0 ${sweep} ${round9(cx + rr)} ${round9(y)}`, class: cls, fill: "none" })];
|
|
26029
27084
|
}
|
|
26030
27085
|
case "surfacing": {
|
|
26031
|
-
const
|
|
27086
|
+
const r7 = W / 4;
|
|
26032
27087
|
const yy = y + dir * 3;
|
|
26033
|
-
const bump = (off) => path({ d: `M ${round9(cx - W / 2)} ${round9(off)} a ${round9(
|
|
27088
|
+
const bump = (off) => path({ d: `M ${round9(cx - W / 2)} ${round9(off)} a ${round9(r7)} ${round9(r7)} 0 0 ${dir > 0 ? 1 : 0} ${round9(W / 2)} 0 a ${round9(r7)} ${round9(r7)} 0 0 ${dir > 0 ? 1 : 0} ${round9(W / 2)} 0`, class: cls, fill: "none" });
|
|
26034
27089
|
return [bump(y), bump(yy)];
|
|
26035
27090
|
}
|
|
26036
27091
|
case "edge":
|
|
@@ -26902,7 +27957,7 @@ function computeMaxLW(subtreeRoots, maxLabelWidth) {
|
|
|
26902
27957
|
if (maxLW[n.depth] === void 0 || m.width > maxLW[n.depth]) maxLW[n.depth] = m.width;
|
|
26903
27958
|
for (const c of n.children) walk(c);
|
|
26904
27959
|
};
|
|
26905
|
-
for (const
|
|
27960
|
+
for (const r7 of subtreeRoots) walk(r7);
|
|
26906
27961
|
return maxLW;
|
|
26907
27962
|
}
|
|
26908
27963
|
function buildColumns(maxLW, firstColStartX, rootDepth) {
|
|
@@ -27269,9 +28324,9 @@ function renderNode5(n, color, theme, fontFamily, orderClass) {
|
|
|
27269
28324
|
for (let i = 0; i < lineCount; i++) {
|
|
27270
28325
|
const line2 = n.lines[i];
|
|
27271
28326
|
const cy = topY + (i + 0.5) * lh;
|
|
27272
|
-
const
|
|
27273
|
-
decorations.push(...
|
|
27274
|
-
children.push(
|
|
28327
|
+
const r7 = renderLine2(line2, textLeft, cy, fs, fontFamily, weight, theme);
|
|
28328
|
+
decorations.push(...r7.decorations);
|
|
28329
|
+
children.push(r7.textElement);
|
|
27275
28330
|
}
|
|
27276
28331
|
const ux1 = n.x - n.labelWidth / 2;
|
|
27277
28332
|
const ux2 = n.x + n.labelWidth / 2;
|
|
@@ -27995,11 +29050,11 @@ function parseMatrix(text2) {
|
|
|
27995
29050
|
const gm = v.match(/^(\d+)\s*x\s*(\d+)$/);
|
|
27996
29051
|
if (gm) {
|
|
27997
29052
|
const c = Number(gm[1]);
|
|
27998
|
-
const
|
|
29053
|
+
const r7 = Number(gm[2]);
|
|
27999
29054
|
st.ast.cols = c;
|
|
28000
|
-
st.ast.rows =
|
|
28001
|
-
if (c === 2 &&
|
|
28002
|
-
else if (c === 3 &&
|
|
29055
|
+
st.ast.rows = r7;
|
|
29056
|
+
if (c === 2 && r7 === 2) st.ast.grid = "2x2";
|
|
29057
|
+
else if (c === 3 && r7 === 3) st.ast.grid = "3x3";
|
|
28003
29058
|
else st.ast.grid = "NxM";
|
|
28004
29059
|
}
|
|
28005
29060
|
continue;
|
|
@@ -28212,11 +29267,11 @@ function punnettFooter(result) {
|
|
|
28212
29267
|
}
|
|
28213
29268
|
function computeQfdImportance(qfd) {
|
|
28214
29269
|
const raw = qfd.hows.map(() => 0);
|
|
28215
|
-
for (const
|
|
28216
|
-
if (
|
|
28217
|
-
if (
|
|
28218
|
-
const w = qfd.whats[
|
|
28219
|
-
raw[
|
|
29270
|
+
for (const r7 of qfd.relationships) {
|
|
29271
|
+
if (r7.how < 0 || r7.how >= qfd.hows.length) continue;
|
|
29272
|
+
if (r7.what < 0 || r7.what >= qfd.whats.length) continue;
|
|
29273
|
+
const w = qfd.whats[r7.what].weight;
|
|
29274
|
+
raw[r7.how] += w * r7.strength;
|
|
28220
29275
|
}
|
|
28221
29276
|
const total = raw.reduce((acc, v) => acc + v, 0);
|
|
28222
29277
|
return raw.map((importance, how) => ({
|
|
@@ -28237,12 +29292,12 @@ function estimateWidth(text2) {
|
|
|
28237
29292
|
const cjk = (text2.match(/[\u3000-\u9fff]/g) ?? []).length;
|
|
28238
29293
|
return (text2.length - cjk) * CHAR_W2 + cjk * 12 + 8;
|
|
28239
29294
|
}
|
|
28240
|
-
function
|
|
29295
|
+
function clamp012(v) {
|
|
28241
29296
|
return Math.max(0.02, Math.min(0.98, v));
|
|
28242
29297
|
}
|
|
28243
29298
|
function placePoint(p, plot) {
|
|
28244
|
-
const nx =
|
|
28245
|
-
const ny =
|
|
29299
|
+
const nx = clamp012(p.x);
|
|
29300
|
+
const ny = clamp012(p.y);
|
|
28246
29301
|
const px = plot.x0 + nx * plot.w;
|
|
28247
29302
|
const py = plot.y0 + (1 - ny) * plot.h;
|
|
28248
29303
|
return { px, py };
|
|
@@ -28258,8 +29313,8 @@ function computeRadius(p, maxSize, plot, scale) {
|
|
|
28258
29313
|
}
|
|
28259
29314
|
const maxArea = Math.PI * maxRadius * maxRadius;
|
|
28260
29315
|
const area = ratio * maxArea;
|
|
28261
|
-
const
|
|
28262
|
-
return Math.max(minRadius,
|
|
29316
|
+
const r7 = Math.sqrt(area / Math.PI);
|
|
29317
|
+
return Math.max(minRadius, r7);
|
|
28263
29318
|
}
|
|
28264
29319
|
function resolveLabelCollisions(points, plot, mode) {
|
|
28265
29320
|
if (mode === "off") {
|
|
@@ -28460,20 +29515,20 @@ function layoutMatrix(ast) {
|
|
|
28460
29515
|
}
|
|
28461
29516
|
for (const p of ast.points) {
|
|
28462
29517
|
const { px, py } = placePoint(p, plot);
|
|
28463
|
-
const
|
|
29518
|
+
const r7 = computeRadius(p, maxSize, plot, ast.config.bubbleScale);
|
|
28464
29519
|
const width = estimateWidth(p.label);
|
|
28465
29520
|
const label = {
|
|
28466
29521
|
text: p.label,
|
|
28467
29522
|
ax: px,
|
|
28468
29523
|
ay: py,
|
|
28469
|
-
lx: px +
|
|
28470
|
-
ly: py -
|
|
29524
|
+
lx: px + r7 + 4 + width / 2,
|
|
29525
|
+
ly: py - r7 - 4,
|
|
28471
29526
|
width,
|
|
28472
29527
|
height: LABEL_H,
|
|
28473
29528
|
external: false,
|
|
28474
29529
|
textAnchor: "middle"
|
|
28475
29530
|
};
|
|
28476
|
-
points.push({ point: p, px, py, r:
|
|
29531
|
+
points.push({ point: p, px, py, r: r7, label });
|
|
28477
29532
|
if (p.category) categoriesSet.add(p.category);
|
|
28478
29533
|
}
|
|
28479
29534
|
resolveLabelCollisions(points, plot, ast.config.labelCollision);
|
|
@@ -28623,7 +29678,7 @@ function renderQuadrantBackground(ast, lay) {
|
|
|
28623
29678
|
return group(
|
|
28624
29679
|
{ id: "sx-matrix-quad-bg" },
|
|
28625
29680
|
rects.map(
|
|
28626
|
-
(
|
|
29681
|
+
(r7) => rect({ x: r7.x, y: r7.y, width: r7.w, height: r7.h, fill: r7.fill, "fill-opacity": 0.55 })
|
|
28627
29682
|
)
|
|
28628
29683
|
);
|
|
28629
29684
|
}
|
|
@@ -29275,9 +30330,9 @@ function renderOnePoint(pl2, categories) {
|
|
|
29275
30330
|
class: "sx-matrix-bubble"
|
|
29276
30331
|
});
|
|
29277
30332
|
} else if (shape === "diamond") {
|
|
29278
|
-
const
|
|
30333
|
+
const r7 = pl2.r;
|
|
29279
30334
|
shapeEl = polygon({
|
|
29280
|
-
points: `${pl2.px},${pl2.py -
|
|
30335
|
+
points: `${pl2.px},${pl2.py - r7} ${pl2.px + r7},${pl2.py} ${pl2.px},${pl2.py + r7} ${pl2.px - r7},${pl2.py}`,
|
|
29281
30336
|
fill: color,
|
|
29282
30337
|
"fill-opacity": fillOpacity,
|
|
29283
30338
|
stroke,
|
|
@@ -29285,9 +30340,9 @@ function renderOnePoint(pl2, categories) {
|
|
|
29285
30340
|
class: "sx-matrix-bubble"
|
|
29286
30341
|
});
|
|
29287
30342
|
} else {
|
|
29288
|
-
const
|
|
30343
|
+
const r7 = pl2.r;
|
|
29289
30344
|
shapeEl = polygon({
|
|
29290
|
-
points: `${pl2.px},${pl2.py -
|
|
30345
|
+
points: `${pl2.px},${pl2.py - r7} ${pl2.px + r7},${pl2.py + r7 * 0.8} ${pl2.px - r7},${pl2.py + r7 * 0.8}`,
|
|
29291
30346
|
fill: color,
|
|
29292
30347
|
"fill-opacity": fillOpacity,
|
|
29293
30348
|
stroke,
|
|
@@ -29419,15 +30474,15 @@ function renderSipocAST(ast, config) {
|
|
|
29419
30474
|
const items = sipoc[def.key];
|
|
29420
30475
|
const isProcess = def.key === "process";
|
|
29421
30476
|
const cellNodes = [];
|
|
29422
|
-
for (let
|
|
29423
|
-
const cellY = lay.y0 + lay.headerH +
|
|
29424
|
-
const item = items[
|
|
29425
|
-
const cellClass = isProcess ? "sx-sipoc-process" :
|
|
30477
|
+
for (let r7 = 0; r7 < lay.rows; r7++) {
|
|
30478
|
+
const cellY = lay.y0 + lay.headerH + r7 * lay.rowH;
|
|
30479
|
+
const item = items[r7];
|
|
30480
|
+
const cellClass = isProcess ? "sx-sipoc-process" : r7 % 2 === 0 ? "sx-sipoc-cell" : "sx-sipoc-cell-alt";
|
|
29426
30481
|
cellNodes.push(
|
|
29427
30482
|
rect({ x: colX, y: cellY, width: lay.colW, height: lay.rowH, class: cellClass })
|
|
29428
30483
|
);
|
|
29429
30484
|
if (item) {
|
|
29430
|
-
const label = isProcess ? `${
|
|
30485
|
+
const label = isProcess ? `${r7 + 1}. ${item}` : item;
|
|
29431
30486
|
const lines = wrapToLines(label, maxChars, 2);
|
|
29432
30487
|
const lineH = 14;
|
|
29433
30488
|
const startY = cellY + lay.rowH / 2 - (lines.length - 1) * lineH / 2;
|
|
@@ -29490,17 +30545,17 @@ var CORR_LABEL = {
|
|
|
29490
30545
|
"-": "negative",
|
|
29491
30546
|
"--": "strong negative"
|
|
29492
30547
|
};
|
|
29493
|
-
function renderQfdRelationshipSymbol(strength, cx, cy,
|
|
30548
|
+
function renderQfdRelationshipSymbol(strength, cx, cy, r7) {
|
|
29494
30549
|
if (strength === 9) {
|
|
29495
30550
|
return group({}, [
|
|
29496
|
-
circle({ cx, cy, r:
|
|
29497
|
-
circle({ cx, cy, r:
|
|
30551
|
+
circle({ cx, cy, r: r7, fill: "none", stroke: "#2563eb", "stroke-width": 1.4 }),
|
|
30552
|
+
circle({ cx, cy, r: r7 * 0.5, class: "sx-qfd-rel-strong" })
|
|
29498
30553
|
]);
|
|
29499
30554
|
}
|
|
29500
30555
|
if (strength === 3) {
|
|
29501
|
-
return circle({ cx, cy, r:
|
|
30556
|
+
return circle({ cx, cy, r: r7, class: "sx-qfd-rel-medium" });
|
|
29502
30557
|
}
|
|
29503
|
-
const t =
|
|
30558
|
+
const t = r7 * 0.95;
|
|
29504
30559
|
return polygon({
|
|
29505
30560
|
points: `${cx},${cy - t} ${cx + t},${cy + t * 0.85} ${cx - t},${cy + t * 0.85}`,
|
|
29506
30561
|
class: "sx-qfd-rel-weak"
|
|
@@ -29598,15 +30653,15 @@ function renderQfdAST(ast, config) {
|
|
|
29598
30653
|
)
|
|
29599
30654
|
);
|
|
29600
30655
|
const gridNodes = [];
|
|
29601
|
-
for (let
|
|
29602
|
-
const y = lay.gridY0 +
|
|
30656
|
+
for (let r7 = 0; r7 < lay.rows; r7++) {
|
|
30657
|
+
const y = lay.gridY0 + r7 * lay.cellH;
|
|
29603
30658
|
gridNodes.push(
|
|
29604
30659
|
rect({
|
|
29605
30660
|
x: lay.gridX0,
|
|
29606
30661
|
y,
|
|
29607
30662
|
width: lay.cols * lay.cellW,
|
|
29608
30663
|
height: lay.cellH,
|
|
29609
|
-
class:
|
|
30664
|
+
class: r7 % 2 === 0 ? "sx-qfd-cellbg" : "sx-qfd-cellbg-alt"
|
|
29610
30665
|
})
|
|
29611
30666
|
);
|
|
29612
30667
|
}
|
|
@@ -29784,18 +30839,18 @@ function renderPunnettAST(ast, config) {
|
|
|
29784
30839
|
nodes.push(rect({ x: cx, y: lay.y0, width: lay.cellW, height: lay.headerH, class: "sx-punnett-header" }));
|
|
29785
30840
|
nodes.push(text({ x: cx + lay.cellW / 2, y: lay.y0 + lay.headerH / 2, class: "sx-punnett-gamete" }, g));
|
|
29786
30841
|
});
|
|
29787
|
-
result.gametes2.forEach((g,
|
|
29788
|
-
const cy = gy0 +
|
|
30842
|
+
result.gametes2.forEach((g, r7) => {
|
|
30843
|
+
const cy = gy0 + r7 * lay.cellH;
|
|
29789
30844
|
nodes.push(rect({ x: lay.x0, y: cy, width: lay.headerW, height: lay.cellH, class: "sx-punnett-header" }));
|
|
29790
30845
|
nodes.push(text({ x: lay.x0 + lay.headerW / 2, y: cy + lay.cellH / 2, class: "sx-punnett-gamete" }, g));
|
|
29791
30846
|
});
|
|
29792
|
-
for (let
|
|
29793
|
-
const row = result.grid[
|
|
30847
|
+
for (let r7 = 0; r7 < result.grid.length; r7++) {
|
|
30848
|
+
const row = result.grid[r7];
|
|
29794
30849
|
for (let c = 0; c < row.length; c++) {
|
|
29795
30850
|
const cell = row[c];
|
|
29796
30851
|
const color = phenoColor.get(cell.phenotypeKey);
|
|
29797
30852
|
const cx = gx0 + c * lay.cellW;
|
|
29798
|
-
const cy = gy0 +
|
|
30853
|
+
const cy = gy0 + r7 * lay.cellH;
|
|
29799
30854
|
nodes.push(rect({ x: cx, y: cy, width: lay.cellW, height: lay.cellH, fill: color.tint, class: "sx-punnett-cell" }));
|
|
29800
30855
|
nodes.push(text({ x: cx + lay.cellW / 2, y: cy + lay.cellH / 2, class: "sx-punnett-genotype" }, cell.genotype));
|
|
29801
30856
|
}
|
|
@@ -30348,12 +31403,12 @@ function buildColumnAssignment(ast) {
|
|
|
30348
31403
|
const ids = ast.entities.map((e) => e.id);
|
|
30349
31404
|
const idToIdx = new Map(ids.map((id, i) => [id, i]));
|
|
30350
31405
|
const pairs = [];
|
|
30351
|
-
for (const
|
|
30352
|
-
const f = parseRefSide(
|
|
30353
|
-
const t = parseRefSide(
|
|
31406
|
+
for (const r7 of ast.refs) {
|
|
31407
|
+
const f = parseRefSide(r7.from);
|
|
31408
|
+
const t = parseRefSide(r7.to);
|
|
30354
31409
|
if (idToIdx.has(f.table) && idToIdx.has(t.table)) {
|
|
30355
|
-
const oneIsTo = isOne(
|
|
30356
|
-
const oneIsFrom = isOne(
|
|
31410
|
+
const oneIsTo = isOne(r7.toCard) && !isOne(r7.fromCard);
|
|
31411
|
+
const oneIsFrom = isOne(r7.fromCard) && !isOne(r7.toCard);
|
|
30357
31412
|
if (oneIsTo) pairs.push({ from: t.table, to: f.table });
|
|
30358
31413
|
else if (oneIsFrom) pairs.push({ from: f.table, to: t.table });
|
|
30359
31414
|
else pairs.push({ from: f.table, to: t.table });
|
|
@@ -30388,9 +31443,9 @@ function isOne(c) {
|
|
|
30388
31443
|
function reorderByBarycenter(layerToEnts, layers, refs) {
|
|
30389
31444
|
if (layers.length < 2) return;
|
|
30390
31445
|
const neighbors = /* @__PURE__ */ new Map();
|
|
30391
|
-
for (const
|
|
30392
|
-
const a = parseRefSide(
|
|
30393
|
-
const b = parseRefSide(
|
|
31446
|
+
for (const r7 of refs) {
|
|
31447
|
+
const a = parseRefSide(r7.from).table;
|
|
31448
|
+
const b = parseRefSide(r7.to).table;
|
|
30394
31449
|
if (!neighbors.has(a)) neighbors.set(a, /* @__PURE__ */ new Set());
|
|
30395
31450
|
if (!neighbors.has(b)) neighbors.set(b, /* @__PURE__ */ new Set());
|
|
30396
31451
|
neighbors.get(a).add(b);
|
|
@@ -30520,9 +31575,9 @@ function layoutErd(ast) {
|
|
|
30520
31575
|
const layers = Array.from(layerToEnts.keys()).sort((a, b) => a - b);
|
|
30521
31576
|
reorderByBarycenter(layerToEnts, layers, ast.refs);
|
|
30522
31577
|
const neighbors = /* @__PURE__ */ new Map();
|
|
30523
|
-
for (const
|
|
30524
|
-
const a = parseRefSide(
|
|
30525
|
-
const b = parseRefSide(
|
|
31578
|
+
for (const r7 of ast.refs) {
|
|
31579
|
+
const a = parseRefSide(r7.from).table;
|
|
31580
|
+
const b = parseRefSide(r7.to).table;
|
|
30526
31581
|
if (!neighbors.has(a)) neighbors.set(a, /* @__PURE__ */ new Set());
|
|
30527
31582
|
if (!neighbors.has(b)) neighbors.set(b, /* @__PURE__ */ new Set());
|
|
30528
31583
|
neighbors.get(a).add(b);
|
|
@@ -30600,17 +31655,17 @@ function layoutErd(ast) {
|
|
|
30600
31655
|
const placedById = new Map(placed.map((p) => [p.entity.id, p]));
|
|
30601
31656
|
const edges = [];
|
|
30602
31657
|
const bendBucketUses = /* @__PURE__ */ new Map();
|
|
30603
|
-
for (const
|
|
30604
|
-
const fromTable = parseRefSide(
|
|
30605
|
-
const toTable = parseRefSide(
|
|
31658
|
+
for (const r7 of ast.refs) {
|
|
31659
|
+
const fromTable = parseRefSide(r7.from).table;
|
|
31660
|
+
const toTable = parseRefSide(r7.to).table;
|
|
30606
31661
|
const a = placedById.get(fromTable);
|
|
30607
31662
|
const b = placedById.get(toTable);
|
|
30608
31663
|
if (!a || !b) continue;
|
|
30609
|
-
const fromCol = parseRefSide(
|
|
30610
|
-
const toCol = parseRefSide(
|
|
31664
|
+
const fromCol = parseRefSide(r7.from).column;
|
|
31665
|
+
const toCol = parseRefSide(r7.to).column;
|
|
30611
31666
|
const route = routeOrthogonal(a, b, fromCol, toCol, bendBucketUses);
|
|
30612
31667
|
edges.push({
|
|
30613
|
-
ref:
|
|
31668
|
+
ref: r7,
|
|
30614
31669
|
path: route.path,
|
|
30615
31670
|
fromAnchor: route.fromAnchor,
|
|
30616
31671
|
toAnchor: route.toAnchor,
|
|
@@ -30627,7 +31682,7 @@ function layoutErd(ast) {
|
|
|
30627
31682
|
}
|
|
30628
31683
|
function rowYByColumn(e, col) {
|
|
30629
31684
|
if (col) {
|
|
30630
|
-
const idx = e.rows.findIndex((
|
|
31685
|
+
const idx = e.rows.findIndex((r7) => r7.attribute.name.toLowerCase() === col.toLowerCase());
|
|
30631
31686
|
if (idx >= 0) return e.y + e.rows[idx].yCenter;
|
|
30632
31687
|
}
|
|
30633
31688
|
return e.y + e.height / 2;
|
|
@@ -31407,8 +32462,8 @@ var PITCH = 14;
|
|
|
31407
32462
|
function rectShape(x, y, w, h, attrs) {
|
|
31408
32463
|
return el("rect", { x, y, width: w, height: h, ...attrs });
|
|
31409
32464
|
}
|
|
31410
|
-
function circShape(cx, cy,
|
|
31411
|
-
return el("circle", { cx, cy, r:
|
|
32465
|
+
function circShape(cx, cy, r7, attrs) {
|
|
32466
|
+
return el("circle", { cx, cy, r: r7, ...attrs });
|
|
31412
32467
|
}
|
|
31413
32468
|
function lineShape(x1, y1, x2, y2, attrs) {
|
|
31414
32469
|
return el("line", { x1, y1, x2, y2, ...attrs });
|
|
@@ -32129,13 +33184,13 @@ function renderSubstrate(sub) {
|
|
|
32129
33184
|
{ y: sub.y + BB_CONST.BOARD_PAD_Y, type: "top" },
|
|
32130
33185
|
{ y: sub.y + sub.height - BB_CONST.BOARD_PAD_Y - BB_CONST.RAIL_HEIGHT, type: "bottom" }
|
|
32131
33186
|
];
|
|
32132
|
-
for (const
|
|
33187
|
+
for (const r7 of rails) {
|
|
32133
33188
|
elements.push(path({
|
|
32134
|
-
d: `M ${sub.x + BB_CONST.BOARD_PAD_X} ${
|
|
33189
|
+
d: `M ${sub.x + BB_CONST.BOARD_PAD_X} ${r7.y + 4} L ${sub.x + sub.width - BB_CONST.BOARD_PAD_X} ${r7.y + 4}`,
|
|
32135
33190
|
class: "lt-bb-rail-stripe-pos"
|
|
32136
33191
|
}));
|
|
32137
33192
|
elements.push(path({
|
|
32138
|
-
d: `M ${sub.x + BB_CONST.BOARD_PAD_X} ${
|
|
33193
|
+
d: `M ${sub.x + BB_CONST.BOARD_PAD_X} ${r7.y + BB_CONST.RAIL_HEIGHT - 4} L ${sub.x + sub.width - BB_CONST.BOARD_PAD_X} ${r7.y + BB_CONST.RAIL_HEIGHT - 4}`,
|
|
32139
33194
|
class: "lt-bb-rail-stripe-neg"
|
|
32140
33195
|
}));
|
|
32141
33196
|
if (sub.railsBreak) {
|
|
@@ -32143,7 +33198,7 @@ function renderSubstrate(sub) {
|
|
|
32143
33198
|
const breakX2 = breakX1 + PITCH2;
|
|
32144
33199
|
elements.push(rect({
|
|
32145
33200
|
x: breakX1,
|
|
32146
|
-
y:
|
|
33201
|
+
y: r7.y,
|
|
32147
33202
|
width: breakX2 - breakX1,
|
|
32148
33203
|
height: BB_CONST.RAIL_HEIGHT,
|
|
32149
33204
|
fill: "#e7d8b6"
|
|
@@ -32151,8 +33206,8 @@ function renderSubstrate(sub) {
|
|
|
32151
33206
|
}
|
|
32152
33207
|
for (let c = 1; c <= sub.cols; c++) {
|
|
32153
33208
|
const cx = sub.x + BB_CONST.BOARD_PAD_X + BB_CONST.ROW_LABEL_W + PITCH2 / 2 + (c - 1) * PITCH2;
|
|
32154
|
-
elements.push(circle({ cx, cy:
|
|
32155
|
-
elements.push(circle({ cx, cy:
|
|
33209
|
+
elements.push(circle({ cx, cy: r7.y + 4, r: 1.4, class: "lt-bb-hole-rail" }));
|
|
33210
|
+
elements.push(circle({ cx, cy: r7.y + BB_CONST.RAIL_HEIGHT - 4, r: 1.4, class: "lt-bb-hole-rail" }));
|
|
32156
33211
|
}
|
|
32157
33212
|
}
|
|
32158
33213
|
}
|
|
@@ -32179,10 +33234,10 @@ function renderSubstrate(sub) {
|
|
|
32179
33234
|
elements.push(text({ x: sub.x + sub.width - BB_CONST.BOARD_PAD_X - 4, y: yBot, class: "lt-bb-row-label" }, rowsBot[i]));
|
|
32180
33235
|
}
|
|
32181
33236
|
for (let c = 1; c <= sub.cols; c++) {
|
|
32182
|
-
for (let
|
|
33237
|
+
for (let r7 = 0; r7 < 10; r7++) {
|
|
32183
33238
|
const cx = sub.x + BB_CONST.BOARD_PAD_X + BB_CONST.ROW_LABEL_W + PITCH2 / 2 + (c - 1) * PITCH2;
|
|
32184
|
-
let cy = gridY0 +
|
|
32185
|
-
if (
|
|
33239
|
+
let cy = gridY0 + r7 * PITCH2;
|
|
33240
|
+
if (r7 >= 5) cy += BB_CONST.TROUGH;
|
|
32186
33241
|
elements.push(circle({ cx, cy, r: 1.6, class: "lt-bb-hole" }));
|
|
32187
33242
|
}
|
|
32188
33243
|
}
|
|
@@ -32684,34 +33739,34 @@ function parseFlowLine(ln, flows, objectOwner, poolByLabel) {
|
|
|
32684
33739
|
connectorLen = 3;
|
|
32685
33740
|
} else if (rest.startsWith("--?")) {
|
|
32686
33741
|
kind = "conditional";
|
|
32687
|
-
let
|
|
32688
|
-
const q = takeQuoted(
|
|
33742
|
+
let r7 = rest.slice(3).trimStart();
|
|
33743
|
+
const q = takeQuoted(r7);
|
|
32689
33744
|
if (q) {
|
|
32690
33745
|
connectorLabel = q.value;
|
|
32691
|
-
|
|
33746
|
+
r7 = q.rest.trimStart();
|
|
32692
33747
|
}
|
|
32693
|
-
if (!
|
|
33748
|
+
if (!r7.startsWith("-->")) {
|
|
32694
33749
|
throw new BpmnParseError(
|
|
32695
|
-
`conditional flow must end with --> (got '${
|
|
33750
|
+
`conditional flow must end with --> (got '${r7.slice(0, 20)}')`,
|
|
32696
33751
|
ln.no
|
|
32697
33752
|
);
|
|
32698
33753
|
}
|
|
32699
|
-
connectorLen = rest.length -
|
|
33754
|
+
connectorLen = rest.length - r7.length + 3;
|
|
32700
33755
|
} else if (rest.startsWith("--*")) {
|
|
32701
33756
|
kind = "default";
|
|
32702
|
-
let
|
|
32703
|
-
const q = takeQuoted(
|
|
33757
|
+
let r7 = rest.slice(3).trimStart();
|
|
33758
|
+
const q = takeQuoted(r7);
|
|
32704
33759
|
if (q) {
|
|
32705
33760
|
connectorLabel = q.value;
|
|
32706
|
-
|
|
33761
|
+
r7 = q.rest.trimStart();
|
|
32707
33762
|
}
|
|
32708
|
-
if (!
|
|
33763
|
+
if (!r7.startsWith("-->")) {
|
|
32709
33764
|
throw new BpmnParseError(
|
|
32710
|
-
`default flow must end with --> (got '${
|
|
33765
|
+
`default flow must end with --> (got '${r7.slice(0, 20)}')`,
|
|
32711
33766
|
ln.no
|
|
32712
33767
|
);
|
|
32713
33768
|
}
|
|
32714
|
-
connectorLen = rest.length -
|
|
33769
|
+
connectorLen = rest.length - r7.length + 3;
|
|
32715
33770
|
} else if (rest.startsWith("-->")) {
|
|
32716
33771
|
kind = "sequence";
|
|
32717
33772
|
connectorLen = 3;
|
|
@@ -32804,8 +33859,8 @@ function objBox(o) {
|
|
|
32804
33859
|
if ("gatewayKind" in o) {
|
|
32805
33860
|
return { w: BPMN_CONST.gatewaySize, h: BPMN_CONST.gatewaySize };
|
|
32806
33861
|
}
|
|
32807
|
-
const
|
|
32808
|
-
return { w:
|
|
33862
|
+
const r7 = BPMN_CONST.eventRadius;
|
|
33863
|
+
return { w: r7 * 2, h: r7 * 2 };
|
|
32809
33864
|
}
|
|
32810
33865
|
function layoutBpmn(ast) {
|
|
32811
33866
|
const allObjects = [
|
|
@@ -33416,11 +34471,11 @@ function renderGateway(ol, t) {
|
|
|
33416
34471
|
const g = ol.obj;
|
|
33417
34472
|
const cx = ol.x + ol.width / 2;
|
|
33418
34473
|
const cy = ol.y + ol.height / 2;
|
|
33419
|
-
const
|
|
33420
|
-
const points = `${cx},${cy -
|
|
34474
|
+
const r7 = ol.width / 2;
|
|
34475
|
+
const points = `${cx},${cy - r7} ${cx + r7},${cy} ${cx},${cy + r7} ${cx - r7},${cy}`;
|
|
33421
34476
|
const inner = [];
|
|
33422
34477
|
if (g.gatewayKind === "xor") {
|
|
33423
|
-
const a =
|
|
34478
|
+
const a = r7 * 0.42;
|
|
33424
34479
|
inner.push(
|
|
33425
34480
|
el("path", {
|
|
33426
34481
|
d: `M ${cx - a} ${cy - a} L ${cx + a} ${cy + a} M ${cx + a} ${cy - a} L ${cx - a} ${cy + a}`,
|
|
@@ -33430,7 +34485,7 @@ function renderGateway(ol, t) {
|
|
|
33430
34485
|
})
|
|
33431
34486
|
);
|
|
33432
34487
|
} else if (g.gatewayKind === "and") {
|
|
33433
|
-
const a =
|
|
34488
|
+
const a = r7 * 0.5;
|
|
33434
34489
|
inner.push(
|
|
33435
34490
|
el("path", {
|
|
33436
34491
|
d: `M ${cx - a} ${cy} L ${cx + a} ${cy} M ${cx} ${cy - a} L ${cx} ${cy + a}`,
|
|
@@ -33444,7 +34499,7 @@ function renderGateway(ol, t) {
|
|
|
33444
34499
|
el("circle", {
|
|
33445
34500
|
cx,
|
|
33446
34501
|
cy,
|
|
33447
|
-
r:
|
|
34502
|
+
r: r7 * 0.45,
|
|
33448
34503
|
fill: "none",
|
|
33449
34504
|
stroke: t.gatewayGlyph,
|
|
33450
34505
|
"stroke-width": 2
|
|
@@ -33455,13 +34510,13 @@ function renderGateway(ol, t) {
|
|
|
33455
34510
|
el("circle", {
|
|
33456
34511
|
cx,
|
|
33457
34512
|
cy,
|
|
33458
|
-
r:
|
|
34513
|
+
r: r7 * 0.55,
|
|
33459
34514
|
fill: "none",
|
|
33460
34515
|
stroke: t.gatewayGlyph,
|
|
33461
34516
|
"stroke-width": 1
|
|
33462
34517
|
})
|
|
33463
34518
|
);
|
|
33464
|
-
const pr =
|
|
34519
|
+
const pr = r7 * 0.32;
|
|
33465
34520
|
const pts = [];
|
|
33466
34521
|
for (let k = 0; k < 5; k++) {
|
|
33467
34522
|
const ang = -Math.PI / 2 + k * 2 * Math.PI / 5;
|
|
@@ -33503,7 +34558,7 @@ function renderEvent2(ol, t) {
|
|
|
33503
34558
|
const e = ol.obj;
|
|
33504
34559
|
const cx = ol.x + ol.width / 2;
|
|
33505
34560
|
const cy = ol.y + ol.height / 2;
|
|
33506
|
-
const
|
|
34561
|
+
const r7 = ol.width / 2;
|
|
33507
34562
|
const isEnd = e.kind === "end";
|
|
33508
34563
|
const isIntermediate = e.kind === "intermediate";
|
|
33509
34564
|
const strokeW = isEnd ? 3 : 1.2;
|
|
@@ -33514,7 +34569,7 @@ function renderEvent2(ol, t) {
|
|
|
33514
34569
|
el("circle", {
|
|
33515
34570
|
cx,
|
|
33516
34571
|
cy,
|
|
33517
|
-
r:
|
|
34572
|
+
r: r7,
|
|
33518
34573
|
fill,
|
|
33519
34574
|
stroke: ring,
|
|
33520
34575
|
"stroke-width": strokeW
|
|
@@ -33525,7 +34580,7 @@ function renderEvent2(ol, t) {
|
|
|
33525
34580
|
el("circle", {
|
|
33526
34581
|
cx,
|
|
33527
34582
|
cy,
|
|
33528
|
-
r:
|
|
34583
|
+
r: r7 - 3,
|
|
33529
34584
|
fill: "none",
|
|
33530
34585
|
stroke: ring,
|
|
33531
34586
|
"stroke-width": 1.2
|
|
@@ -33534,9 +34589,9 @@ function renderEvent2(ol, t) {
|
|
|
33534
34589
|
}
|
|
33535
34590
|
const filled = e.throwCatch === "throw" && (isIntermediate || isEnd);
|
|
33536
34591
|
if (e.trigger === "message") {
|
|
33537
|
-
children.push(messageGlyph(cx, cy,
|
|
34592
|
+
children.push(messageGlyph(cx, cy, r7 * 0.55, filled, t));
|
|
33538
34593
|
} else if (e.trigger === "timer") {
|
|
33539
|
-
children.push(timerGlyph(cx, cy,
|
|
34594
|
+
children.push(timerGlyph(cx, cy, r7 * 0.55, t));
|
|
33540
34595
|
}
|
|
33541
34596
|
if (e.label) {
|
|
33542
34597
|
children.push(
|
|
@@ -33579,22 +34634,22 @@ function messageGlyph(cx, cy, size, filled, t) {
|
|
|
33579
34634
|
]);
|
|
33580
34635
|
}
|
|
33581
34636
|
function timerGlyph(cx, cy, size, t) {
|
|
33582
|
-
const
|
|
34637
|
+
const r7 = size / 2;
|
|
33583
34638
|
const ticks = [];
|
|
33584
34639
|
for (let k = 0; k < 12; k++) {
|
|
33585
34640
|
const ang = k * Math.PI / 6 - Math.PI / 2;
|
|
33586
|
-
const t1x = cx + (
|
|
33587
|
-
const t1y = cy + (
|
|
33588
|
-
const t2x = cx +
|
|
33589
|
-
const t2y = cy +
|
|
34641
|
+
const t1x = cx + (r7 - 1.5) * Math.cos(ang);
|
|
34642
|
+
const t1y = cy + (r7 - 1.5) * Math.sin(ang);
|
|
34643
|
+
const t2x = cx + r7 * Math.cos(ang);
|
|
34644
|
+
const t2y = cy + r7 * Math.sin(ang);
|
|
33590
34645
|
ticks.push(`M ${t1x} ${t1y} L ${t2x} ${t2y}`);
|
|
33591
34646
|
}
|
|
33592
34647
|
return el("g", { class: "trigger-timer" }, [
|
|
33593
|
-
el("circle", { cx, cy, r:
|
|
34648
|
+
el("circle", { cx, cy, r: r7, fill: "none", stroke: t.bpmnStroke, "stroke-width": 1 }),
|
|
33594
34649
|
el("path", { d: ticks.join(" "), stroke: t.bpmnStroke, "stroke-width": 0.8 }),
|
|
33595
34650
|
// Hands
|
|
33596
34651
|
el("path", {
|
|
33597
|
-
d: `M ${cx} ${cy} L ${cx} ${cy -
|
|
34652
|
+
d: `M ${cx} ${cy} L ${cx} ${cy - r7 * 0.7} M ${cx} ${cy} L ${cx + r7 * 0.5} ${cy}`,
|
|
33598
34653
|
stroke: t.bpmnStroke,
|
|
33599
34654
|
"stroke-width": 1.2,
|
|
33600
34655
|
"stroke-linecap": "round"
|
|
@@ -33665,8 +34720,8 @@ function parseStart(d) {
|
|
|
33665
34720
|
if (!m) return null;
|
|
33666
34721
|
return { x: parseFloat(m[1]), y: parseFloat(m[2]) };
|
|
33667
34722
|
}
|
|
33668
|
-
function diamondPoints(cx, cy,
|
|
33669
|
-
return `${cx -
|
|
34723
|
+
function diamondPoints(cx, cy, r7) {
|
|
34724
|
+
return `${cx - r7},${cy} ${cx},${cy - r7} ${cx + r7},${cy} ${cx},${cy + r7}`;
|
|
33670
34725
|
}
|
|
33671
34726
|
|
|
33672
34727
|
// src/diagrams/bpmn/index.ts
|
|
@@ -34869,7 +35924,7 @@ function wireClass(t) {
|
|
|
34869
35924
|
return "lt-fbd-wire-any";
|
|
34870
35925
|
}
|
|
34871
35926
|
}
|
|
34872
|
-
function
|
|
35927
|
+
function renderBlock2(lb) {
|
|
34873
35928
|
const { x, y, width, height, block } = lb;
|
|
34874
35929
|
const headerH = FBD_CONST.block_header_h;
|
|
34875
35930
|
const parts = [];
|
|
@@ -35005,7 +36060,7 @@ function renderNetwork2(ln) {
|
|
|
35005
36060
|
for (const j of ln.junctions) {
|
|
35006
36061
|
parts.push(circle({ class: "lt-fbd-junction", cx: j.x, cy: j.y, r: 3 }));
|
|
35007
36062
|
}
|
|
35008
|
-
for (const b of ln.blocks) parts.push(
|
|
36063
|
+
for (const b of ln.blocks) parts.push(renderBlock2(b));
|
|
35009
36064
|
return group({ class: "lt-fbd-network", "data-network": ln.network.index }, parts);
|
|
35010
36065
|
}
|
|
35011
36066
|
function renderFbdLayout(layout) {
|
|
@@ -36075,14 +37130,14 @@ function roundTable(seats, diaM) {
|
|
|
36075
37130
|
draw: (c) => {
|
|
36076
37131
|
const half = Math.min(c.w, c.h) / 2;
|
|
36077
37132
|
const ring = Math.min(RING, half * 0.37);
|
|
36078
|
-
const
|
|
37133
|
+
const r7 = half - ring;
|
|
36079
37134
|
const cx = c.w / 2;
|
|
36080
37135
|
const cy = c.h / 2;
|
|
36081
|
-
const parts = [circle({ class: "sx-fp-furn", cx: c.px(cx), cy: c.px(cy), r: c.px(
|
|
37136
|
+
const parts = [circle({ class: "sx-fp-furn", cx: c.px(cx), cy: c.px(cy), r: c.px(r7) })];
|
|
36082
37137
|
for (let i = 0; i < seats; i++) {
|
|
36083
37138
|
const a = i / seats * 2 * Math.PI - Math.PI / 2;
|
|
36084
|
-
const px0 = cx + (
|
|
36085
|
-
const py0 = cy + (
|
|
37139
|
+
const px0 = cx + (r7 + ring * 0.55) * Math.cos(a);
|
|
37140
|
+
const py0 = cy + (r7 + ring * 0.55) * Math.sin(a);
|
|
36086
37141
|
parts.push(chairAt(c.px, px0, py0, a * 180 / Math.PI + 90));
|
|
36087
37142
|
}
|
|
36088
37143
|
return parts.join("");
|
|
@@ -36232,11 +37287,11 @@ function uStairs(c) {
|
|
|
36232
37287
|
return parts.join("");
|
|
36233
37288
|
}
|
|
36234
37289
|
function spiralStairs(c) {
|
|
36235
|
-
const
|
|
37290
|
+
const r7 = Math.min(c.w, c.h) / 2 - 0.02;
|
|
36236
37291
|
const cx = c.w / 2;
|
|
36237
37292
|
const cy = c.h / 2;
|
|
36238
37293
|
const parts = [
|
|
36239
|
-
circle({ class: "sx-fp-furn", cx: c.px(cx), cy: c.px(cy), r: c.px(
|
|
37294
|
+
circle({ class: "sx-fp-furn", cx: c.px(cx), cy: c.px(cy), r: c.px(r7) }),
|
|
36240
37295
|
circle({ class: "sx-fp-furn-line", cx: c.px(cx), cy: c.px(cy), r: c.px(0.08) })
|
|
36241
37296
|
];
|
|
36242
37297
|
for (let i = 0; i < 12; i++) {
|
|
@@ -36246,12 +37301,12 @@ function spiralStairs(c) {
|
|
|
36246
37301
|
class: "sx-fp-furn-line",
|
|
36247
37302
|
x1: c.px(cx + 0.08 * Math.cos(a)),
|
|
36248
37303
|
y1: c.px(cy + 0.08 * Math.sin(a)),
|
|
36249
|
-
x2: c.px(cx +
|
|
36250
|
-
y2: c.px(cy +
|
|
37304
|
+
x2: c.px(cx + r7 * Math.cos(a)),
|
|
37305
|
+
y2: c.px(cy + r7 * Math.sin(a))
|
|
36251
37306
|
})
|
|
36252
37307
|
);
|
|
36253
37308
|
}
|
|
36254
|
-
const wr =
|
|
37309
|
+
const wr = r7 * 0.62;
|
|
36255
37310
|
const a0 = Math.PI * 0.75;
|
|
36256
37311
|
const a1 = Math.PI * 1.9;
|
|
36257
37312
|
const steps = 5;
|
|
@@ -36323,8 +37378,8 @@ var FLOORPLAN_SYMBOLS = {
|
|
|
36323
37378
|
w: 0.5,
|
|
36324
37379
|
h: 0.5,
|
|
36325
37380
|
draw: (c) => {
|
|
36326
|
-
const
|
|
36327
|
-
const parts = [circle({ class: "sx-fp-furn", cx: c.px(c.w / 2), cy: c.px(c.h / 2), r: c.px(
|
|
37381
|
+
const r7 = Math.min(c.w, c.h) / 2;
|
|
37382
|
+
const parts = [circle({ class: "sx-fp-furn", cx: c.px(c.w / 2), cy: c.px(c.h / 2), r: c.px(r7) })];
|
|
36328
37383
|
for (const a of [0, 60, 120, 180, 240, 300]) {
|
|
36329
37384
|
const rad = a * Math.PI / 180;
|
|
36330
37385
|
parts.push(
|
|
@@ -36332,8 +37387,8 @@ var FLOORPLAN_SYMBOLS = {
|
|
|
36332
37387
|
class: "sx-fp-furn-line",
|
|
36333
37388
|
x1: c.px(c.w / 2),
|
|
36334
37389
|
y1: c.px(c.h / 2),
|
|
36335
|
-
x2: c.px(c.w / 2 + (
|
|
36336
|
-
y2: c.px(c.h / 2 + (
|
|
37390
|
+
x2: c.px(c.w / 2 + (r7 - 0.03) * Math.cos(rad)),
|
|
37391
|
+
y2: c.px(c.h / 2 + (r7 - 0.03) * Math.sin(rad))
|
|
36337
37392
|
})
|
|
36338
37393
|
);
|
|
36339
37394
|
}
|
|
@@ -36393,11 +37448,11 @@ var FLOORPLAN_SYMBOLS = {
|
|
|
36393
37448
|
w: 0.35,
|
|
36394
37449
|
h: 0.35,
|
|
36395
37450
|
draw: (c) => {
|
|
36396
|
-
const
|
|
37451
|
+
const r7 = Math.min(c.w, c.h) / 2;
|
|
36397
37452
|
return [
|
|
36398
|
-
circle({ class: "sx-fp-furn", cx: c.px(c.w / 2), cy: c.px(c.h / 2), r: c.px(
|
|
36399
|
-
line({ class: "sx-fp-furn-line", x1: c.px(c.w / 2 -
|
|
36400
|
-
line({ class: "sx-fp-furn-line", x1: c.px(c.w / 2), y1: c.px(c.h / 2 -
|
|
37453
|
+
circle({ class: "sx-fp-furn", cx: c.px(c.w / 2), cy: c.px(c.h / 2), r: c.px(r7) }),
|
|
37454
|
+
line({ class: "sx-fp-furn-line", x1: c.px(c.w / 2 - r7), y1: c.px(c.h / 2), x2: c.px(c.w / 2 + r7), y2: c.px(c.h / 2) }),
|
|
37455
|
+
line({ class: "sx-fp-furn-line", x1: c.px(c.w / 2), y1: c.px(c.h / 2 - r7), x2: c.px(c.w / 2), y2: c.px(c.h / 2 + r7) })
|
|
36401
37456
|
].join("");
|
|
36402
37457
|
}
|
|
36403
37458
|
},
|
|
@@ -36473,23 +37528,23 @@ var FLOORPLAN_SYMBOLS = {
|
|
|
36473
37528
|
underlay: true,
|
|
36474
37529
|
// overhead fixture — never collides with floor furniture
|
|
36475
37530
|
draw: (c) => {
|
|
36476
|
-
const
|
|
37531
|
+
const r7 = Math.min(c.w, c.h) / 2;
|
|
36477
37532
|
const cx = c.w / 2;
|
|
36478
37533
|
const cy = c.h / 2;
|
|
36479
37534
|
const parts = [
|
|
36480
|
-
circle({ class: "sx-fp-furn-dash", cx: c.px(cx), cy: c.px(cy), r: c.px(
|
|
36481
|
-
circle({ class: "sx-fp-furn", cx: c.px(cx), cy: c.px(cy), r: c.px(
|
|
37535
|
+
circle({ class: "sx-fp-furn-dash", cx: c.px(cx), cy: c.px(cy), r: c.px(r7) }),
|
|
37536
|
+
circle({ class: "sx-fp-furn", cx: c.px(cx), cy: c.px(cy), r: c.px(r7 * 0.18) })
|
|
36482
37537
|
];
|
|
36483
37538
|
for (const a of [20, 110, 200, 290]) {
|
|
36484
37539
|
const rad = a * Math.PI / 180;
|
|
36485
37540
|
parts.push(
|
|
36486
37541
|
el("ellipse", {
|
|
36487
37542
|
class: "sx-fp-furn-line",
|
|
36488
|
-
cx: c.px(cx +
|
|
36489
|
-
cy: c.px(cy +
|
|
36490
|
-
rx: c.px(
|
|
36491
|
-
ry: c.px(
|
|
36492
|
-
transform: `rotate(${a} ${c.px(cx +
|
|
37543
|
+
cx: c.px(cx + r7 * 0.55 * Math.cos(rad)),
|
|
37544
|
+
cy: c.px(cy + r7 * 0.55 * Math.sin(rad)),
|
|
37545
|
+
rx: c.px(r7 * 0.42),
|
|
37546
|
+
ry: c.px(r7 * 0.15),
|
|
37547
|
+
transform: `rotate(${a} ${c.px(cx + r7 * 0.55 * Math.cos(rad))} ${c.px(cy + r7 * 0.55 * Math.sin(rad))})`
|
|
36493
37548
|
})
|
|
36494
37549
|
);
|
|
36495
37550
|
}
|
|
@@ -36866,11 +37921,11 @@ var FLOORPLAN_SYMBOLS = {
|
|
|
36866
37921
|
w: 1,
|
|
36867
37922
|
h: 1,
|
|
36868
37923
|
draw: (c) => {
|
|
36869
|
-
const
|
|
37924
|
+
const r7 = Math.min(c.w, c.h) / 2;
|
|
36870
37925
|
const cx = c.w / 2;
|
|
36871
37926
|
const cy = c.h / 2;
|
|
36872
37927
|
const parts = [
|
|
36873
|
-
circle({ class: "sx-fp-furn-nofill", cx: c.px(cx), cy: c.px(cy), r: c.px(
|
|
37928
|
+
circle({ class: "sx-fp-furn-nofill", cx: c.px(cx), cy: c.px(cy), r: c.px(r7) }),
|
|
36874
37929
|
circle({ class: "sx-fp-furn-dot", cx: c.px(cx), cy: c.px(cy), r: c.px(0.04) })
|
|
36875
37930
|
];
|
|
36876
37931
|
for (const a of [0, 45, 90, 135, 180, 225, 270, 315]) {
|
|
@@ -36878,10 +37933,10 @@ var FLOORPLAN_SYMBOLS = {
|
|
|
36878
37933
|
parts.push(
|
|
36879
37934
|
line({
|
|
36880
37935
|
class: "sx-fp-furn-line",
|
|
36881
|
-
x1: c.px(cx + (
|
|
36882
|
-
y1: c.px(cy + (
|
|
36883
|
-
x2: c.px(cx +
|
|
36884
|
-
y2: c.px(cy +
|
|
37936
|
+
x1: c.px(cx + (r7 - 0.09) * Math.cos(rad)),
|
|
37937
|
+
y1: c.px(cy + (r7 - 0.09) * Math.sin(rad)),
|
|
37938
|
+
x2: c.px(cx + r7 * Math.cos(rad)),
|
|
37939
|
+
y2: c.px(cy + r7 * Math.sin(rad))
|
|
36885
37940
|
})
|
|
36886
37941
|
);
|
|
36887
37942
|
}
|
|
@@ -37031,10 +38086,10 @@ var FLOORPLAN_SYMBOLS = {
|
|
|
37031
38086
|
w: 2,
|
|
37032
38087
|
h: 2,
|
|
37033
38088
|
draw: (c) => {
|
|
37034
|
-
const
|
|
38089
|
+
const r7 = Math.min(c.w, c.h) / 2;
|
|
37035
38090
|
return [
|
|
37036
|
-
circle({ class: "sx-fp-furn", cx: c.px(c.w / 2), cy: c.px(c.h / 2), r: c.px(
|
|
37037
|
-
circle({ class: "sx-fp-furn-line", cx: c.px(c.w / 2), cy: c.px(c.h / 2), r: c.px(
|
|
38091
|
+
circle({ class: "sx-fp-furn", cx: c.px(c.w / 2), cy: c.px(c.h / 2), r: c.px(r7) }),
|
|
38092
|
+
circle({ class: "sx-fp-furn-line", cx: c.px(c.w / 2), cy: c.px(c.h / 2), r: c.px(r7 * 0.6) }),
|
|
37038
38093
|
circle({ class: "sx-fp-furn-dot", cx: c.px(c.w / 2), cy: c.px(c.h / 2), r: c.px(0.07) })
|
|
37039
38094
|
].join("");
|
|
37040
38095
|
}
|
|
@@ -37068,10 +38123,10 @@ var FloorplanParseError = class extends Error {
|
|
|
37068
38123
|
};
|
|
37069
38124
|
var isStr = (t) => t !== void 0 && "str" in t;
|
|
37070
38125
|
var isWord = (t, w) => t !== void 0 && "word" in t && (w === void 0 || t.word === w);
|
|
37071
|
-
function
|
|
38126
|
+
function normalizeQuotes4(line2) {
|
|
37072
38127
|
return line2.replace(/[“”「」『』]/g, '"').replace(/[‘’]/g, "'");
|
|
37073
38128
|
}
|
|
37074
|
-
function
|
|
38129
|
+
function tokenize8(line2) {
|
|
37075
38130
|
const out = [];
|
|
37076
38131
|
const re = /"([^"]*)"|(\S+)/g;
|
|
37077
38132
|
let m;
|
|
@@ -37081,7 +38136,7 @@ function tokenize7(line2) {
|
|
|
37081
38136
|
}
|
|
37082
38137
|
return out;
|
|
37083
38138
|
}
|
|
37084
|
-
function
|
|
38139
|
+
function parseNum2(t, what, ln) {
|
|
37085
38140
|
if (!isWord(t)) throw new FloorplanParseError(`expected a number for ${what}`, ln);
|
|
37086
38141
|
const v = Number(t.word);
|
|
37087
38142
|
if (!Number.isFinite(v)) throw new FloorplanParseError(`expected a number for ${what}, got "${t.word}"`, ln);
|
|
@@ -37134,7 +38189,7 @@ function parseHeader3(tok, ast, ln) {
|
|
|
37134
38189
|
}
|
|
37135
38190
|
function parseRoom(tok, ast, ln) {
|
|
37136
38191
|
const id = parseId(tok.shift(), "a room id", ln);
|
|
37137
|
-
if (ast.rooms.some((
|
|
38192
|
+
if (ast.rooms.some((r7) => r7.id === id)) {
|
|
37138
38193
|
throw new FloorplanParseError(`duplicate room id "${id}"`, ln);
|
|
37139
38194
|
}
|
|
37140
38195
|
const room = { id, label: id, w: 4, h: 3, line: ln };
|
|
@@ -37151,7 +38206,7 @@ function parseRoom(tok, ast, ln) {
|
|
|
37151
38206
|
};
|
|
37152
38207
|
} else if (t.word === "offset") {
|
|
37153
38208
|
if (!room.rel) throw new FloorplanParseError(`"offset" requires a relative placement (right-of/left-of/above/below)`, ln);
|
|
37154
|
-
room.rel.offset =
|
|
38209
|
+
room.rel.offset = parseNum2(tok.shift(), "offset", ln);
|
|
37155
38210
|
} else if (t.word === "align") {
|
|
37156
38211
|
if (!room.rel) throw new FloorplanParseError(`"align" requires a relative placement (right-of/left-of/above/below)`, ln);
|
|
37157
38212
|
const a = parseId(tok.shift(), "align (start|center|end)", ln);
|
|
@@ -37185,7 +38240,7 @@ function parseExtend(tok, ast, ln) {
|
|
|
37185
38240
|
};
|
|
37186
38241
|
} else if (t.word === "offset") {
|
|
37187
38242
|
if (!ext.rel) throw new FloorplanParseError(`"offset" requires a relative placement (right-of/left-of/above/below)`, ln);
|
|
37188
|
-
ext.rel.offset =
|
|
38243
|
+
ext.rel.offset = parseNum2(tok.shift(), "offset", ln);
|
|
37189
38244
|
} else if (t.word === "align") {
|
|
37190
38245
|
if (!ext.rel) throw new FloorplanParseError(`"align" requires a relative placement (right-of/left-of/above/below)`, ln);
|
|
37191
38246
|
const a = parseId(tok.shift(), "align (start|center|end)", ln);
|
|
@@ -37230,7 +38285,7 @@ function parseOpening(kind, tok, ast, ln) {
|
|
|
37230
38285
|
const t = tok.shift();
|
|
37231
38286
|
if (!isWord(t)) throw new FloorplanParseError(`${kind}: unexpected string "${t.str}"`, ln);
|
|
37232
38287
|
else if (t.word === "at") op.pct = parsePct(tok.shift(), ln);
|
|
37233
|
-
else if (t.word === "width") op.width =
|
|
38288
|
+
else if (t.word === "width") op.width = parseNum2(tok.shift(), "width", ln);
|
|
37234
38289
|
else if (t.word === "hinge") {
|
|
37235
38290
|
const h = parseId(tok.shift(), "hinge (left|right)", ln);
|
|
37236
38291
|
if (h !== "left" && h !== "right") throw new FloorplanParseError(`hinge must be left|right, got "${h}"`, ln);
|
|
@@ -37271,7 +38326,7 @@ function parseFurniture(tok, ast, ln) {
|
|
|
37271
38326
|
f.x = c.x;
|
|
37272
38327
|
f.y = c.y;
|
|
37273
38328
|
} else if (t.word === "size") f.size = parseDims(tok.shift(), "size", ln);
|
|
37274
|
-
else if (t.word === "rotate") f.rotate =
|
|
38329
|
+
else if (t.word === "rotate") f.rotate = parseNum2(tok.shift(), "rotate", ln);
|
|
37275
38330
|
else throw new FloorplanParseError(`furniture: unexpected token "${t.word}"`, ln);
|
|
37276
38331
|
}
|
|
37277
38332
|
ast.furniture.push(f);
|
|
@@ -37291,18 +38346,18 @@ function parseArray(mode, tok, ast, ln) {
|
|
|
37291
38346
|
const t = tok.shift();
|
|
37292
38347
|
if (!isWord(t)) throw new FloorplanParseError(`${mode}: unexpected string "${t.str}"`, ln);
|
|
37293
38348
|
else if (t.word === "in") a.room = parseId(tok.shift(), `a room id after "in"`, ln);
|
|
37294
|
-
else if (t.word === "rows") a.rows =
|
|
37295
|
-
else if (t.word === "cols") a.cols =
|
|
37296
|
-
else if (t.word === "count") a.count =
|
|
38349
|
+
else if (t.word === "rows") a.rows = parseNum2(tok.shift(), "rows", ln);
|
|
38350
|
+
else if (t.word === "cols") a.cols = parseNum2(tok.shift(), "cols", ln);
|
|
38351
|
+
else if (t.word === "count") a.count = parseNum2(tok.shift(), "count", ln);
|
|
37297
38352
|
else if (t.word === "area") {
|
|
37298
38353
|
a.p1 = parseCoord2(tok.shift(), "area p1", ln);
|
|
37299
38354
|
a.p2 = parseCoord2(tok.shift(), "area p2", ln);
|
|
37300
38355
|
} else if (t.word === "itemsize") a.itemsize = parseDims(tok.shift(), "itemsize", ln);
|
|
37301
|
-
else if (t.word === "rotate") a.rotate =
|
|
38356
|
+
else if (t.word === "rotate") a.rotate = parseNum2(tok.shift(), "rotate", ln);
|
|
37302
38357
|
else if (t.word === "center") a.center = parseCoord2(tok.shift(), "center", ln);
|
|
37303
|
-
else if (t.word === "radius") a.radius =
|
|
37304
|
-
else if (t.word === "from") a.fromDeg =
|
|
37305
|
-
else if (t.word === "to") a.toDeg =
|
|
38358
|
+
else if (t.word === "radius") a.radius = parseNum2(tok.shift(), "radius", ln);
|
|
38359
|
+
else if (t.word === "from") a.fromDeg = parseNum2(tok.shift(), "from", ln);
|
|
38360
|
+
else if (t.word === "to") a.toDeg = parseNum2(tok.shift(), "to", ln);
|
|
37306
38361
|
else throw new FloorplanParseError(`${mode}: unexpected token "${t.word}"`, ln);
|
|
37307
38362
|
}
|
|
37308
38363
|
ast.arrays.push(a);
|
|
@@ -37322,9 +38377,9 @@ function parseFloorplan(text2) {
|
|
|
37322
38377
|
const lines = text2.split(/\r?\n/);
|
|
37323
38378
|
for (let i = 0; i < lines.length; i++) {
|
|
37324
38379
|
const ln = i + 1;
|
|
37325
|
-
const raw =
|
|
38380
|
+
const raw = normalizeQuotes4(lines[i]).trim();
|
|
37326
38381
|
if (!raw) continue;
|
|
37327
|
-
const all =
|
|
38382
|
+
const all = tokenize8(raw);
|
|
37328
38383
|
const tok = [];
|
|
37329
38384
|
for (let k = 0; k < all.length; k++) {
|
|
37330
38385
|
const t = all[k];
|
|
@@ -37349,7 +38404,7 @@ function parseFloorplan(text2) {
|
|
|
37349
38404
|
throw new FloorplanParseError(`the first statement must be the "floorplan" header`, ln);
|
|
37350
38405
|
} else if (kw === "room") parseRoom(tok, ast, ln);
|
|
37351
38406
|
else if (kw === "north") {
|
|
37352
|
-
ast.north = tok.length ?
|
|
38407
|
+
ast.north = tok.length ? parseNum2(tok.shift(), "north rotation (degrees)", ln) : 0;
|
|
37353
38408
|
if (tok.length) throw new FloorplanParseError(`north: unexpected trailing tokens`, ln);
|
|
37354
38409
|
} else if (kw === "extend") parseExtend(tok, ast, ln);
|
|
37355
38410
|
else if (kw === "door" || kw === "window" || kw === "opening") parseOpening(kw, tok, ast, ln);
|
|
@@ -37612,14 +38667,14 @@ function layoutFloorplan(ast) {
|
|
|
37612
38667
|
].sort((a, b) => a.line - b.line);
|
|
37613
38668
|
for (const stmt of stmts) {
|
|
37614
38669
|
if (stmt.room) {
|
|
37615
|
-
const
|
|
37616
|
-
const w =
|
|
37617
|
-
const h =
|
|
37618
|
-
const pos = resolvePlacement(
|
|
38670
|
+
const r7 = stmt.room;
|
|
38671
|
+
const w = r7.w * u;
|
|
38672
|
+
const h = r7.h * u;
|
|
38673
|
+
const pos = resolvePlacement(r7, w, h, byId, rooms, u, `room "${r7.id}"`, errors) ?? { x: 0, y: 0 };
|
|
37619
38674
|
const part = { x: pos.x, y: pos.y, w, h };
|
|
37620
38675
|
const room = {
|
|
37621
|
-
id:
|
|
37622
|
-
label:
|
|
38676
|
+
id: r7.id,
|
|
38677
|
+
label: r7.label,
|
|
37623
38678
|
x: part.x,
|
|
37624
38679
|
y: part.y,
|
|
37625
38680
|
w,
|
|
@@ -37627,11 +38682,11 @@ function layoutFloorplan(ast) {
|
|
|
37627
38682
|
parts: [part],
|
|
37628
38683
|
areaM2: 0,
|
|
37629
38684
|
areaText: "",
|
|
37630
|
-
fill:
|
|
37631
|
-
nolabel:
|
|
38685
|
+
fill: r7.fill,
|
|
38686
|
+
nolabel: r7.nolabel ?? false
|
|
37632
38687
|
};
|
|
37633
38688
|
refreshRoomBounds(room, ast.unit);
|
|
37634
|
-
byId.set(
|
|
38689
|
+
byId.set(r7.id, rooms.length);
|
|
37635
38690
|
rooms.push(room);
|
|
37636
38691
|
} else if (stmt.ext) {
|
|
37637
38692
|
const e = stmt.ext;
|
|
@@ -37744,10 +38799,10 @@ function layoutFloorplan(ast) {
|
|
|
37744
38799
|
const spanW = p2.x - p1.x;
|
|
37745
38800
|
const spanH = p2.y - p1.y;
|
|
37746
38801
|
let placed = 0;
|
|
37747
|
-
for (let
|
|
38802
|
+
for (let r7 = 0; r7 < nRows && placed < cap2; r7++) {
|
|
37748
38803
|
for (let col = 0; col < nCols && placed < cap2; col++) {
|
|
37749
38804
|
const cx = p1.x + (nCols === 1 ? spanW / 2 : col * spanW / (nCols - 1));
|
|
37750
|
-
const cy = p1.y + (nRows === 1 ? spanH / 2 :
|
|
38805
|
+
const cy = p1.y + (nRows === 1 ? spanH / 2 : r7 * spanH / (nRows - 1));
|
|
37751
38806
|
place(a.type, idx, cx - iw / 2, cy - ih / 2, iw, ih, a.rotate);
|
|
37752
38807
|
placed++;
|
|
37753
38808
|
}
|
|
@@ -37768,7 +38823,7 @@ function layoutFloorplan(ast) {
|
|
|
37768
38823
|
}
|
|
37769
38824
|
}
|
|
37770
38825
|
const roomOf = /* @__PURE__ */ new Map();
|
|
37771
|
-
for (const
|
|
38826
|
+
for (const r7 of rooms) roomOf.set(r7.id, r7);
|
|
37772
38827
|
const warnItems = /* @__PURE__ */ new Set();
|
|
37773
38828
|
for (const it of items) {
|
|
37774
38829
|
const room = roomOf.get(it.roomId);
|
|
@@ -37827,11 +38882,11 @@ function layoutFloorplan(ast) {
|
|
|
37827
38882
|
let minY = Infinity;
|
|
37828
38883
|
let maxX = -Infinity;
|
|
37829
38884
|
let maxY = -Infinity;
|
|
37830
|
-
for (const
|
|
37831
|
-
minX = Math.min(minX,
|
|
37832
|
-
minY = Math.min(minY,
|
|
37833
|
-
maxX = Math.max(maxX,
|
|
37834
|
-
maxY = Math.max(maxY,
|
|
38885
|
+
for (const r7 of rooms) {
|
|
38886
|
+
minX = Math.min(minX, r7.x);
|
|
38887
|
+
minY = Math.min(minY, r7.y);
|
|
38888
|
+
maxX = Math.max(maxX, r7.x + r7.w);
|
|
38889
|
+
maxY = Math.max(maxY, r7.y + r7.h);
|
|
37835
38890
|
}
|
|
37836
38891
|
if (rooms.length === 0) {
|
|
37837
38892
|
minX = minY = 0;
|
|
@@ -37857,8 +38912,8 @@ function layoutFloorplan(ast) {
|
|
|
37857
38912
|
minor: false
|
|
37858
38913
|
});
|
|
37859
38914
|
const topSegs = [];
|
|
37860
|
-
for (const
|
|
37861
|
-
for (const sg of sideSegments(
|
|
38915
|
+
for (const r7 of rooms) {
|
|
38916
|
+
for (const sg of sideSegments(r7, "north")) {
|
|
37862
38917
|
if (Math.abs(sg.along - minY) < 0.01) topSegs.push({ lo: sg.lo, hi: sg.hi });
|
|
37863
38918
|
}
|
|
37864
38919
|
}
|
|
@@ -37875,8 +38930,8 @@ function layoutFloorplan(ast) {
|
|
|
37875
38930
|
}
|
|
37876
38931
|
}
|
|
37877
38932
|
const leftSegs = [];
|
|
37878
|
-
for (const
|
|
37879
|
-
for (const sg of sideSegments(
|
|
38933
|
+
for (const r7 of rooms) {
|
|
38934
|
+
for (const sg of sideSegments(r7, "west")) {
|
|
37880
38935
|
if (Math.abs(sg.along - minX) < 0.01) leftSegs.push({ lo: sg.lo, hi: sg.hi });
|
|
37881
38936
|
}
|
|
37882
38937
|
}
|
|
@@ -37904,7 +38959,7 @@ function layoutFloorplan(ast) {
|
|
|
37904
38959
|
dims,
|
|
37905
38960
|
bounds: { minX, minY, maxX, maxY },
|
|
37906
38961
|
wallT: FLOORPLAN_CONST.wallT,
|
|
37907
|
-
totalAreaM2: rooms.reduce((s,
|
|
38962
|
+
totalAreaM2: rooms.reduce((s, r7) => s + r7.areaM2, 0),
|
|
37908
38963
|
errors,
|
|
37909
38964
|
warnings,
|
|
37910
38965
|
warnItems: [...warnItems]
|
|
@@ -37956,11 +39011,11 @@ function resolveOpening(op, rooms, byId, u, unit, errors, warnings) {
|
|
|
37956
39011
|
return null;
|
|
37957
39012
|
}
|
|
37958
39013
|
owner = idx;
|
|
37959
|
-
const
|
|
39014
|
+
const r7 = rooms[idx];
|
|
37960
39015
|
const side = op.side;
|
|
37961
|
-
const segs = sideSegments(
|
|
39016
|
+
const segs = sideSegments(r7, side);
|
|
37962
39017
|
if (segs.length === 0) {
|
|
37963
|
-
errors.push(`${op.kind} on "${
|
|
39018
|
+
errors.push(`${op.kind} on "${r7.id}" ${side}: that side has no exterior wall segment`);
|
|
37964
39019
|
return null;
|
|
37965
39020
|
}
|
|
37966
39021
|
const total = segs.reduce((s, sg) => s + (sg.hi - sg.lo), 0);
|
|
@@ -38301,13 +39356,13 @@ function renderFloorplanLayout(lay, config) {
|
|
|
38301
39356
|
const openings = [];
|
|
38302
39357
|
const labels = [];
|
|
38303
39358
|
const dims = [];
|
|
38304
|
-
for (const
|
|
39359
|
+
for (const r7 of lay.rooms) {
|
|
38305
39360
|
floors.push(
|
|
38306
39361
|
group(
|
|
38307
|
-
{ class: "sx-fp-floor", "data-room":
|
|
38308
|
-
|
|
39362
|
+
{ class: "sx-fp-floor", "data-room": r7.id },
|
|
39363
|
+
r7.parts.map(
|
|
38309
39364
|
(p) => rect({
|
|
38310
|
-
fill:
|
|
39365
|
+
fill: r7.fill ?? t.floorFill,
|
|
38311
39366
|
x: X(p.x),
|
|
38312
39367
|
y: Y(p.y),
|
|
38313
39368
|
width: px(p.w),
|
|
@@ -38316,12 +39371,12 @@ function renderFloorplanLayout(lay, config) {
|
|
|
38316
39371
|
)
|
|
38317
39372
|
)
|
|
38318
39373
|
);
|
|
38319
|
-
if (!
|
|
38320
|
-
const main =
|
|
39374
|
+
if (!r7.nolabel) {
|
|
39375
|
+
const main = r7.parts.reduce((a, b) => b.w * b.h > a.w * a.h ? b : a);
|
|
38321
39376
|
const cx = X(main.x + main.w / 2);
|
|
38322
39377
|
const cy = Y(main.y + main.h / 2);
|
|
38323
|
-
labels.push(text({ class: "sx-fp-room-name", x: cx, y: r24(cy - 3), "text-anchor": "middle" },
|
|
38324
|
-
labels.push(text({ class: "sx-fp-room-area", x: cx, y: r24(cy + 13), "text-anchor": "middle" },
|
|
39378
|
+
labels.push(text({ class: "sx-fp-room-name", x: cx, y: r24(cy - 3), "text-anchor": "middle" }, r7.label));
|
|
39379
|
+
labels.push(text({ class: "sx-fp-room-area", x: cx, y: r24(cy + 13), "text-anchor": "middle" }, r7.areaText));
|
|
38325
39380
|
}
|
|
38326
39381
|
}
|
|
38327
39382
|
const warnSet = new Set(lay.warnItems);
|
|
@@ -38351,8 +39406,8 @@ function renderFloorplanLayout(lay, config) {
|
|
|
38351
39406
|
}
|
|
38352
39407
|
});
|
|
38353
39408
|
const tw = lay.wallT;
|
|
38354
|
-
for (const
|
|
38355
|
-
for (const p of
|
|
39409
|
+
for (const r7 of lay.rooms) {
|
|
39410
|
+
for (const p of r7.parts) {
|
|
38356
39411
|
walls.push(rect({ class: "sx-fp-wall", x: r24(X(p.x) - px(tw / 2)), y: r24(Y(p.y) - px(tw / 2)), width: r24(px(p.w + tw)), height: px(tw) }));
|
|
38357
39412
|
walls.push(rect({ class: "sx-fp-wall", x: r24(X(p.x) - px(tw / 2)), y: r24(Y(p.y + p.h) - px(tw / 2)), width: r24(px(p.w + tw)), height: px(tw) }));
|
|
38358
39413
|
walls.push(rect({ class: "sx-fp-wall", x: r24(X(p.x) - px(tw / 2)), y: r24(Y(p.y) - px(tw / 2)), width: px(tw), height: r24(px(p.h + tw)) }));
|
|
@@ -38485,8 +39540,8 @@ var PlaybookParseError = class extends Error {
|
|
|
38485
39540
|
var isStr2 = (t) => t !== void 0 && "str" in t;
|
|
38486
39541
|
var isWord2 = (t, w) => t !== void 0 && "word" in t && (w === void 0 || t.word.toLowerCase() === w);
|
|
38487
39542
|
var tokDisplay = (t) => "word" in t ? t.word : `"${t.str}"`;
|
|
38488
|
-
var
|
|
38489
|
-
function
|
|
39543
|
+
var normalizeQuotes5 = (s) => s.replace(/[“”「」『』]/g, '"').replace(/[‘’]/g, "'");
|
|
39544
|
+
function tokenize9(line2) {
|
|
38490
39545
|
const out = [];
|
|
38491
39546
|
const re = /"([^"]*)"|(\S+)/g;
|
|
38492
39547
|
let m;
|
|
@@ -38496,7 +39551,7 @@ function tokenize8(line2) {
|
|
|
38496
39551
|
}
|
|
38497
39552
|
return out;
|
|
38498
39553
|
}
|
|
38499
|
-
function
|
|
39554
|
+
function parseNum3(t, what, ln) {
|
|
38500
39555
|
if (!isWord2(t)) throw new PlaybookParseError(`expected a number for ${what}`, ln);
|
|
38501
39556
|
const v = Number(t.word);
|
|
38502
39557
|
if (!Number.isFinite(v)) throw new PlaybookParseError(`expected a number for ${what}, got "${t.word}"`, ln);
|
|
@@ -38603,10 +39658,10 @@ function parseHeader4(tok, ast, ln) {
|
|
|
38603
39658
|
function parseField(tok, ast, ln) {
|
|
38604
39659
|
while (tok.length) {
|
|
38605
39660
|
const t = tok.shift();
|
|
38606
|
-
if (isWord2(t, "down")) ast.down =
|
|
38607
|
-
else if (isWord2(t, "distance") || isWord2(t, "togo")) ast.distance =
|
|
38608
|
-
else if (isWord2(t, "los") || isWord2(t, "ball")) ast.losYard =
|
|
38609
|
-
else if (isWord2(t, "goal") || isWord2(t, "togoal")) ast.toGoal =
|
|
39661
|
+
if (isWord2(t, "down")) ast.down = parseNum3(tok.shift(), "down", ln);
|
|
39662
|
+
else if (isWord2(t, "distance") || isWord2(t, "togo")) ast.distance = parseNum3(tok.shift(), "distance", ln);
|
|
39663
|
+
else if (isWord2(t, "los") || isWord2(t, "ball")) ast.losYard = parseNum3(tok.shift(), "los", ln);
|
|
39664
|
+
else if (isWord2(t, "goal") || isWord2(t, "togoal")) ast.toGoal = parseNum3(tok.shift(), "goal", ln);
|
|
38610
39665
|
else if (isWord2(t, "view")) {
|
|
38611
39666
|
const v = parseId2(tok.shift(), "view (full|half)", ln).toLowerCase();
|
|
38612
39667
|
if (v !== "full" && v !== "half" && v !== "auto") throw new PlaybookParseError(`view must be full|half`, ln);
|
|
@@ -38710,7 +39765,7 @@ function parseRouteRun(kind, tok, ast, ln) {
|
|
|
38710
39765
|
const t = tok.shift();
|
|
38711
39766
|
if (isWord2(t) && DIRS.includes(t.word.toLowerCase())) m.dir = t.word.toLowerCase();
|
|
38712
39767
|
else if (isWord2(t) && Number.isFinite(Number(t.word))) m.depth = Number(t.word);
|
|
38713
|
-
else if (isWord2(t, "depth")) m.depth =
|
|
39768
|
+
else if (isWord2(t, "depth")) m.depth = parseNum3(tok.shift(), "depth", ln);
|
|
38714
39769
|
else throw new PlaybookParseError(`${kind}: unexpected token "${tokDisplay(t)}"`, ln);
|
|
38715
39770
|
}
|
|
38716
39771
|
ast.moves.push(m);
|
|
@@ -38815,9 +39870,9 @@ function parsePlaybook(text2) {
|
|
|
38815
39870
|
const lines = text2.split(/\r?\n/);
|
|
38816
39871
|
for (let i = 0; i < lines.length; i++) {
|
|
38817
39872
|
const ln = i + 1;
|
|
38818
|
-
const raw =
|
|
39873
|
+
const raw = normalizeQuotes5(lines[i]).trim();
|
|
38819
39874
|
if (!raw) continue;
|
|
38820
|
-
const all =
|
|
39875
|
+
const all = tokenize9(raw);
|
|
38821
39876
|
const tok = [];
|
|
38822
39877
|
for (const t of all) {
|
|
38823
39878
|
if (isWord2(t) && (t.word.startsWith("#") || t.word.startsWith("//"))) break;
|
|
@@ -39663,12 +40718,12 @@ function resolveGeneric(m, src, byId, players, mod, sport, warnings) {
|
|
|
39663
40718
|
let cur = { x: src.x, y: src.y };
|
|
39664
40719
|
for (const p of m.points) {
|
|
39665
40720
|
if (p.ref) {
|
|
39666
|
-
const
|
|
39667
|
-
if (!
|
|
40721
|
+
const r7 = resolveRef(p.ref, byId, players, mod);
|
|
40722
|
+
if (!r7) {
|
|
39668
40723
|
warnings.push(`${m.kind} ${m.player}: unknown destination "${p.ref}" \u2014 skipped`);
|
|
39669
40724
|
return null;
|
|
39670
40725
|
}
|
|
39671
|
-
cur =
|
|
40726
|
+
cur = r7;
|
|
39672
40727
|
} else if (p.rel) {
|
|
39673
40728
|
cur = { x: cur.x + (p.x ?? 0), y: cur.y + (p.y ?? 0) };
|
|
39674
40729
|
} else {
|
|
@@ -39811,22 +40866,22 @@ function renderMove(mv, ctx) {
|
|
|
39811
40866
|
return group({ class: "sx-pb-move-g", "data-kind": mv.kind, "data-player": mv.player }, parts);
|
|
39812
40867
|
}
|
|
39813
40868
|
function playerSymbol(p, ctx) {
|
|
39814
|
-
const cx = ctx.X(p.x), cy = ctx.Y(p.y),
|
|
40869
|
+
const cx = ctx.X(p.x), cy = ctx.Y(p.y), r7 = 10;
|
|
39815
40870
|
const parts = [];
|
|
39816
40871
|
if (p.side === "defense" || p.pos === "x") {
|
|
39817
|
-
const k =
|
|
40872
|
+
const k = r7 * 0.78;
|
|
39818
40873
|
parts.push(line({ class: "sx-pb-x", x1: r28(cx - k), y1: r28(cy - k), x2: r28(cx + k), y2: r28(cy + k) }));
|
|
39819
40874
|
parts.push(line({ class: "sx-pb-x", x1: r28(cx - k), y1: r28(cy + k), x2: r28(cx + k), y2: r28(cy - k) }));
|
|
39820
40875
|
if (p.label) parts.push(text({ class: "sx-pb-x-text", x: r28(cx + k + 5), y: r28(cy - k + 2), "text-anchor": "middle" }, p.label));
|
|
39821
40876
|
} else if (p.pos === "gk") {
|
|
39822
|
-
const h =
|
|
40877
|
+
const h = r7 * 1.15;
|
|
39823
40878
|
parts.push(polygon({ class: "sx-pb-gk", points: `${r28(cx)},${r28(cy - h)} ${r28(cx + h)},${r28(cy + h * 0.8)} ${r28(cx - h)},${r28(cy + h * 0.8)}` }));
|
|
39824
40879
|
parts.push(text({ class: "sx-pb-o-text", x: r28(cx), y: r28(cy + 6), "text-anchor": "middle" }, p.label));
|
|
39825
40880
|
} else if (p.pos === "c") {
|
|
39826
|
-
parts.push(rect({ class: "sx-pb-o", x: r28(cx -
|
|
40881
|
+
parts.push(rect({ class: "sx-pb-o", x: r28(cx - r7 * 0.82), y: r28(cy - r7 * 0.82), width: r28(r7 * 1.64), height: r28(r7 * 1.64) }));
|
|
39827
40882
|
parts.push(text({ class: "sx-pb-o-text", x: r28(cx), y: r28(cy + 3.6), "text-anchor": "middle" }, p.label));
|
|
39828
40883
|
} else {
|
|
39829
|
-
parts.push(circle({ class: "sx-pb-o", cx: r28(cx), cy: r28(cy), r:
|
|
40884
|
+
parts.push(circle({ class: "sx-pb-o", cx: r28(cx), cy: r28(cy), r: r7 }));
|
|
39830
40885
|
parts.push(text({ class: "sx-pb-o-text", x: r28(cx), y: r28(cy + 3.6), "text-anchor": "middle" }, p.label));
|
|
39831
40886
|
}
|
|
39832
40887
|
return group({ class: "sx-pb-player", "data-side": p.side, "data-id": p.id }, parts);
|
|
@@ -39903,7 +40958,7 @@ function renderPlaybookLayout(lay, config) {
|
|
|
39903
40958
|
const surfaceBase = rect({ class: surfaceCls, x: EDGE, y: r28(fieldTop), width: r28(fieldW), height: r28(fieldH), rx: fieldRx });
|
|
39904
40959
|
const boundary = rect({ class: boundaryCls, x: EDGE, y: r28(fieldTop), width: r28(fieldW), height: r28(fieldH), rx: fieldRx });
|
|
39905
40960
|
const clipId = "sx-pb-clip";
|
|
39906
|
-
const
|
|
40961
|
+
const clip7 = el("clipPath", { id: clipId }, [rect({ x: EDGE, y: r28(fieldTop), width: r28(fieldW), height: r28(fieldH), rx: fieldRx })]);
|
|
39907
40962
|
const field = group({ "clip-path": `url(#${clipId})` }, [mod.drawField(lay, ctx, t)]);
|
|
39908
40963
|
const zones = [];
|
|
39909
40964
|
for (const z of lay.zones) {
|
|
@@ -39931,7 +40986,7 @@ function renderPlaybookLayout(lay, config) {
|
|
|
39931
40986
|
desc(descText),
|
|
39932
40987
|
el("style", {}, buildCss14(t)),
|
|
39933
40988
|
rect({ fill: t.bg, x: 0, y: 0, width: W2, height: H2 }),
|
|
39934
|
-
el("defs", {}, [
|
|
40989
|
+
el("defs", {}, [clip7]),
|
|
39935
40990
|
text({ class: "sx-pb-title", x: r28(W2 / 2), y: TITLE.y, "text-anchor": "middle" }, lay.title),
|
|
39936
40991
|
...annoParts,
|
|
39937
40992
|
surround,
|
|
@@ -40033,6 +41088,7 @@ var plugins = [
|
|
|
40033
41088
|
bowtie2,
|
|
40034
41089
|
eventtree,
|
|
40035
41090
|
fmea,
|
|
41091
|
+
rbd,
|
|
40036
41092
|
causalloop,
|
|
40037
41093
|
markov,
|
|
40038
41094
|
gitgraph,
|
|
@@ -40052,7 +41108,7 @@ function detectPlugin(text2, config) {
|
|
|
40052
41108
|
if (plugin.detect(text2)) return plugin;
|
|
40053
41109
|
}
|
|
40054
41110
|
throw new Error(
|
|
40055
|
-
"Cannot detect diagram type. Start your text with 'genogram', 'ecomap', 'pedigree', 'phylo', 'sociogram', 'timing', 'logic', 'circuit', 'blockdiagram', 'ladder', 'sld', 'entity-structure', 'fishbone', 'venn', 'flowchart', 'mindmap', 'matrix', 'orgchart', 'state', 'pid', 'erd', 'breadboard', 'bpmn', 'fbd', 'sfc', 'prisma', 'usecase', 'pert', 'sequence', 'petri', 'network', 'umlclass', 'faulttree', 'bowtie', 'floorplan', or 'playbook'."
|
|
41111
|
+
"Cannot detect diagram type. Start your text with 'genogram', 'ecomap', 'pedigree', 'phylo', 'sociogram', 'timing', 'logic', 'circuit', 'blockdiagram', 'ladder', 'sld', 'entity-structure', 'fishbone', 'venn', 'flowchart', 'mindmap', 'matrix', 'orgchart', 'state', 'pid', 'erd', 'breadboard', 'bpmn', 'fbd', 'sfc', 'prisma', 'usecase', 'pert', 'sequence', 'petri', 'network', 'umlclass', 'faulttree', 'bowtie', 'rbd', 'floorplan', or 'playbook'."
|
|
40056
41112
|
);
|
|
40057
41113
|
}
|
|
40058
41114
|
function stripCodeFences(text2) {
|
|
@@ -40189,6 +41245,6 @@ function renderWithPlugin(prepared, plugin, config) {
|
|
|
40189
41245
|
return plugin.render(prepared, renderConfig);
|
|
40190
41246
|
}
|
|
40191
41247
|
|
|
40192
|
-
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, render, renderEquip, renderPreview, renderResult, sequence, state, threatmodel, timeline, umlclass, usecase, welding };
|
|
40193
|
-
//# sourceMappingURL=chunk-
|
|
40194
|
-
//# sourceMappingURL=chunk-
|
|
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-4W75FGWO.js.map
|
|
41250
|
+
//# sourceMappingURL=chunk-4W75FGWO.js.map
|