schematex 0.1.1 → 0.2.2
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 +130 -15
- package/dist/api-bQZ98gkJ.d.cts +22 -0
- package/dist/api-bQZ98gkJ.d.ts +22 -0
- package/dist/browser.cjs +46 -0
- package/dist/browser.cjs.map +1 -0
- package/dist/browser.d.cts +27 -0
- package/dist/browser.d.ts +27 -0
- package/dist/browser.js +40 -0
- package/dist/browser.js.map +1 -0
- package/dist/{chunk-IX554O5K.js → chunk-2VNMKOUO.js} +90 -6
- package/dist/chunk-2VNMKOUO.js.map +1 -0
- package/dist/{chunk-LMFSHK45.js → chunk-4KYW63IK.js} +4 -3
- package/dist/{chunk-LMFSHK45.js.map → chunk-4KYW63IK.js.map} +1 -1
- package/dist/{chunk-FGPTCDUT.cjs → chunk-4S2WILLW.cjs} +5 -4
- package/dist/chunk-4S2WILLW.cjs.map +1 -0
- package/dist/{chunk-4G7ZIBHN.js → chunk-5SH5NUDW.js} +3 -2
- package/dist/{chunk-4G7ZIBHN.js.map → chunk-5SH5NUDW.js.map} +1 -1
- package/dist/{chunk-PDPHRZZT.js → chunk-5UV5VQ7J.js} +4 -3
- package/dist/chunk-5UV5VQ7J.js.map +1 -0
- package/dist/{chunk-VFQCTXOX.js → chunk-5YYAYW67.js} +4 -3
- package/dist/chunk-5YYAYW67.js.map +1 -0
- package/dist/{chunk-HGHWCB6K.js → chunk-6YMQSTFF.js} +4 -3
- package/dist/chunk-6YMQSTFF.js.map +1 -0
- package/dist/chunk-7HKXU7J2.cjs +4838 -0
- package/dist/chunk-7HKXU7J2.cjs.map +1 -0
- package/dist/{chunk-UHLYS3W5.cjs → chunk-7IRT3LOY.cjs} +5 -4
- package/dist/{chunk-UHLYS3W5.cjs.map → chunk-7IRT3LOY.cjs.map} +1 -1
- package/dist/{chunk-U5GGE6PJ.js → chunk-CJ2A3UEQ.js} +4 -3
- package/dist/chunk-CJ2A3UEQ.js.map +1 -0
- package/dist/chunk-CXHPP5BL.cjs +1880 -0
- package/dist/chunk-CXHPP5BL.cjs.map +1 -0
- package/dist/{chunk-N7KOXOMX.cjs → chunk-D7EHZFK4.cjs} +90 -5
- package/dist/chunk-D7EHZFK4.cjs.map +1 -0
- package/dist/{chunk-FDLZEKEB.js → chunk-GEPBET4L.js} +3 -2
- package/dist/chunk-GEPBET4L.js.map +1 -0
- package/dist/{chunk-4DBRNOPA.cjs → chunk-ISACNVFE.cjs} +5 -4
- package/dist/{chunk-4DBRNOPA.cjs.map → chunk-ISACNVFE.cjs.map} +1 -1
- package/dist/{chunk-ROFLJ74T.js → chunk-JDTB7IKL.js} +4 -3
- package/dist/chunk-JDTB7IKL.js.map +1 -0
- package/dist/{chunk-47ZC6EMJ.js → chunk-LCR3KOJV.js} +4 -3
- package/dist/{chunk-47ZC6EMJ.js.map → chunk-LCR3KOJV.js.map} +1 -1
- package/dist/{chunk-7FZSPKX3.cjs → chunk-LKOBOVNL.cjs} +6 -5
- package/dist/chunk-LKOBOVNL.cjs.map +1 -0
- package/dist/{chunk-34X3ZJ6E.cjs → chunk-LXNFVHDT.cjs} +3 -2
- package/dist/{chunk-34X3ZJ6E.cjs.map → chunk-LXNFVHDT.cjs.map} +1 -1
- package/dist/{chunk-XX4BKS7Y.js → chunk-M5B2UUNW.js} +4 -3
- package/dist/chunk-M5B2UUNW.js.map +1 -0
- package/dist/{chunk-XXU36667.js → chunk-PGALHQFF.js} +4 -3
- package/dist/chunk-PGALHQFF.js.map +1 -0
- package/dist/{chunk-ZX7QKZK2.cjs → chunk-QR7VTCI4.cjs} +28 -27
- package/dist/chunk-QR7VTCI4.cjs.map +1 -0
- package/dist/{chunk-3FTUWAXK.cjs → chunk-QSQX77S2.cjs} +5 -4
- package/dist/chunk-QSQX77S2.cjs.map +1 -0
- package/dist/chunk-UUPYTUGR.js +4833 -0
- package/dist/chunk-UUPYTUGR.js.map +1 -0
- package/dist/{chunk-BE5HNDA5.cjs → chunk-WYFXOXVK.cjs} +5 -4
- package/dist/{chunk-BE5HNDA5.cjs.map → chunk-WYFXOXVK.cjs.map} +1 -1
- package/dist/{chunk-5C7DPDHQ.js → chunk-X2BQKXMA.js} +28 -27
- package/dist/chunk-X2BQKXMA.js.map +1 -0
- package/dist/{chunk-XQ52ICHU.cjs → chunk-X7RPFTTR.cjs} +14 -13
- package/dist/chunk-X7RPFTTR.cjs.map +1 -0
- package/dist/{chunk-S6BK5DB6.cjs → chunk-XHZ7GXP2.cjs} +13 -12
- package/dist/chunk-XHZ7GXP2.cjs.map +1 -0
- package/dist/{chunk-DS47NTWZ.cjs → chunk-XVCAOGFL.cjs} +11 -10
- package/dist/chunk-XVCAOGFL.cjs.map +1 -0
- package/dist/{chunk-D4JTSPOL.js → chunk-YN467EEQ.js} +4 -3
- package/dist/chunk-YN467EEQ.js.map +1 -0
- package/dist/{chunk-CZRM7LT7.js → chunk-YQANC7HQ.js} +4 -3
- package/dist/chunk-YQANC7HQ.js.map +1 -0
- package/dist/{chunk-NYCIK4SU.cjs → chunk-YXIIWLLB.cjs} +13 -12
- package/dist/chunk-YXIIWLLB.cjs.map +1 -0
- package/dist/chunk-Z3WOHHG3.js +1873 -0
- package/dist/chunk-Z3WOHHG3.js.map +1 -0
- package/dist/{chunk-2UKC6ZCY.cjs → chunk-Z63XPA2V.cjs} +12 -11
- package/dist/chunk-Z63XPA2V.cjs.map +1 -0
- package/dist/{chunk-V6WO7RK7.cjs → chunk-ZNOD4VZT.cjs} +5 -4
- package/dist/chunk-ZNOD4VZT.cjs.map +1 -0
- package/dist/{chunk-3J7TFUOC.js → chunk-ZNZIL244.js} +4 -3
- package/dist/{chunk-3J7TFUOC.js.map → chunk-ZNZIL244.js.map} +1 -1
- package/dist/{chunk-2MQWZ2XY.cjs → chunk-ZO77FHBF.cjs} +3 -2
- package/dist/chunk-ZO77FHBF.cjs.map +1 -0
- package/dist/diagrams/blockdiagram/index.cjs +5 -5
- package/dist/diagrams/blockdiagram/index.d.cts +1 -1
- package/dist/diagrams/blockdiagram/index.d.ts +1 -1
- package/dist/diagrams/blockdiagram/index.js +1 -1
- package/dist/diagrams/circuit/index.cjs +8 -8
- package/dist/diagrams/circuit/index.d.cts +1 -1
- package/dist/diagrams/circuit/index.d.ts +1 -1
- package/dist/diagrams/circuit/index.js +2 -2
- package/dist/diagrams/ecomap/index.cjs +7 -7
- package/dist/diagrams/ecomap/index.d.cts +1 -1
- package/dist/diagrams/ecomap/index.d.ts +1 -1
- package/dist/diagrams/ecomap/index.js +2 -2
- package/dist/diagrams/entity/index.cjs +6 -6
- package/dist/diagrams/entity/index.d.cts +1 -1
- package/dist/diagrams/entity/index.d.ts +1 -1
- package/dist/diagrams/entity/index.js +2 -2
- package/dist/diagrams/fishbone/index.cjs +8 -8
- package/dist/diagrams/fishbone/index.d.cts +1 -1
- package/dist/diagrams/fishbone/index.d.ts +1 -1
- package/dist/diagrams/fishbone/index.js +2 -2
- package/dist/diagrams/flowchart/index.cjs +8 -8
- package/dist/diagrams/flowchart/index.d.cts +2 -2
- package/dist/diagrams/flowchart/index.d.ts +2 -2
- package/dist/diagrams/flowchart/index.js +2 -2
- package/dist/diagrams/genogram/index.cjs +9 -9
- package/dist/diagrams/genogram/index.d.cts +1 -1
- package/dist/diagrams/genogram/index.d.ts +1 -1
- package/dist/diagrams/genogram/index.js +2 -2
- package/dist/diagrams/ladder/index.cjs +6 -6
- package/dist/diagrams/ladder/index.d.cts +1 -1
- package/dist/diagrams/ladder/index.d.ts +1 -1
- package/dist/diagrams/ladder/index.js +2 -2
- package/dist/diagrams/logic/index.cjs +6 -6
- package/dist/diagrams/logic/index.d.cts +1 -1
- package/dist/diagrams/logic/index.d.ts +1 -1
- package/dist/diagrams/logic/index.js +2 -2
- package/dist/diagrams/orgchart/index.cjs +7 -7
- package/dist/diagrams/orgchart/index.d.cts +1 -1
- package/dist/diagrams/orgchart/index.d.ts +1 -1
- package/dist/diagrams/orgchart/index.js +2 -2
- package/dist/diagrams/pedigree/index.cjs +7 -7
- package/dist/diagrams/pedigree/index.d.cts +1 -1
- package/dist/diagrams/pedigree/index.d.ts +1 -1
- package/dist/diagrams/pedigree/index.js +2 -2
- package/dist/diagrams/phylo/index.cjs +7 -7
- package/dist/diagrams/phylo/index.d.cts +1 -1
- package/dist/diagrams/phylo/index.d.ts +1 -1
- package/dist/diagrams/phylo/index.js +2 -2
- package/dist/diagrams/sld/index.cjs +6 -6
- package/dist/diagrams/sld/index.d.cts +1 -1
- package/dist/diagrams/sld/index.d.ts +1 -1
- package/dist/diagrams/sld/index.js +2 -2
- package/dist/diagrams/sociogram/index.cjs +6 -6
- package/dist/diagrams/sociogram/index.d.cts +1 -1
- package/dist/diagrams/sociogram/index.d.ts +1 -1
- package/dist/diagrams/sociogram/index.js +2 -2
- package/dist/diagrams/timing/index.cjs +4 -4
- package/dist/diagrams/timing/index.d.cts +1 -1
- package/dist/diagrams/timing/index.d.ts +1 -1
- package/dist/diagrams/timing/index.js +1 -1
- package/dist/diagrams/venn/index.cjs +9 -9
- package/dist/diagrams/venn/index.d.cts +1 -1
- package/dist/diagrams/venn/index.d.ts +1 -1
- package/dist/diagrams/venn/index.js +2 -2
- package/dist/export.cjs +87 -0
- package/dist/export.cjs.map +1 -0
- package/dist/export.d.cts +38 -0
- package/dist/export.d.ts +38 -0
- package/dist/export.js +83 -0
- package/dist/export.js.map +1 -0
- package/dist/{index-BXefHVce.d.cts → index-SSGpCggE.d.cts} +52 -3
- package/dist/{index-BSlza1YY.d.ts → index-ga04CTBI.d.ts} +52 -3
- package/dist/index.cjs +65 -1948
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -12
- package/dist/index.d.ts +7 -12
- package/dist/index.js +19 -1942
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +56 -0
- package/dist/react.cjs.map +1 -0
- package/dist/react.d.cts +24 -0
- package/dist/react.d.ts +24 -0
- package/dist/react.js +54 -0
- package/dist/react.js.map +1 -0
- package/dist/{types-DqfcYkcY.d.ts → types-BcPhMdHd.d.cts} +6 -2
- package/dist/{types-DqfcYkcY.d.cts → types-BcPhMdHd.d.ts} +6 -2
- package/package.json +34 -4
- package/dist/chunk-2MQWZ2XY.cjs.map +0 -1
- package/dist/chunk-2UKC6ZCY.cjs.map +0 -1
- package/dist/chunk-3FTUWAXK.cjs.map +0 -1
- package/dist/chunk-5C7DPDHQ.js.map +0 -1
- package/dist/chunk-7FZSPKX3.cjs.map +0 -1
- package/dist/chunk-ADOXGKAK.js +0 -1251
- package/dist/chunk-ADOXGKAK.js.map +0 -1
- package/dist/chunk-CZRM7LT7.js.map +0 -1
- package/dist/chunk-D4JTSPOL.js.map +0 -1
- package/dist/chunk-DS47NTWZ.cjs.map +0 -1
- package/dist/chunk-FDLZEKEB.js.map +0 -1
- package/dist/chunk-FGPTCDUT.cjs.map +0 -1
- package/dist/chunk-HGHWCB6K.js.map +0 -1
- package/dist/chunk-IX554O5K.js.map +0 -1
- package/dist/chunk-MDICUK6F.cjs +0 -1258
- package/dist/chunk-MDICUK6F.cjs.map +0 -1
- package/dist/chunk-N7KOXOMX.cjs.map +0 -1
- package/dist/chunk-NYCIK4SU.cjs.map +0 -1
- package/dist/chunk-PDPHRZZT.js.map +0 -1
- package/dist/chunk-ROFLJ74T.js.map +0 -1
- package/dist/chunk-S6BK5DB6.cjs.map +0 -1
- package/dist/chunk-U5GGE6PJ.js.map +0 -1
- package/dist/chunk-V6WO7RK7.cjs.map +0 -1
- package/dist/chunk-VFQCTXOX.js.map +0 -1
- package/dist/chunk-XQ52ICHU.cjs.map +0 -1
- package/dist/chunk-XX4BKS7Y.js.map +0 -1
- package/dist/chunk-XXU36667.js.map +0 -1
- package/dist/chunk-ZX7QKZK2.cjs.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1,2033 +1,150 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
5
|
-
var
|
|
6
|
-
var
|
|
7
|
-
var
|
|
8
|
-
var
|
|
9
|
-
var
|
|
10
|
-
var
|
|
11
|
-
var
|
|
12
|
-
var
|
|
13
|
-
var
|
|
14
|
-
var
|
|
15
|
-
var
|
|
16
|
-
var
|
|
17
|
-
var
|
|
18
|
-
var
|
|
19
|
-
var
|
|
20
|
-
var
|
|
3
|
+
var chunk7HKXU7J2_cjs = require('./chunk-7HKXU7J2.cjs');
|
|
4
|
+
var chunk7IRT3LOY_cjs = require('./chunk-7IRT3LOY.cjs');
|
|
5
|
+
var chunk4S2WILLW_cjs = require('./chunk-4S2WILLW.cjs');
|
|
6
|
+
var chunkLXNFVHDT_cjs = require('./chunk-LXNFVHDT.cjs');
|
|
7
|
+
var chunkISACNVFE_cjs = require('./chunk-ISACNVFE.cjs');
|
|
8
|
+
var chunkQR7VTCI4_cjs = require('./chunk-QR7VTCI4.cjs');
|
|
9
|
+
var chunkZNOD4VZT_cjs = require('./chunk-ZNOD4VZT.cjs');
|
|
10
|
+
var chunkLKOBOVNL_cjs = require('./chunk-LKOBOVNL.cjs');
|
|
11
|
+
var chunkQSQX77S2_cjs = require('./chunk-QSQX77S2.cjs');
|
|
12
|
+
var chunkCXHPP5BL_cjs = require('./chunk-CXHPP5BL.cjs');
|
|
13
|
+
var chunkZ63XPA2V_cjs = require('./chunk-Z63XPA2V.cjs');
|
|
14
|
+
var chunkXHZ7GXP2_cjs = require('./chunk-XHZ7GXP2.cjs');
|
|
15
|
+
var chunkXVCAOGFL_cjs = require('./chunk-XVCAOGFL.cjs');
|
|
16
|
+
var chunkX7RPFTTR_cjs = require('./chunk-X7RPFTTR.cjs');
|
|
17
|
+
var chunkYXIIWLLB_cjs = require('./chunk-YXIIWLLB.cjs');
|
|
18
|
+
var chunkZO77FHBF_cjs = require('./chunk-ZO77FHBF.cjs');
|
|
19
|
+
var chunkWYFXOXVK_cjs = require('./chunk-WYFXOXVK.cjs');
|
|
20
|
+
var chunkD7EHZFK4_cjs = require('./chunk-D7EHZFK4.cjs');
|
|
21
|
+
require('./chunk-HDKDQAEQ.cjs');
|
|
21
22
|
|
|
22
|
-
// src/diagrams/mindmap/parser.ts
|
|
23
|
-
var VALID_STYLES = ["map", "logic-right"];
|
|
24
|
-
function parseDirective(line2, out) {
|
|
25
|
-
const body = line2.replace(/^%%\s*/, "").trim();
|
|
26
|
-
const idx = body.indexOf(":");
|
|
27
|
-
if (idx < 0) return;
|
|
28
|
-
const key = body.slice(0, idx).trim().toLowerCase();
|
|
29
|
-
const val = body.slice(idx + 1).trim();
|
|
30
|
-
if (key === "style" && VALID_STYLES.includes(val)) {
|
|
31
|
-
out.style = val;
|
|
32
|
-
} else if (key === "theme") {
|
|
33
|
-
out.themeOverride = val;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
function parseMindmap(text2) {
|
|
37
|
-
const lines = text2.split(/\r?\n/);
|
|
38
|
-
if (lines[0]?.trim().toLowerCase() === "mindmap") lines.shift();
|
|
39
|
-
const directives = { style: "map" };
|
|
40
|
-
let root = null;
|
|
41
|
-
let idCounter = 0;
|
|
42
|
-
const nextId = () => `n${idCounter++}`;
|
|
43
|
-
const stack = [];
|
|
44
|
-
let lastHeadingDepth = 0;
|
|
45
|
-
const attach = (node, depth) => {
|
|
46
|
-
while (stack.length && stack[stack.length - 1].depth >= depth) stack.pop();
|
|
47
|
-
const parent = stack[stack.length - 1]?.node;
|
|
48
|
-
if (!parent) throw new Error("Mindmap: orphan node \u2014 expected root # heading first");
|
|
49
|
-
node.depth = parent.depth + 1;
|
|
50
|
-
parent.children.push(node);
|
|
51
|
-
stack.push({ node, depth });
|
|
52
|
-
};
|
|
53
|
-
for (const raw of lines) {
|
|
54
|
-
const line2 = raw.replace(/\s+$/, "");
|
|
55
|
-
const trimmed = line2.trim();
|
|
56
|
-
if (!trimmed) continue;
|
|
57
|
-
if (trimmed.startsWith("%%")) {
|
|
58
|
-
parseDirective(trimmed, directives);
|
|
59
|
-
continue;
|
|
60
|
-
}
|
|
61
|
-
const heading = line2.match(/^\s*(#{1,6})\s+(.+)$/);
|
|
62
|
-
if (heading) {
|
|
63
|
-
const depth = heading[1].length - 1;
|
|
64
|
-
const label = heading[2].trim();
|
|
65
|
-
const node = { id: nextId(), label, depth, children: [] };
|
|
66
|
-
if (depth === 0) {
|
|
67
|
-
if (root) throw new Error("Mindmap: multiple `#` center nodes not allowed");
|
|
68
|
-
root = node;
|
|
69
|
-
stack.length = 0;
|
|
70
|
-
stack.push({ node, depth: 0 });
|
|
71
|
-
} else {
|
|
72
|
-
attach(node, depth);
|
|
73
|
-
}
|
|
74
|
-
lastHeadingDepth = depth;
|
|
75
|
-
continue;
|
|
76
|
-
}
|
|
77
|
-
const bullet = line2.match(/^(\s*)[-*+]\s+(.+)$/);
|
|
78
|
-
if (bullet) {
|
|
79
|
-
const indent = bullet[1].length;
|
|
80
|
-
const depth = lastHeadingDepth + 1 + Math.floor(indent / 2);
|
|
81
|
-
const label = bullet[2].trim();
|
|
82
|
-
const node = { id: nextId(), label, depth, children: [] };
|
|
83
|
-
attach(node, depth);
|
|
84
|
-
continue;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
if (!root) throw new Error("Mindmap: missing central topic \u2014 start with `# Title`");
|
|
88
|
-
const ast = {
|
|
89
|
-
type: "mindmap",
|
|
90
|
-
style: directives.style,
|
|
91
|
-
root
|
|
92
|
-
};
|
|
93
|
-
if (directives.themeOverride) ast.themeOverride = directives.themeOverride;
|
|
94
|
-
return ast;
|
|
95
|
-
}
|
|
96
23
|
|
|
97
|
-
// src/diagrams/mindmap/layout.ts
|
|
98
|
-
var PADDING = 40;
|
|
99
|
-
var SIBLING_GAP = 20;
|
|
100
|
-
var MAIN_GAP = 44;
|
|
101
|
-
var ROOT_CAPSULE_PAD_X = 10;
|
|
102
|
-
var ROOT_CAPSULE_PAD_Y = 10;
|
|
103
|
-
function bezierGapFor(childDepth) {
|
|
104
|
-
if (childDepth <= 1) return 90;
|
|
105
|
-
if (childDepth === 2) return 60;
|
|
106
|
-
return 45;
|
|
107
|
-
}
|
|
108
|
-
var FONT_CENTRAL = 20;
|
|
109
|
-
var FONT_MAIN = 15;
|
|
110
|
-
var FONT_SUB = 13;
|
|
111
|
-
function fontSizeOf(depth) {
|
|
112
|
-
if (depth === 0) return FONT_CENTRAL;
|
|
113
|
-
if (depth === 1) return FONT_MAIN;
|
|
114
|
-
return FONT_SUB;
|
|
115
|
-
}
|
|
116
|
-
function estimateLabelWidth(label, depth) {
|
|
117
|
-
return Math.max(32, label.length * fontSizeOf(depth) * 0.58);
|
|
118
|
-
}
|
|
119
|
-
function rowHeightOf(depth) {
|
|
120
|
-
return fontSizeOf(depth) + 14;
|
|
121
|
-
}
|
|
122
|
-
function computeColumns(subtreeRoots, firstColStartX) {
|
|
123
|
-
const maxLW = [];
|
|
124
|
-
const walk = (n) => {
|
|
125
|
-
const lw = estimateLabelWidth(n.label, n.depth);
|
|
126
|
-
if (maxLW[n.depth] === void 0 || lw > maxLW[n.depth]) maxLW[n.depth] = lw;
|
|
127
|
-
for (const c of n.children) walk(c);
|
|
128
|
-
};
|
|
129
|
-
for (const r of subtreeRoots) walk(r);
|
|
130
|
-
const center = [];
|
|
131
|
-
if (subtreeRoots.length === 0) return { center };
|
|
132
|
-
const rootDepth = subtreeRoots[0].depth;
|
|
133
|
-
let slotLeft = firstColStartX;
|
|
134
|
-
center[rootDepth] = slotLeft + maxLW[rootDepth] / 2;
|
|
135
|
-
for (let d = rootDepth + 1; d < maxLW.length; d++) {
|
|
136
|
-
slotLeft = slotLeft + maxLW[d - 1] + bezierGapFor(d);
|
|
137
|
-
center[d] = slotLeft + maxLW[d] / 2;
|
|
138
|
-
}
|
|
139
|
-
return { center };
|
|
140
|
-
}
|
|
141
|
-
function tidyRight(node, yTop, branchIdx, columns, out) {
|
|
142
|
-
const rowH = rowHeightOf(node.depth);
|
|
143
|
-
const lw = estimateLabelWidth(node.label, node.depth);
|
|
144
|
-
const x = columns.center[node.depth];
|
|
145
|
-
if (node.children.length === 0) {
|
|
146
|
-
const ln2 = {
|
|
147
|
-
node,
|
|
148
|
-
x,
|
|
149
|
-
y: yTop + rowH / 2,
|
|
150
|
-
side: "right",
|
|
151
|
-
branchIndex: branchIdx,
|
|
152
|
-
labelWidth: lw,
|
|
153
|
-
labelHeight: rowH
|
|
154
|
-
};
|
|
155
|
-
out.push(ln2);
|
|
156
|
-
return { layoutNode: ln2, height: rowH };
|
|
157
|
-
}
|
|
158
|
-
let cursor = yTop;
|
|
159
|
-
const childLayouts = [];
|
|
160
|
-
for (let i = 0; i < node.children.length; i++) {
|
|
161
|
-
if (i > 0) cursor += SIBLING_GAP;
|
|
162
|
-
const { layoutNode: cln, height } = tidyRight(
|
|
163
|
-
node.children[i],
|
|
164
|
-
cursor,
|
|
165
|
-
branchIdx,
|
|
166
|
-
columns,
|
|
167
|
-
out
|
|
168
|
-
);
|
|
169
|
-
childLayouts.push(cln);
|
|
170
|
-
cursor += height;
|
|
171
|
-
}
|
|
172
|
-
const totalH = Math.max(rowH, cursor - yTop);
|
|
173
|
-
const firstY = childLayouts[0].y;
|
|
174
|
-
const lastY = childLayouts[childLayouts.length - 1].y;
|
|
175
|
-
const parentY = (firstY + lastY) / 2;
|
|
176
|
-
const ln = {
|
|
177
|
-
node,
|
|
178
|
-
x,
|
|
179
|
-
y: parentY,
|
|
180
|
-
side: "right",
|
|
181
|
-
branchIndex: branchIdx,
|
|
182
|
-
labelWidth: lw,
|
|
183
|
-
labelHeight: rowH
|
|
184
|
-
};
|
|
185
|
-
out.push(ln);
|
|
186
|
-
return { layoutNode: ln, height: totalH };
|
|
187
|
-
}
|
|
188
|
-
function labelEdgeX(n, outward) {
|
|
189
|
-
if (n.side === "center") return n.x;
|
|
190
|
-
const dir = n.side === "left" ? -1 : 1;
|
|
191
|
-
return n.x + (outward ? dir : -dir) * n.labelWidth / 2;
|
|
192
|
-
}
|
|
193
|
-
function bezierH(x1, y1, x2, y2) {
|
|
194
|
-
const k = (x2 - x1) * 0.55;
|
|
195
|
-
return `M ${x1.toFixed(1)} ${y1.toFixed(1)} C ${(x1 + k).toFixed(1)} ${y1.toFixed(1)}, ${(x2 - k).toFixed(1)} ${y2.toFixed(1)}, ${x2.toFixed(1)} ${y2.toFixed(1)}`;
|
|
196
|
-
}
|
|
197
|
-
function edgeWidthFor(depth) {
|
|
198
|
-
return depth <= 1 ? 2.2 : 1.4;
|
|
199
|
-
}
|
|
200
|
-
function normalize(nodes) {
|
|
201
|
-
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
202
|
-
for (const n of nodes) {
|
|
203
|
-
const lw = n.labelWidth;
|
|
204
|
-
const lh = n.labelHeight;
|
|
205
|
-
const leftX = n.x - lw / 2;
|
|
206
|
-
const rightX = n.x + lw / 2;
|
|
207
|
-
minX = Math.min(minX, leftX);
|
|
208
|
-
maxX = Math.max(maxX, rightX);
|
|
209
|
-
minY = Math.min(minY, n.y - lh);
|
|
210
|
-
maxY = Math.max(maxY, n.y + lh);
|
|
211
|
-
}
|
|
212
|
-
const dx = PADDING - minX;
|
|
213
|
-
const dy = PADDING - minY;
|
|
214
|
-
for (const n of nodes) {
|
|
215
|
-
n.x += dx;
|
|
216
|
-
n.y += dy;
|
|
217
|
-
}
|
|
218
|
-
return { width: maxX - minX + PADDING * 2, height: maxY - minY + PADDING * 2 };
|
|
219
|
-
}
|
|
220
|
-
function buildEdges(root, byId) {
|
|
221
|
-
const edges = [];
|
|
222
|
-
const walk = (parent) => {
|
|
223
|
-
const pln = byId.get(parent.id);
|
|
224
|
-
for (const c of parent.children) {
|
|
225
|
-
const cln = byId.get(c.id);
|
|
226
|
-
let fromX;
|
|
227
|
-
if (pln.side === "center") {
|
|
228
|
-
const halfW = pln.labelWidth / 2;
|
|
229
|
-
fromX = cln.side === "left" ? pln.x - halfW : pln.x + halfW;
|
|
230
|
-
} else {
|
|
231
|
-
fromX = labelEdgeX(pln, true);
|
|
232
|
-
}
|
|
233
|
-
const toX = labelEdgeX(cln, false);
|
|
234
|
-
edges.push({
|
|
235
|
-
from: parent.id,
|
|
236
|
-
to: c.id,
|
|
237
|
-
path: bezierH(fromX, pln.y, toX, cln.y),
|
|
238
|
-
color: "",
|
|
239
|
-
width: edgeWidthFor(c.depth)
|
|
240
|
-
});
|
|
241
|
-
walk(c);
|
|
242
|
-
}
|
|
243
|
-
};
|
|
244
|
-
walk(root);
|
|
245
|
-
return edges;
|
|
246
|
-
}
|
|
247
|
-
function layoutMap(ast) {
|
|
248
|
-
const root = ast.root;
|
|
249
|
-
const mains = root.children;
|
|
250
|
-
const rightCount = Math.ceil(mains.length / 2);
|
|
251
|
-
const rightMains = mains.slice(0, rightCount);
|
|
252
|
-
const leftMains = mains.slice(rightCount);
|
|
253
|
-
const nodes = [];
|
|
254
|
-
const rootLabelW = estimateLabelWidth(root.label, 0);
|
|
255
|
-
const rootCapsuleW = rootLabelW + ROOT_CAPSULE_PAD_X * 2;
|
|
256
|
-
const rootCapsuleH = rowHeightOf(0) + ROOT_CAPSULE_PAD_Y;
|
|
257
|
-
const firstColLeft = rootCapsuleW / 2 + bezierGapFor(1);
|
|
258
|
-
const rightCols = computeColumns(rightMains, firstColLeft);
|
|
259
|
-
let rightCursor = 0;
|
|
260
|
-
for (let i = 0; i < rightMains.length; i++) {
|
|
261
|
-
if (i > 0) rightCursor += MAIN_GAP;
|
|
262
|
-
const { height: height2 } = tidyRight(rightMains[i], rightCursor, i, rightCols, nodes);
|
|
263
|
-
rightCursor += height2;
|
|
264
|
-
}
|
|
265
|
-
const rightHeight = rightCursor;
|
|
266
|
-
const leftCols = computeColumns(leftMains, firstColLeft);
|
|
267
|
-
const leftStart = nodes.length;
|
|
268
|
-
let leftCursor = 0;
|
|
269
|
-
for (let i = 0; i < leftMains.length; i++) {
|
|
270
|
-
if (i > 0) leftCursor += MAIN_GAP;
|
|
271
|
-
const { height: height2 } = tidyRight(leftMains[i], leftCursor, rightCount + i, leftCols, nodes);
|
|
272
|
-
leftCursor += height2;
|
|
273
|
-
}
|
|
274
|
-
const leftHeight = leftCursor;
|
|
275
|
-
for (let k = leftStart; k < nodes.length; k++) {
|
|
276
|
-
nodes[k].x = -nodes[k].x;
|
|
277
|
-
nodes[k].side = "left";
|
|
278
|
-
}
|
|
279
|
-
const rootY = Math.max(rightHeight, leftHeight) / 2;
|
|
280
|
-
const rootNode = {
|
|
281
|
-
node: root,
|
|
282
|
-
x: 0,
|
|
283
|
-
y: rootY,
|
|
284
|
-
side: "center",
|
|
285
|
-
branchIndex: -1,
|
|
286
|
-
labelWidth: rootCapsuleW,
|
|
287
|
-
labelHeight: rootCapsuleH
|
|
288
|
-
};
|
|
289
|
-
nodes.push(rootNode);
|
|
290
|
-
const { width, height } = normalize(nodes);
|
|
291
|
-
const byId = new Map(nodes.map((n) => [n.node.id, n]));
|
|
292
|
-
const edges = buildEdges(root, byId);
|
|
293
|
-
return { width, height, style: "map", nodes, edges, title: ast.title };
|
|
294
|
-
}
|
|
295
|
-
function layoutLogicRight(ast) {
|
|
296
|
-
const root = ast.root;
|
|
297
|
-
const nodes = [];
|
|
298
|
-
const rootLabelW = estimateLabelWidth(root.label, 0);
|
|
299
|
-
const rootCapsuleW = rootLabelW + ROOT_CAPSULE_PAD_X * 2;
|
|
300
|
-
const rootCapsuleH = rowHeightOf(0) + ROOT_CAPSULE_PAD_Y;
|
|
301
|
-
const firstColLeft = rootCapsuleW / 2 + bezierGapFor(1);
|
|
302
|
-
const cols = computeColumns(root.children, firstColLeft);
|
|
303
|
-
let cursor = 0;
|
|
304
|
-
for (let i = 0; i < root.children.length; i++) {
|
|
305
|
-
if (i > 0) cursor += MAIN_GAP;
|
|
306
|
-
const { height: height2 } = tidyRight(root.children[i], cursor, i, cols, nodes);
|
|
307
|
-
cursor += height2;
|
|
308
|
-
}
|
|
309
|
-
const totalHeight = cursor;
|
|
310
|
-
const rootNode = {
|
|
311
|
-
node: root,
|
|
312
|
-
x: 0,
|
|
313
|
-
y: totalHeight / 2,
|
|
314
|
-
side: "center",
|
|
315
|
-
branchIndex: -1,
|
|
316
|
-
labelWidth: rootCapsuleW,
|
|
317
|
-
labelHeight: rootCapsuleH
|
|
318
|
-
};
|
|
319
|
-
nodes.push(rootNode);
|
|
320
|
-
const { width, height } = normalize(nodes);
|
|
321
|
-
const byId = new Map(nodes.map((n) => [n.node.id, n]));
|
|
322
|
-
const edges = buildEdges(root, byId);
|
|
323
|
-
return { width, height, style: "logic-right", nodes, edges, title: ast.title };
|
|
324
|
-
}
|
|
325
|
-
function layoutMindmap(ast) {
|
|
326
|
-
const style = ast.style;
|
|
327
|
-
if (style === "logic-right") return layoutLogicRight(ast);
|
|
328
|
-
return layoutMap(ast);
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
// src/diagrams/mindmap/renderer.ts
|
|
332
|
-
var UNDERLINE_MAIN = 2.2;
|
|
333
|
-
var UNDERLINE_MAIN_MONO = 1.5;
|
|
334
|
-
function paletteColor(theme, branchIndex) {
|
|
335
|
-
if (branchIndex < 0) return theme.centralFill;
|
|
336
|
-
return theme.branchPalette[branchIndex % theme.branchPalette.length];
|
|
337
|
-
}
|
|
338
|
-
function underlineMain(theme) {
|
|
339
|
-
return theme.branchPalette.length <= 1 ? UNDERLINE_MAIN_MONO : UNDERLINE_MAIN;
|
|
340
|
-
}
|
|
341
|
-
function renderCentral(n, theme, fontFamily) {
|
|
342
|
-
const fs = fontSizeOf(0);
|
|
343
|
-
const pillW = n.labelWidth;
|
|
344
|
-
const pillH = n.labelHeight;
|
|
345
|
-
return chunkHDKDQAEQ_cjs.group(
|
|
346
|
-
{ class: "schematex-mindmap-central", "data-node-id": n.node.id },
|
|
347
|
-
[
|
|
348
|
-
chunkHDKDQAEQ_cjs.rect({
|
|
349
|
-
x: n.x - pillW / 2,
|
|
350
|
-
y: n.y - pillH / 2,
|
|
351
|
-
width: pillW,
|
|
352
|
-
height: pillH,
|
|
353
|
-
rx: pillH / 2,
|
|
354
|
-
ry: pillH / 2,
|
|
355
|
-
fill: "none",
|
|
356
|
-
stroke: theme.textMuted,
|
|
357
|
-
"stroke-width": underlineMain(theme)
|
|
358
|
-
}),
|
|
359
|
-
chunkHDKDQAEQ_cjs.text(
|
|
360
|
-
{
|
|
361
|
-
x: n.x,
|
|
362
|
-
y: n.y + fs * 0.35,
|
|
363
|
-
"text-anchor": "middle",
|
|
364
|
-
"font-family": fontFamily,
|
|
365
|
-
"font-size": fs,
|
|
366
|
-
"font-weight": 700,
|
|
367
|
-
fill: theme.text
|
|
368
|
-
},
|
|
369
|
-
n.node.label
|
|
370
|
-
)
|
|
371
|
-
]
|
|
372
|
-
);
|
|
373
|
-
}
|
|
374
|
-
function renderBranchNode(n, color, theme, fontFamily) {
|
|
375
|
-
const isMain = n.node.depth === 1;
|
|
376
|
-
const fs = fontSizeOf(n.node.depth);
|
|
377
|
-
const tx = n.x;
|
|
378
|
-
const ty = isMain ? n.y - 3 : n.y + fs * 0.35;
|
|
379
|
-
const ux1 = n.x - n.labelWidth / 2;
|
|
380
|
-
const ux2 = n.x + n.labelWidth / 2;
|
|
381
|
-
const uy = n.y;
|
|
382
|
-
const children = [
|
|
383
|
-
chunkHDKDQAEQ_cjs.text(
|
|
384
|
-
{
|
|
385
|
-
x: tx,
|
|
386
|
-
y: ty,
|
|
387
|
-
"text-anchor": "middle",
|
|
388
|
-
"font-family": fontFamily,
|
|
389
|
-
"font-size": fs,
|
|
390
|
-
"font-weight": isMain ? 600 : 400,
|
|
391
|
-
fill: theme.text
|
|
392
|
-
},
|
|
393
|
-
n.node.label
|
|
394
|
-
)
|
|
395
|
-
];
|
|
396
|
-
if (isMain) {
|
|
397
|
-
children.push(
|
|
398
|
-
chunkHDKDQAEQ_cjs.el("line", {
|
|
399
|
-
x1: ux1,
|
|
400
|
-
y1: uy,
|
|
401
|
-
x2: ux2,
|
|
402
|
-
y2: uy,
|
|
403
|
-
stroke: color,
|
|
404
|
-
"stroke-width": underlineMain(theme),
|
|
405
|
-
"stroke-linecap": "round"
|
|
406
|
-
})
|
|
407
|
-
);
|
|
408
|
-
}
|
|
409
|
-
return chunkHDKDQAEQ_cjs.group(
|
|
410
|
-
{
|
|
411
|
-
class: isMain ? "schematex-mindmap-main" : "schematex-mindmap-leaf",
|
|
412
|
-
"data-node-id": n.node.id,
|
|
413
|
-
"data-depth": n.node.depth,
|
|
414
|
-
"data-branch-idx": n.branchIndex
|
|
415
|
-
},
|
|
416
|
-
children
|
|
417
|
-
);
|
|
418
|
-
}
|
|
419
|
-
function renderMindmapAST(ast, themeName = "default", fontFamily = "system-ui, -apple-system, sans-serif") {
|
|
420
|
-
const theme = chunkN7KOXOMX_cjs.resolveMindmapTheme(ast.themeOverride ?? themeName);
|
|
421
|
-
const layout = layoutMindmap(ast);
|
|
422
|
-
const byId = new Map(layout.nodes.map((n) => [n.node.id, n]));
|
|
423
|
-
const edgeSvgs = [];
|
|
424
|
-
for (const e of layout.edges) {
|
|
425
|
-
const target = byId.get(e.to);
|
|
426
|
-
if (!target) continue;
|
|
427
|
-
const color = paletteColor(theme, target.branchIndex);
|
|
428
|
-
edgeSvgs.push(
|
|
429
|
-
chunkHDKDQAEQ_cjs.path({
|
|
430
|
-
d: e.path,
|
|
431
|
-
fill: "none",
|
|
432
|
-
stroke: color,
|
|
433
|
-
"stroke-width": e.width,
|
|
434
|
-
"stroke-linecap": "round"
|
|
435
|
-
})
|
|
436
|
-
);
|
|
437
|
-
}
|
|
438
|
-
const nodeSvgs = [];
|
|
439
|
-
for (const n of layout.nodes) {
|
|
440
|
-
if (n.node.depth === 0) {
|
|
441
|
-
nodeSvgs.push(renderCentral(n, theme, fontFamily));
|
|
442
|
-
} else {
|
|
443
|
-
nodeSvgs.push(
|
|
444
|
-
renderBranchNode(n, paletteColor(theme, n.branchIndex), theme, fontFamily)
|
|
445
|
-
);
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
const title2 = ast.title ?? ast.root.label;
|
|
449
|
-
return chunkHDKDQAEQ_cjs.svgRoot(
|
|
450
|
-
{
|
|
451
|
-
viewBox: `0 0 ${layout.width.toFixed(1)} ${layout.height.toFixed(1)}`,
|
|
452
|
-
width: layout.width.toFixed(1),
|
|
453
|
-
height: layout.height.toFixed(1),
|
|
454
|
-
role: "graphics-document",
|
|
455
|
-
"aria-label": `Mindmap: ${chunkHDKDQAEQ_cjs.escapeXml(title2)}`
|
|
456
|
-
},
|
|
457
|
-
[
|
|
458
|
-
chunkHDKDQAEQ_cjs.title(title2),
|
|
459
|
-
chunkHDKDQAEQ_cjs.desc(`${layout.style} mindmap with ${layout.nodes.length} nodes`),
|
|
460
|
-
chunkHDKDQAEQ_cjs.rect({ x: 0, y: 0, width: layout.width, height: layout.height, fill: theme.bg }),
|
|
461
|
-
chunkHDKDQAEQ_cjs.group({ class: "schematex-mindmap-edges", "aria-hidden": "true" }, edgeSvgs),
|
|
462
|
-
chunkHDKDQAEQ_cjs.group({ class: "schematex-mindmap-nodes" }, nodeSvgs)
|
|
463
|
-
]
|
|
464
|
-
);
|
|
465
|
-
}
|
|
466
|
-
function renderMindmap(text2, opts) {
|
|
467
|
-
const ast = parseMindmap(text2);
|
|
468
|
-
return renderMindmapAST(ast, opts?.theme, opts?.fontFamily);
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
// src/diagrams/mindmap/index.ts
|
|
472
|
-
var mindmap = {
|
|
473
|
-
type: "mindmap",
|
|
474
|
-
detect(text2) {
|
|
475
|
-
const lines = text2.trim().split("\n");
|
|
476
|
-
const first = lines[0]?.trim().toLowerCase() ?? "";
|
|
477
|
-
if (first.startsWith("mindmap")) return true;
|
|
478
|
-
for (const ln of lines) {
|
|
479
|
-
const t = ln.trim();
|
|
480
|
-
if (!t) continue;
|
|
481
|
-
if (t.startsWith("%%")) continue;
|
|
482
|
-
return /^#\s+\S/.test(t);
|
|
483
|
-
}
|
|
484
|
-
return false;
|
|
485
|
-
},
|
|
486
|
-
render(text2, config) {
|
|
487
|
-
return renderMindmap(text2, {
|
|
488
|
-
theme: config?.theme,
|
|
489
|
-
fontFamily: config?.fontFamily
|
|
490
|
-
});
|
|
491
|
-
}
|
|
492
|
-
};
|
|
493
|
-
|
|
494
|
-
// src/diagrams/matrix/templates.ts
|
|
495
|
-
var TEMPLATES = {
|
|
496
|
-
"eisenhower": {
|
|
497
|
-
grid: "2x2",
|
|
498
|
-
xAxis: { low: "Urgent", high: "Not Urgent" },
|
|
499
|
-
yAxis: { low: "Not Important", high: "Important" },
|
|
500
|
-
annotations: [
|
|
501
|
-
{ q: 1, label: "Schedule" },
|
|
502
|
-
{ q: 2, label: "Do First" },
|
|
503
|
-
{ q: 3, label: "Delete" },
|
|
504
|
-
{ q: 4, label: "Delegate" }
|
|
505
|
-
]
|
|
506
|
-
},
|
|
507
|
-
"impact-effort": {
|
|
508
|
-
grid: "2x2",
|
|
509
|
-
xAxis: { low: "Low Effort", high: "High Effort" },
|
|
510
|
-
yAxis: { low: "Low Impact", high: "High Impact" },
|
|
511
|
-
annotations: [
|
|
512
|
-
{ q: 1, label: "Major Projects" },
|
|
513
|
-
{ q: 2, label: "Quick Wins" },
|
|
514
|
-
{ q: 3, label: "Fill-ins" },
|
|
515
|
-
{ q: 4, label: "Thankless" }
|
|
516
|
-
]
|
|
517
|
-
},
|
|
518
|
-
"rice": {
|
|
519
|
-
grid: "2x2",
|
|
520
|
-
xAxis: { low: "Low Effort", high: "High Effort" },
|
|
521
|
-
yAxis: { low: "Low Reach \xD7 Impact", high: "High Reach \xD7 Impact" },
|
|
522
|
-
annotations: [
|
|
523
|
-
{ q: 1, label: "Strategic Bets" },
|
|
524
|
-
{ q: 2, label: "High RICE" },
|
|
525
|
-
{ q: 3, label: "Backlog" },
|
|
526
|
-
{ q: 4, label: "Reconsider" }
|
|
527
|
-
]
|
|
528
|
-
},
|
|
529
|
-
"bcg": {
|
|
530
|
-
grid: "2x2",
|
|
531
|
-
// BCG convention: high market share on left (x-axis reversed)
|
|
532
|
-
xAxis: { low: "High Market Share", high: "Low Market Share" },
|
|
533
|
-
yAxis: { low: "Low Growth", high: "High Growth" },
|
|
534
|
-
annotations: [
|
|
535
|
-
{ q: 1, label: "Question Marks" },
|
|
536
|
-
{ q: 2, label: "Stars" },
|
|
537
|
-
{ q: 3, label: "Cash Cows" },
|
|
538
|
-
{ q: 4, label: "Dogs" }
|
|
539
|
-
]
|
|
540
|
-
},
|
|
541
|
-
"ansoff": {
|
|
542
|
-
grid: "2x2",
|
|
543
|
-
xAxis: { low: "Existing Products", high: "New Products" },
|
|
544
|
-
yAxis: { low: "Existing Markets", high: "New Markets" },
|
|
545
|
-
annotations: [
|
|
546
|
-
{ q: 1, label: "Diversification" },
|
|
547
|
-
{ q: 2, label: "Market Development" },
|
|
548
|
-
{ q: 3, label: "Market Penetration" },
|
|
549
|
-
{ q: 4, label: "Product Development" }
|
|
550
|
-
]
|
|
551
|
-
},
|
|
552
|
-
"johari": {
|
|
553
|
-
grid: "2x2",
|
|
554
|
-
xAxis: { low: "Known to Self", high: "Not Known to Self" },
|
|
555
|
-
yAxis: { low: "Not Known to Others", high: "Known to Others" },
|
|
556
|
-
annotations: [
|
|
557
|
-
{ q: 1, label: "Blind" },
|
|
558
|
-
{ q: 2, label: "Open / Arena" },
|
|
559
|
-
{ q: 3, label: "Hidden / Fa\xE7ade" },
|
|
560
|
-
{ q: 4, label: "Unknown" }
|
|
561
|
-
]
|
|
562
|
-
},
|
|
563
|
-
"9-box": {
|
|
564
|
-
grid: "3x3",
|
|
565
|
-
cols: 3,
|
|
566
|
-
rows: 3,
|
|
567
|
-
xAxis: { low: "Low Performance", high: "High Performance" },
|
|
568
|
-
yAxis: { low: "Low Potential", high: "High Potential" },
|
|
569
|
-
cellLabels: [
|
|
570
|
-
{ col: 0, row: 2, label: "Enigma" },
|
|
571
|
-
{ col: 1, row: 2, label: "Growth Employee" },
|
|
572
|
-
{ col: 2, row: 2, label: "Future Leader" },
|
|
573
|
-
{ col: 0, row: 1, label: "Dilemma" },
|
|
574
|
-
{ col: 1, row: 1, label: "Core Player" },
|
|
575
|
-
{ col: 2, row: 1, label: "High Impact" },
|
|
576
|
-
{ col: 0, row: 0, label: "Under-performer" },
|
|
577
|
-
{ col: 1, row: 0, label: "Effective" },
|
|
578
|
-
{ col: 2, row: 0, label: "Trusted Pro" }
|
|
579
|
-
]
|
|
580
|
-
},
|
|
581
|
-
"risk-matrix": {
|
|
582
|
-
grid: "NxM",
|
|
583
|
-
mode: "heatmap",
|
|
584
|
-
cols: 5,
|
|
585
|
-
rows: 5,
|
|
586
|
-
xAxis: { low: "Negligible", high: "Severe" },
|
|
587
|
-
yAxis: { low: "Rare", high: "Certain" },
|
|
588
|
-
rowLabels: ["Rare", "Unlikely", "Possible", "Likely", "Certain"],
|
|
589
|
-
colLabels: ["Negligible", "Minor", "Moderate", "Major", "Severe"]
|
|
590
|
-
}
|
|
591
|
-
};
|
|
592
|
-
function resolveTemplate(name) {
|
|
593
|
-
if (name in TEMPLATES) return TEMPLATES[name];
|
|
594
|
-
return void 0;
|
|
595
|
-
}
|
|
596
|
-
function applyTemplateDefaults(ast, spec) {
|
|
597
|
-
if (spec.grid === "3x3") {
|
|
598
|
-
ast.grid = "3x3";
|
|
599
|
-
ast.cols = 3;
|
|
600
|
-
ast.rows = 3;
|
|
601
|
-
} else if (spec.grid === "NxM") {
|
|
602
|
-
ast.grid = "NxM";
|
|
603
|
-
ast.cols = spec.cols ?? 5;
|
|
604
|
-
ast.rows = spec.rows ?? 5;
|
|
605
|
-
} else {
|
|
606
|
-
ast.grid = "2x2";
|
|
607
|
-
ast.cols = 2;
|
|
608
|
-
ast.rows = 2;
|
|
609
|
-
}
|
|
610
|
-
if (spec.mode) ast.mode = spec.mode;
|
|
611
|
-
if (!ast.xAxis.low && !ast.xAxis.high) ast.xAxis = { ...spec.xAxis };
|
|
612
|
-
if (!ast.yAxis.low && !ast.yAxis.high) ast.yAxis = { ...spec.yAxis };
|
|
613
|
-
if (spec.annotations && ast.annotations.length === 0) {
|
|
614
|
-
ast.annotations = spec.annotations.map((a) => ({ ...a }));
|
|
615
|
-
}
|
|
616
|
-
if (spec.cellLabels && ast.cellLabels.length === 0) {
|
|
617
|
-
ast.cellLabels = spec.cellLabels.map((c) => ({ ...c }));
|
|
618
|
-
}
|
|
619
|
-
if (spec.rowLabels && !ast.rowLabels) ast.rowLabels = [...spec.rowLabels];
|
|
620
|
-
if (spec.colLabels && !ast.colLabels) ast.colLabels = [...spec.colLabels];
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
// src/diagrams/matrix/parser.ts
|
|
624
|
-
var TEMPLATE_NAMES = /* @__PURE__ */ new Set([
|
|
625
|
-
"eisenhower",
|
|
626
|
-
"impact-effort",
|
|
627
|
-
"rice",
|
|
628
|
-
"bcg",
|
|
629
|
-
"ansoff",
|
|
630
|
-
"johari",
|
|
631
|
-
"9-box",
|
|
632
|
-
"risk-matrix"
|
|
633
|
-
]);
|
|
634
|
-
var DEFAULT_CONFIG = {
|
|
635
|
-
quadrantBg: true,
|
|
636
|
-
gridLines: true,
|
|
637
|
-
axisArrows: true,
|
|
638
|
-
labelCollision: "auto",
|
|
639
|
-
bubbleScale: "area",
|
|
640
|
-
quadrantAnnotations: true,
|
|
641
|
-
legendPosition: "bottom-right",
|
|
642
|
-
offChartPolicy: "clamp-badge",
|
|
643
|
-
showAxis: "auto",
|
|
644
|
-
margins: false
|
|
645
|
-
};
|
|
646
|
-
function emptyAxis() {
|
|
647
|
-
return { low: "", high: "" };
|
|
648
|
-
}
|
|
649
|
-
function newAST() {
|
|
650
|
-
return {
|
|
651
|
-
type: "matrix",
|
|
652
|
-
mode: "quadrant",
|
|
653
|
-
grid: "2x2",
|
|
654
|
-
cols: 2,
|
|
655
|
-
rows: 2,
|
|
656
|
-
xAxis: emptyAxis(),
|
|
657
|
-
yAxis: emptyAxis(),
|
|
658
|
-
points: [],
|
|
659
|
-
cells: [],
|
|
660
|
-
cellLabels: [],
|
|
661
|
-
annotations: [],
|
|
662
|
-
config: { ...DEFAULT_CONFIG }
|
|
663
|
-
};
|
|
664
|
-
}
|
|
665
|
-
function stripQuotes(s) {
|
|
666
|
-
const t = s.trim();
|
|
667
|
-
if (t.startsWith('"') && t.endsWith('"') || t.startsWith("'") && t.endsWith("'")) {
|
|
668
|
-
return t.slice(1, -1);
|
|
669
|
-
}
|
|
670
|
-
return t;
|
|
671
|
-
}
|
|
672
|
-
function readQuoted(line2, from) {
|
|
673
|
-
let i = from;
|
|
674
|
-
while (i < line2.length && /\s/.test(line2[i])) i++;
|
|
675
|
-
if (line2[i] !== '"' && line2[i] !== "'") return null;
|
|
676
|
-
const quote = line2[i];
|
|
677
|
-
const start = i + 1;
|
|
678
|
-
let end = start;
|
|
679
|
-
while (end < line2.length && line2[end] !== quote) end++;
|
|
680
|
-
if (end >= line2.length) return null;
|
|
681
|
-
return { text: line2.slice(start, end), next: end + 1 };
|
|
682
|
-
}
|
|
683
|
-
function parseAxis(raw) {
|
|
684
|
-
const arrowMatch = raw.match(/\s*(→|↑|->|>|↓|←|<-|<)\s*/);
|
|
685
|
-
if (arrowMatch) {
|
|
686
|
-
const arrow = arrowMatch[1];
|
|
687
|
-
const idx = arrowMatch.index;
|
|
688
|
-
const left = raw.slice(0, idx).trim();
|
|
689
|
-
const right = raw.slice(idx + arrowMatch[0].length).trim();
|
|
690
|
-
const reversed = arrow === "\u2190" || arrow === "<-" || arrow === "<";
|
|
691
|
-
if (reversed) {
|
|
692
|
-
return { low: right, high: left, reversed: true };
|
|
693
|
-
}
|
|
694
|
-
return { low: left, high: right };
|
|
695
|
-
}
|
|
696
|
-
return { low: "", high: raw.trim() };
|
|
697
|
-
}
|
|
698
|
-
function parseNumberList(raw) {
|
|
699
|
-
const t = raw.trim();
|
|
700
|
-
const inner = t.startsWith("[") && t.endsWith("]") ? t.slice(1, -1) : t;
|
|
701
|
-
return inner.split(",").map((s) => stripQuotes(s.trim())).filter((s) => s.length > 0);
|
|
702
|
-
}
|
|
703
|
-
function parseProperties(raw, point) {
|
|
704
|
-
let i = 0;
|
|
705
|
-
while (i < raw.length) {
|
|
706
|
-
while (i < raw.length && /\s/.test(raw[i])) i++;
|
|
707
|
-
if (i >= raw.length) break;
|
|
708
|
-
const keyMatch = raw.slice(i).match(/^([a-zA-Z_-]+)\s*:\s*/);
|
|
709
|
-
if (!keyMatch) break;
|
|
710
|
-
const key = keyMatch[1].toLowerCase();
|
|
711
|
-
i += keyMatch[0].length;
|
|
712
|
-
if (raw[i] === '"' || raw[i] === "'") {
|
|
713
|
-
const q = readQuoted(raw, i);
|
|
714
|
-
if (!q) break;
|
|
715
|
-
if (key === "note") point.note = q.text;
|
|
716
|
-
else if (key === "label") point.label = q.text;
|
|
717
|
-
i = q.next;
|
|
718
|
-
} else {
|
|
719
|
-
const rest = raw.slice(i);
|
|
720
|
-
const endMatch = rest.match(/\s+[a-zA-Z_-]+\s*:/);
|
|
721
|
-
const end = endMatch ? endMatch.index : rest.length;
|
|
722
|
-
const val = rest.slice(0, end).trim();
|
|
723
|
-
i += end;
|
|
724
|
-
if (key === "size") {
|
|
725
|
-
const n = Number(val);
|
|
726
|
-
if (!Number.isNaN(n)) point.size = n;
|
|
727
|
-
} else if (key === "category") {
|
|
728
|
-
point.category = val;
|
|
729
|
-
} else if (key === "color") {
|
|
730
|
-
point.color = val;
|
|
731
|
-
} else if (key === "shape") {
|
|
732
|
-
if (val === "circle" || val === "square" || val === "triangle" || val === "diamond") {
|
|
733
|
-
point.shape = val;
|
|
734
|
-
}
|
|
735
|
-
} else if (key === "highlight") {
|
|
736
|
-
point.highlight = val === "true" || val === "1";
|
|
737
|
-
}
|
|
738
|
-
}
|
|
739
|
-
}
|
|
740
|
-
}
|
|
741
|
-
function parsePointLine(line2, st) {
|
|
742
|
-
const q = readQuoted(line2, 0);
|
|
743
|
-
if (!q) return false;
|
|
744
|
-
const rest = line2.slice(q.next).trim();
|
|
745
|
-
const atMatch = rest.match(/^at\s*\(\s*(-?\d+(?:\.\d+)?)\s*,\s*(-?\d+(?:\.\d+)?)\s*\)\s*(.*)$/);
|
|
746
|
-
if (!atMatch) return false;
|
|
747
|
-
const x = Number(atMatch[1]);
|
|
748
|
-
const y = Number(atMatch[2]);
|
|
749
|
-
const props = atMatch[3];
|
|
750
|
-
const offChart = x < 0 || x > 1 || y < 0 || y > 1;
|
|
751
|
-
const clampedX = Math.max(0, Math.min(1, x));
|
|
752
|
-
const clampedY = Math.max(0, Math.min(1, y));
|
|
753
|
-
const point = {
|
|
754
|
-
id: `p${st.pointIdSeq++}`,
|
|
755
|
-
label: q.text,
|
|
756
|
-
x: clampedX,
|
|
757
|
-
y: clampedY,
|
|
758
|
-
offChart,
|
|
759
|
-
origX: offChart ? x : void 0,
|
|
760
|
-
origY: offChart ? y : void 0
|
|
761
|
-
};
|
|
762
|
-
if (props) parseProperties(props, point);
|
|
763
|
-
st.ast.points.push(point);
|
|
764
|
-
return true;
|
|
765
|
-
}
|
|
766
|
-
function parseCellLine(line2, st) {
|
|
767
|
-
const m = line2.match(/^cell\s*\(\s*(\d+)\s*,\s*(\d+)\s*\)\s*(.*)$/i);
|
|
768
|
-
if (!m) return false;
|
|
769
|
-
const col = Number(m[1]);
|
|
770
|
-
const row = Number(m[2]);
|
|
771
|
-
const rest = m[3];
|
|
772
|
-
const cell = { col, row };
|
|
773
|
-
const valMatch = rest.match(/value:\s*(-?\d+(?:\.\d+)?)/i);
|
|
774
|
-
if (valMatch) cell.value = Number(valMatch[1]);
|
|
775
|
-
const labMatch = rest.match(/label:\s*"([^"]*)"/i);
|
|
776
|
-
if (labMatch) cell.label = labMatch[1];
|
|
777
|
-
const lvlMatch = rest.match(/level:\s*(strong|medium|weak)\b/i);
|
|
778
|
-
if (lvlMatch) {
|
|
779
|
-
const lv = lvlMatch[1].toLowerCase();
|
|
780
|
-
cell.level = lv;
|
|
781
|
-
if (cell.value === void 0) cell.value = lv === "strong" ? 3 : lv === "medium" ? 2 : 1;
|
|
782
|
-
}
|
|
783
|
-
st.ast.cells.push(cell);
|
|
784
|
-
if (cell.label) {
|
|
785
|
-
st.ast.cellLabels.push({ col, row, label: cell.label });
|
|
786
|
-
}
|
|
787
|
-
return true;
|
|
788
|
-
}
|
|
789
|
-
function parseConfigLine(key, value, ast) {
|
|
790
|
-
const k = key.trim().toLowerCase();
|
|
791
|
-
const v = value.trim();
|
|
792
|
-
if (k === "quadrantbg") ast.config.quadrantBg = v === "true";
|
|
793
|
-
else if (k === "gridlines") ast.config.gridLines = v === "true";
|
|
794
|
-
else if (k === "axisarrows") ast.config.axisArrows = v === "true";
|
|
795
|
-
else if (k === "labelcollision") ast.config.labelCollision = v.replace(/"/g, "");
|
|
796
|
-
else if (k === "bubblescale") ast.config.bubbleScale = v === "radius" ? "radius" : "area";
|
|
797
|
-
else if (k === "quadrantannotations") ast.config.quadrantAnnotations = v === "true";
|
|
798
|
-
else if (k === "legendposition") {
|
|
799
|
-
const t = v.replace(/"/g, "");
|
|
800
|
-
ast.config.legendPosition = t;
|
|
801
|
-
} else if (k === "offchartpolicy") {
|
|
802
|
-
const t = v.replace(/"/g, "");
|
|
803
|
-
ast.config.offChartPolicy = t;
|
|
804
|
-
}
|
|
805
|
-
}
|
|
806
|
-
function parseHeader(line2, ast) {
|
|
807
|
-
const t = line2.trim();
|
|
808
|
-
const rest = t.slice("matrix".length).trim();
|
|
809
|
-
const heatMatch = rest.match(/^heatmap\s+(\d+)\s*x\s*(\d+)\s*(.*)$/i);
|
|
810
|
-
if (heatMatch) {
|
|
811
|
-
ast.mode = "heatmap";
|
|
812
|
-
ast.grid = "NxM";
|
|
813
|
-
ast.cols = Number(heatMatch[1]);
|
|
814
|
-
ast.rows = Number(heatMatch[2]);
|
|
815
|
-
const title2 = heatMatch[3].trim();
|
|
816
|
-
if (title2) ast.title = stripQuotes(title2);
|
|
817
|
-
return void 0;
|
|
818
|
-
}
|
|
819
|
-
const corrMatch = rest.match(/^correlation\s*(?:(\d+)\s*x\s*(\d+))?\s*(.*)$/i);
|
|
820
|
-
if (corrMatch) {
|
|
821
|
-
ast.mode = "correlation";
|
|
822
|
-
ast.grid = "NxM";
|
|
823
|
-
if (corrMatch[1] && corrMatch[2]) {
|
|
824
|
-
ast.cols = Number(corrMatch[1]);
|
|
825
|
-
ast.rows = Number(corrMatch[2]);
|
|
826
|
-
}
|
|
827
|
-
const title2 = corrMatch[3].trim();
|
|
828
|
-
if (title2) ast.title = stripQuotes(title2);
|
|
829
|
-
return void 0;
|
|
830
|
-
}
|
|
831
|
-
const tokenMatch = rest.match(/^([a-zA-Z0-9_-]+)\s*(.*)$/);
|
|
832
|
-
if (tokenMatch) {
|
|
833
|
-
const tok = tokenMatch[1].toLowerCase();
|
|
834
|
-
const remainder = tokenMatch[2].trim();
|
|
835
|
-
if (TEMPLATE_NAMES.has(tok)) {
|
|
836
|
-
if (remainder) ast.title = stripQuotes(remainder);
|
|
837
|
-
return tok;
|
|
838
|
-
}
|
|
839
|
-
if (rest.startsWith('"') || rest.startsWith("'")) {
|
|
840
|
-
ast.title = stripQuotes(rest);
|
|
841
|
-
} else if (rest.length > 0) {
|
|
842
|
-
ast.title = stripQuotes(rest);
|
|
843
|
-
}
|
|
844
|
-
}
|
|
845
|
-
return void 0;
|
|
846
|
-
}
|
|
847
|
-
function parseMatrix(text2) {
|
|
848
|
-
const st = { ast: newAST(), pointIdSeq: 0 };
|
|
849
|
-
const lines = text2.split(/\r?\n/);
|
|
850
|
-
let templateName;
|
|
851
|
-
let inConfig = false;
|
|
852
|
-
for (let raw of lines) {
|
|
853
|
-
let line2 = raw;
|
|
854
|
-
const hashIdx = findCommentStart(line2);
|
|
855
|
-
if (hashIdx >= 0) line2 = line2.slice(0, hashIdx);
|
|
856
|
-
line2 = line2.trim();
|
|
857
|
-
if (!line2) {
|
|
858
|
-
inConfig = false;
|
|
859
|
-
continue;
|
|
860
|
-
}
|
|
861
|
-
if (/^matrix\b/i.test(line2)) {
|
|
862
|
-
templateName = parseHeader(line2, st.ast);
|
|
863
|
-
continue;
|
|
864
|
-
}
|
|
865
|
-
if (/^config\s*:/i.test(line2)) {
|
|
866
|
-
inConfig = true;
|
|
867
|
-
continue;
|
|
868
|
-
}
|
|
869
|
-
if (inConfig) {
|
|
870
|
-
const kv = line2.match(/^([a-zA-Z]+)\s*:\s*(.+)$/);
|
|
871
|
-
if (kv) {
|
|
872
|
-
parseConfigLine(kv[1], kv[2], st.ast);
|
|
873
|
-
continue;
|
|
874
|
-
}
|
|
875
|
-
inConfig = false;
|
|
876
|
-
}
|
|
877
|
-
if (/^title\s*:/i.test(line2)) {
|
|
878
|
-
st.ast.title = stripQuotes(line2.replace(/^title\s*:\s*/i, ""));
|
|
879
|
-
continue;
|
|
880
|
-
}
|
|
881
|
-
if (/^x-axis\s*:/i.test(line2)) {
|
|
882
|
-
st.ast.xAxis = parseAxis(line2.replace(/^x-axis\s*:\s*/i, ""));
|
|
883
|
-
continue;
|
|
884
|
-
}
|
|
885
|
-
if (/^y-axis\s*:/i.test(line2)) {
|
|
886
|
-
st.ast.yAxis = parseAxis(line2.replace(/^y-axis\s*:\s*/i, ""));
|
|
887
|
-
continue;
|
|
888
|
-
}
|
|
889
|
-
if (/^rows\s*:/i.test(line2)) {
|
|
890
|
-
st.ast.rowLabels = parseNumberList(line2.replace(/^rows\s*:\s*/i, ""));
|
|
891
|
-
if (st.ast.mode !== "quadrant") st.ast.rows = st.ast.rowLabels.length;
|
|
892
|
-
continue;
|
|
893
|
-
}
|
|
894
|
-
if (/^cols\s*:/i.test(line2)) {
|
|
895
|
-
st.ast.colLabels = parseNumberList(line2.replace(/^cols\s*:\s*/i, ""));
|
|
896
|
-
if (st.ast.mode !== "quadrant") st.ast.cols = st.ast.colLabels.length;
|
|
897
|
-
continue;
|
|
898
|
-
}
|
|
899
|
-
if (/^grid\s*:/i.test(line2)) {
|
|
900
|
-
const v = line2.replace(/^grid\s*:\s*/i, "").trim().toLowerCase();
|
|
901
|
-
const gm = v.match(/^(\d+)\s*x\s*(\d+)$/);
|
|
902
|
-
if (gm) {
|
|
903
|
-
const c = Number(gm[1]);
|
|
904
|
-
const r = Number(gm[2]);
|
|
905
|
-
st.ast.cols = c;
|
|
906
|
-
st.ast.rows = r;
|
|
907
|
-
if (c === 2 && r === 2) st.ast.grid = "2x2";
|
|
908
|
-
else if (c === 3 && r === 3) st.ast.grid = "3x3";
|
|
909
|
-
else st.ast.grid = "NxM";
|
|
910
|
-
}
|
|
911
|
-
continue;
|
|
912
|
-
}
|
|
913
|
-
if (/^quadrant\s+/i.test(line2)) {
|
|
914
|
-
const m = line2.match(/^quadrant\s+(?:Q)?(\d)\s*"([^"]*)"(.*)$/i);
|
|
915
|
-
if (m) {
|
|
916
|
-
const q = Number(m[1]);
|
|
917
|
-
const rest = m[3].trim();
|
|
918
|
-
const descMatch = rest.match(/description:\s*"([^"]*)"/i);
|
|
919
|
-
const description = descMatch ? descMatch[1] : void 0;
|
|
920
|
-
if (q >= 1 && q <= 4) {
|
|
921
|
-
const existing = st.ast.annotations.find((a) => a.q === q);
|
|
922
|
-
if (existing) {
|
|
923
|
-
existing.label = m[2];
|
|
924
|
-
if (description) existing.description = description;
|
|
925
|
-
} else {
|
|
926
|
-
st.ast.annotations.push({ q, label: m[2], description });
|
|
927
|
-
}
|
|
928
|
-
}
|
|
929
|
-
}
|
|
930
|
-
continue;
|
|
931
|
-
}
|
|
932
|
-
if (/^axis\s*:/i.test(line2)) {
|
|
933
|
-
const v = line2.replace(/^axis\s*:\s*/i, "").trim().toLowerCase().replace(/"/g, "");
|
|
934
|
-
if (v === "none" || v === "off" || v === "hidden") st.ast.config.showAxis = "off";
|
|
935
|
-
else if (v === "on" || v === "show" || v === "visible") st.ast.config.showAxis = "on";
|
|
936
|
-
else st.ast.config.showAxis = "auto";
|
|
937
|
-
continue;
|
|
938
|
-
}
|
|
939
|
-
if (/^margins\s*:/i.test(line2)) {
|
|
940
|
-
const v = line2.replace(/^margins\s*:\s*/i, "").trim().toLowerCase();
|
|
941
|
-
st.ast.config.margins = v === "true" || v === "on" || v === "1";
|
|
942
|
-
continue;
|
|
943
|
-
}
|
|
944
|
-
if (/^cell\s*\(/i.test(line2)) {
|
|
945
|
-
parseCellLine(line2, st);
|
|
946
|
-
continue;
|
|
947
|
-
}
|
|
948
|
-
if (line2.startsWith('"') || line2.startsWith("'")) {
|
|
949
|
-
if (parsePointLine(line2, st)) continue;
|
|
950
|
-
}
|
|
951
|
-
}
|
|
952
|
-
if (templateName) {
|
|
953
|
-
const spec = resolveTemplate(templateName);
|
|
954
|
-
if (spec) {
|
|
955
|
-
applyTemplateDefaults(st.ast, spec);
|
|
956
|
-
st.ast.template = templateName;
|
|
957
|
-
}
|
|
958
|
-
}
|
|
959
|
-
if (st.ast.cols === 3 && st.ast.rows === 3 && st.ast.grid !== "NxM") {
|
|
960
|
-
st.ast.grid = "3x3";
|
|
961
|
-
}
|
|
962
|
-
if (st.ast.mode === "heatmap" || st.ast.mode === "correlation") st.ast.grid = "NxM";
|
|
963
|
-
return st.ast;
|
|
964
|
-
}
|
|
965
|
-
function findCommentStart(line2) {
|
|
966
|
-
let inQuote = null;
|
|
967
|
-
for (let i = 0; i < line2.length; i++) {
|
|
968
|
-
const ch = line2[i];
|
|
969
|
-
if (inQuote) {
|
|
970
|
-
if (ch === inQuote) inQuote = null;
|
|
971
|
-
} else if (ch === '"' || ch === "'") {
|
|
972
|
-
inQuote = ch;
|
|
973
|
-
} else if (ch === "#") {
|
|
974
|
-
return i;
|
|
975
|
-
}
|
|
976
|
-
}
|
|
977
|
-
return -1;
|
|
978
|
-
}
|
|
979
|
-
|
|
980
|
-
// src/diagrams/matrix/layout.ts
|
|
981
|
-
var CANVAS_W = 720;
|
|
982
|
-
var CANVAS_H = 560;
|
|
983
|
-
var PADDING_X = 110;
|
|
984
|
-
var PADDING_Y = 90;
|
|
985
|
-
var CHAR_W = 6.2;
|
|
986
|
-
var LABEL_H = 14;
|
|
987
|
-
function estimateWidth(text2) {
|
|
988
|
-
const cjk = (text2.match(/[\u3000-\u9fff]/g) ?? []).length;
|
|
989
|
-
return (text2.length - cjk) * CHAR_W + cjk * 12 + 8;
|
|
990
|
-
}
|
|
991
|
-
function clamp01(v) {
|
|
992
|
-
return Math.max(0.02, Math.min(0.98, v));
|
|
993
|
-
}
|
|
994
|
-
function placePoint(p, plot) {
|
|
995
|
-
const nx = clamp01(p.x);
|
|
996
|
-
const ny = clamp01(p.y);
|
|
997
|
-
const px = plot.x0 + nx * plot.w;
|
|
998
|
-
const py = plot.y0 + (1 - ny) * plot.h;
|
|
999
|
-
return { px, py };
|
|
1000
|
-
}
|
|
1001
|
-
function computeRadius(p, maxSize, plot, scale) {
|
|
1002
|
-
if (p.size === void 0) return 6;
|
|
1003
|
-
const maxRadius = Math.max(14, plot.h * 0.08);
|
|
1004
|
-
const minRadius = 4;
|
|
1005
|
-
if (maxSize <= 0) return 6;
|
|
1006
|
-
const ratio = p.size / maxSize;
|
|
1007
|
-
if (scale === "radius") {
|
|
1008
|
-
return Math.max(minRadius, ratio * maxRadius);
|
|
1009
|
-
}
|
|
1010
|
-
const maxArea = Math.PI * maxRadius * maxRadius;
|
|
1011
|
-
const area = ratio * maxArea;
|
|
1012
|
-
const r = Math.sqrt(area / Math.PI);
|
|
1013
|
-
return Math.max(minRadius, r);
|
|
1014
|
-
}
|
|
1015
|
-
function resolveLabelCollisions(points, plot, mode) {
|
|
1016
|
-
if (mode === "off") {
|
|
1017
|
-
for (const p of points) {
|
|
1018
|
-
p.label.lx = p.px + p.r + 4 + p.label.width / 2;
|
|
1019
|
-
p.label.ly = p.py - p.r - 4;
|
|
1020
|
-
}
|
|
1021
|
-
return;
|
|
1022
|
-
}
|
|
1023
|
-
for (const p of points) {
|
|
1024
|
-
p.label.ax = p.px;
|
|
1025
|
-
p.label.ay = p.py;
|
|
1026
|
-
p.label.lx = p.px + p.r + 4 + p.label.width / 2;
|
|
1027
|
-
p.label.ly = p.py - p.r - 4;
|
|
1028
|
-
p.label.external = false;
|
|
1029
|
-
p.label.textAnchor = "middle";
|
|
1030
|
-
}
|
|
1031
|
-
if (mode === "leader-only") {
|
|
1032
|
-
for (const p of points) {
|
|
1033
|
-
p.label.external = true;
|
|
1034
|
-
p.label.lx = p.px + p.r + 12 + p.label.width / 2;
|
|
1035
|
-
p.label.ly = p.py;
|
|
1036
|
-
p.label.textAnchor = "middle";
|
|
1037
|
-
}
|
|
1038
|
-
return;
|
|
1039
|
-
}
|
|
1040
|
-
const PAD = 3;
|
|
1041
|
-
for (let iter = 0; iter < 30; iter++) {
|
|
1042
|
-
let moved = false;
|
|
1043
|
-
for (let i = 0; i < points.length; i++) {
|
|
1044
|
-
for (let j = i + 1; j < points.length; j++) {
|
|
1045
|
-
const a = points[i].label;
|
|
1046
|
-
const b = points[j].label;
|
|
1047
|
-
const ax0 = a.lx - a.width / 2 - PAD;
|
|
1048
|
-
const ax1 = a.lx + a.width / 2 + PAD;
|
|
1049
|
-
const ay0 = a.ly - a.height / 2 - PAD;
|
|
1050
|
-
const ay1 = a.ly + a.height / 2 + PAD;
|
|
1051
|
-
const bx0 = b.lx - b.width / 2 - PAD;
|
|
1052
|
-
const bx1 = b.lx + b.width / 2 + PAD;
|
|
1053
|
-
const by0 = b.ly - b.height / 2 - PAD;
|
|
1054
|
-
const by1 = b.ly + b.height / 2 + PAD;
|
|
1055
|
-
const overlapX = Math.min(ax1, bx1) - Math.max(ax0, bx0);
|
|
1056
|
-
const overlapY = Math.min(ay1, by1) - Math.max(ay0, by0);
|
|
1057
|
-
if (overlapX > 0 && overlapY > 0) {
|
|
1058
|
-
const dx = a.lx - b.lx || 0.1;
|
|
1059
|
-
const dy = a.ly - b.ly || 0.1;
|
|
1060
|
-
const len = Math.hypot(dx, dy) || 1;
|
|
1061
|
-
const ux = dx / len;
|
|
1062
|
-
const uy = dy / len;
|
|
1063
|
-
const step = Math.min(3, Math.min(overlapX, overlapY) / 2 + 0.5);
|
|
1064
|
-
a.lx += ux * step;
|
|
1065
|
-
a.ly += uy * step;
|
|
1066
|
-
b.lx -= ux * step;
|
|
1067
|
-
b.ly -= uy * step;
|
|
1068
|
-
moved = true;
|
|
1069
|
-
}
|
|
1070
|
-
}
|
|
1071
|
-
const lb = points[i].label;
|
|
1072
|
-
if (lb.lx - lb.width / 2 < plot.x0 + 2) lb.lx = plot.x0 + 2 + lb.width / 2;
|
|
1073
|
-
if (lb.lx + lb.width / 2 > plot.x0 + plot.w - 2) lb.lx = plot.x0 + plot.w - 2 - lb.width / 2;
|
|
1074
|
-
if (lb.ly - lb.height / 2 < plot.y0 + 2) lb.ly = plot.y0 + 2 + lb.height / 2;
|
|
1075
|
-
if (lb.ly + lb.height / 2 > plot.y0 + plot.h - 2) lb.ly = plot.y0 + plot.h - 2 - lb.height / 2;
|
|
1076
|
-
}
|
|
1077
|
-
if (!moved) break;
|
|
1078
|
-
}
|
|
1079
|
-
if (mode === "auto") {
|
|
1080
|
-
for (const p of points) {
|
|
1081
|
-
const dx = p.label.lx - p.px;
|
|
1082
|
-
const dy = p.label.ly - p.py;
|
|
1083
|
-
if (Math.hypot(dx, dy) > 40) {
|
|
1084
|
-
p.label.external = true;
|
|
1085
|
-
}
|
|
1086
|
-
}
|
|
1087
|
-
}
|
|
1088
|
-
}
|
|
1089
|
-
function layoutMatrix(ast) {
|
|
1090
|
-
const canvasWidth = CANVAS_W;
|
|
1091
|
-
const canvasHeight = CANVAS_H;
|
|
1092
|
-
const plot = {
|
|
1093
|
-
x0: PADDING_X,
|
|
1094
|
-
y0: PADDING_Y - 30,
|
|
1095
|
-
w: canvasWidth - PADDING_X * 2,
|
|
1096
|
-
h: canvasHeight - PADDING_Y * 2
|
|
1097
|
-
};
|
|
1098
|
-
const points = [];
|
|
1099
|
-
const categoriesSet = /* @__PURE__ */ new Set();
|
|
1100
|
-
if (ast.mode === "quadrant") {
|
|
1101
|
-
let maxSize = 0;
|
|
1102
|
-
for (const p of ast.points) {
|
|
1103
|
-
if (p.size !== void 0 && p.size > maxSize) maxSize = p.size;
|
|
1104
|
-
}
|
|
1105
|
-
for (const p of ast.points) {
|
|
1106
|
-
const { px, py } = placePoint(p, plot);
|
|
1107
|
-
const r = computeRadius(p, maxSize, plot, ast.config.bubbleScale);
|
|
1108
|
-
const width = estimateWidth(p.label);
|
|
1109
|
-
const label = {
|
|
1110
|
-
text: p.label,
|
|
1111
|
-
ax: px,
|
|
1112
|
-
ay: py,
|
|
1113
|
-
lx: px + r + 4 + width / 2,
|
|
1114
|
-
ly: py - r - 4,
|
|
1115
|
-
width,
|
|
1116
|
-
height: LABEL_H,
|
|
1117
|
-
external: false,
|
|
1118
|
-
textAnchor: "middle"
|
|
1119
|
-
};
|
|
1120
|
-
points.push({ point: p, px, py, r, label });
|
|
1121
|
-
if (p.category) categoriesSet.add(p.category);
|
|
1122
|
-
}
|
|
1123
|
-
resolveLabelCollisions(points, plot, ast.config.labelCollision);
|
|
1124
|
-
}
|
|
1125
|
-
return {
|
|
1126
|
-
canvasWidth,
|
|
1127
|
-
canvasHeight,
|
|
1128
|
-
plot,
|
|
1129
|
-
points,
|
|
1130
|
-
categories: [...categoriesSet]
|
|
1131
|
-
};
|
|
1132
|
-
}
|
|
1133
|
-
|
|
1134
|
-
// src/diagrams/matrix/renderer.ts
|
|
1135
|
-
var CATEGORY_COLORS = [
|
|
1136
|
-
"#2563eb",
|
|
1137
|
-
"#16a34a",
|
|
1138
|
-
"#dc2626",
|
|
1139
|
-
"#9333ea",
|
|
1140
|
-
"#ea580c",
|
|
1141
|
-
"#0891b2",
|
|
1142
|
-
"#ca8a04",
|
|
1143
|
-
"#db2777"
|
|
1144
|
-
];
|
|
1145
|
-
var QUADRANT_TINTS = [
|
|
1146
|
-
// Q1 TR, Q2 TL, Q3 BL, Q4 BR
|
|
1147
|
-
"#dbeafe",
|
|
1148
|
-
"#dcfce7",
|
|
1149
|
-
"#f3f4f6",
|
|
1150
|
-
"#fed7aa"
|
|
1151
|
-
];
|
|
1152
|
-
var HEAT_RAMP = [
|
|
1153
|
-
"#f0fdf4",
|
|
1154
|
-
"#bbf7d0",
|
|
1155
|
-
"#fde68a",
|
|
1156
|
-
"#fdba74",
|
|
1157
|
-
"#f87171",
|
|
1158
|
-
"#ef4444",
|
|
1159
|
-
"#b91c1c"
|
|
1160
|
-
];
|
|
1161
|
-
var CSS = `
|
|
1162
|
-
.sx-matrix { background: #fff; font-family: system-ui, -apple-system, "Segoe UI", sans-serif; }
|
|
1163
|
-
.sx-matrix-title { font: 600 16px sans-serif; fill: #111; }
|
|
1164
|
-
.sx-matrix-grid { stroke: #e5e7eb; stroke-width: 1; fill: none; }
|
|
1165
|
-
.sx-matrix-mid { stroke: #9ca3af; stroke-width: 1.2; stroke-dasharray: 4 3; fill: none; }
|
|
1166
|
-
.sx-matrix-plot-border { stroke: #374151; stroke-width: 1.2; fill: none; }
|
|
1167
|
-
.sx-matrix-axis-label { font: 500 12px sans-serif; fill: #374151; }
|
|
1168
|
-
.sx-matrix-axis-end { font: 500 11px sans-serif; fill: #6b7280; }
|
|
1169
|
-
.sx-matrix-quad-annot { font: 600 13px sans-serif; fill: #475569; opacity: 0.75; }
|
|
1170
|
-
.sx-matrix-quad-desc { font: 400 10.5px sans-serif; fill: #64748b; opacity: 0.85; }
|
|
1171
|
-
.sx-matrix-corr-header { font: 600 11.5px sans-serif; fill: #1f2937; text-anchor: middle; }
|
|
1172
|
-
.sx-matrix-corr-rowlabel { font: 500 11.5px sans-serif; fill: #1f2937; text-anchor: end; dominant-baseline: central; }
|
|
1173
|
-
.sx-matrix-corr-margin { font: 500 11px sans-serif; fill: #374151; text-anchor: middle; dominant-baseline: central; }
|
|
1174
|
-
.sx-matrix-corr-margin-best { font: 700 11.5px sans-serif; fill: #111; text-anchor: middle; dominant-baseline: central; }
|
|
1175
|
-
.sx-matrix-corr-grid { stroke: #d1d5db; stroke-width: 0.8; fill: none; }
|
|
1176
|
-
.sx-matrix-corr-rowbg-a { fill: #f0fdf4; }
|
|
1177
|
-
.sx-matrix-corr-rowbg-b { fill: #fff; }
|
|
1178
|
-
.sx-matrix-cell-label { font: 500 12px sans-serif; fill: #1f2937; text-anchor: middle; }
|
|
1179
|
-
.sx-matrix-cell-value { font: 600 18px sans-serif; fill: #111; text-anchor: middle; }
|
|
1180
|
-
.sx-matrix-bubble { stroke-width: 1.5; }
|
|
1181
|
-
.sx-matrix-label { font: 500 11px sans-serif; fill: #111827; text-anchor: middle; dominant-baseline: central; pointer-events: none; }
|
|
1182
|
-
.sx-matrix-leader { stroke: #94a3b8; stroke-width: 0.6; opacity: 0.7; fill: none; }
|
|
1183
|
-
.sx-matrix-legend-text { font: 500 11px sans-serif; fill: #374151; }
|
|
1184
|
-
.sx-matrix-offchart { fill: #ea580c; }
|
|
1185
|
-
`.trim();
|
|
1186
|
-
function axisArrow() {
|
|
1187
|
-
return chunkHDKDQAEQ_cjs.el(
|
|
1188
|
-
"marker",
|
|
1189
|
-
{
|
|
1190
|
-
id: "sx-matrix-arrow",
|
|
1191
|
-
viewBox: "0 0 10 10",
|
|
1192
|
-
refX: 8,
|
|
1193
|
-
refY: 5,
|
|
1194
|
-
markerWidth: 8,
|
|
1195
|
-
markerHeight: 8,
|
|
1196
|
-
orient: "auto-start-reverse"
|
|
1197
|
-
},
|
|
1198
|
-
[chunkHDKDQAEQ_cjs.el("path", { d: "M0,0 L10,5 L0,10 z", fill: "#374151" })]
|
|
1199
|
-
);
|
|
1200
|
-
}
|
|
1201
|
-
function bubbleFill(p, categories) {
|
|
1202
|
-
if (p.color) return p.color;
|
|
1203
|
-
if (p.category) {
|
|
1204
|
-
const idx = categories.indexOf(p.category);
|
|
1205
|
-
if (idx >= 0) return CATEGORY_COLORS[idx % CATEGORY_COLORS.length];
|
|
1206
|
-
}
|
|
1207
|
-
return "#2563eb";
|
|
1208
|
-
}
|
|
1209
|
-
function renderQuadrantBackground(ast, lay) {
|
|
1210
|
-
if (!ast.config.quadrantBg || ast.grid !== "2x2") return "";
|
|
1211
|
-
const { plot } = lay;
|
|
1212
|
-
const halfW = plot.w / 2;
|
|
1213
|
-
const halfH = plot.h / 2;
|
|
1214
|
-
const rects = [
|
|
1215
|
-
{ x: plot.x0 + halfW, y: plot.y0, w: halfW, h: halfH, fill: QUADRANT_TINTS[0] },
|
|
1216
|
-
{ x: plot.x0, y: plot.y0, w: halfW, h: halfH, fill: QUADRANT_TINTS[1] },
|
|
1217
|
-
{ x: plot.x0, y: plot.y0 + halfH, w: halfW, h: halfH, fill: QUADRANT_TINTS[2] },
|
|
1218
|
-
{ x: plot.x0 + halfW, y: plot.y0 + halfH, w: halfW, h: halfH, fill: QUADRANT_TINTS[3] }
|
|
1219
|
-
];
|
|
1220
|
-
return chunkHDKDQAEQ_cjs.group(
|
|
1221
|
-
{ id: "sx-matrix-quad-bg" },
|
|
1222
|
-
rects.map(
|
|
1223
|
-
(r) => chunkHDKDQAEQ_cjs.rect({ x: r.x, y: r.y, width: r.w, height: r.h, fill: r.fill, "fill-opacity": 0.55 })
|
|
1224
|
-
)
|
|
1225
|
-
);
|
|
1226
|
-
}
|
|
1227
|
-
function renderGrid(ast, lay) {
|
|
1228
|
-
if (!ast.config.gridLines) return "";
|
|
1229
|
-
if (ast.mode === "correlation") return "";
|
|
1230
|
-
const { plot } = lay;
|
|
1231
|
-
const lines = [];
|
|
1232
|
-
const cols = ast.cols;
|
|
1233
|
-
const rows = ast.rows;
|
|
1234
|
-
for (let i = 1; i < cols; i++) {
|
|
1235
|
-
const x = plot.x0 + plot.w * i / cols;
|
|
1236
|
-
const cls = cols === 2 && i === 1 ? "sx-matrix-mid" : "sx-matrix-grid";
|
|
1237
|
-
lines.push(chunkHDKDQAEQ_cjs.line({ x1: x, y1: plot.y0, x2: x, y2: plot.y0 + plot.h, class: cls }));
|
|
1238
|
-
}
|
|
1239
|
-
for (let j = 1; j < rows; j++) {
|
|
1240
|
-
const y = plot.y0 + plot.h * j / rows;
|
|
1241
|
-
const cls = rows === 2 && j === 1 ? "sx-matrix-mid" : "sx-matrix-grid";
|
|
1242
|
-
lines.push(chunkHDKDQAEQ_cjs.line({ x1: plot.x0, y1: y, x2: plot.x0 + plot.w, y2: y, class: cls }));
|
|
1243
|
-
}
|
|
1244
|
-
lines.push(
|
|
1245
|
-
chunkHDKDQAEQ_cjs.rect({
|
|
1246
|
-
x: plot.x0,
|
|
1247
|
-
y: plot.y0,
|
|
1248
|
-
width: plot.w,
|
|
1249
|
-
height: plot.h,
|
|
1250
|
-
class: "sx-matrix-plot-border",
|
|
1251
|
-
fill: "none"
|
|
1252
|
-
})
|
|
1253
|
-
);
|
|
1254
|
-
return chunkHDKDQAEQ_cjs.group({ id: "sx-matrix-grid" }, lines);
|
|
1255
|
-
}
|
|
1256
|
-
function shouldShowAxis(ast) {
|
|
1257
|
-
if (ast.config.showAxis === "on") return true;
|
|
1258
|
-
if (ast.config.showAxis === "off") return false;
|
|
1259
|
-
return ast.mode === "quadrant";
|
|
1260
|
-
}
|
|
1261
|
-
function renderAxes(ast, lay) {
|
|
1262
|
-
if (!shouldShowAxis(ast)) return "";
|
|
1263
|
-
const { plot } = lay;
|
|
1264
|
-
const els = [];
|
|
1265
|
-
const marker = ast.config.axisArrows ? { "marker-end": "url(#sx-matrix-arrow)" } : {};
|
|
1266
|
-
const xy = plot.y0 + plot.h + 14;
|
|
1267
|
-
const yx = plot.x0 - 14;
|
|
1268
|
-
els.push(
|
|
1269
|
-
chunkHDKDQAEQ_cjs.line({
|
|
1270
|
-
x1: plot.x0,
|
|
1271
|
-
y1: xy,
|
|
1272
|
-
x2: plot.x0 + plot.w,
|
|
1273
|
-
y2: xy,
|
|
1274
|
-
stroke: "#374151",
|
|
1275
|
-
"stroke-width": 1.2,
|
|
1276
|
-
...marker
|
|
1277
|
-
})
|
|
1278
|
-
);
|
|
1279
|
-
els.push(
|
|
1280
|
-
chunkHDKDQAEQ_cjs.line({
|
|
1281
|
-
x1: yx,
|
|
1282
|
-
y1: plot.y0 + plot.h,
|
|
1283
|
-
x2: yx,
|
|
1284
|
-
y2: plot.y0,
|
|
1285
|
-
stroke: "#374151",
|
|
1286
|
-
"stroke-width": 1.2,
|
|
1287
|
-
...marker
|
|
1288
|
-
})
|
|
1289
|
-
);
|
|
1290
|
-
if (ast.xAxis.low) {
|
|
1291
|
-
els.push(
|
|
1292
|
-
chunkHDKDQAEQ_cjs.text(
|
|
1293
|
-
{ x: plot.x0, y: xy + 20, class: "sx-matrix-axis-end", "text-anchor": "start" },
|
|
1294
|
-
ast.xAxis.low
|
|
1295
|
-
)
|
|
1296
|
-
);
|
|
1297
|
-
}
|
|
1298
|
-
if (ast.xAxis.high) {
|
|
1299
|
-
els.push(
|
|
1300
|
-
chunkHDKDQAEQ_cjs.text(
|
|
1301
|
-
{ x: plot.x0 + plot.w, y: xy + 20, class: "sx-matrix-axis-end", "text-anchor": "end" },
|
|
1302
|
-
ast.xAxis.high
|
|
1303
|
-
)
|
|
1304
|
-
);
|
|
1305
|
-
}
|
|
1306
|
-
if (ast.yAxis.low) {
|
|
1307
|
-
els.push(
|
|
1308
|
-
chunkHDKDQAEQ_cjs.text(
|
|
1309
|
-
{
|
|
1310
|
-
x: yx - 24,
|
|
1311
|
-
y: plot.y0 + plot.h,
|
|
1312
|
-
class: "sx-matrix-axis-end",
|
|
1313
|
-
"text-anchor": "end",
|
|
1314
|
-
transform: `rotate(-90 ${yx - 24} ${plot.y0 + plot.h})`
|
|
1315
|
-
},
|
|
1316
|
-
ast.yAxis.low
|
|
1317
|
-
)
|
|
1318
|
-
);
|
|
1319
|
-
}
|
|
1320
|
-
if (ast.yAxis.high) {
|
|
1321
|
-
els.push(
|
|
1322
|
-
chunkHDKDQAEQ_cjs.text(
|
|
1323
|
-
{
|
|
1324
|
-
x: yx - 24,
|
|
1325
|
-
y: plot.y0,
|
|
1326
|
-
class: "sx-matrix-axis-end",
|
|
1327
|
-
"text-anchor": "start",
|
|
1328
|
-
transform: `rotate(-90 ${yx - 24} ${plot.y0})`
|
|
1329
|
-
},
|
|
1330
|
-
ast.yAxis.high
|
|
1331
|
-
)
|
|
1332
|
-
);
|
|
1333
|
-
}
|
|
1334
|
-
return chunkHDKDQAEQ_cjs.group({ id: "sx-matrix-axes" }, els);
|
|
1335
|
-
}
|
|
1336
|
-
function renderQuadAnnotations(ast, lay) {
|
|
1337
|
-
if (!ast.config.quadrantAnnotations || ast.grid !== "2x2" || ast.annotations.length === 0) return "";
|
|
1338
|
-
const { plot } = lay;
|
|
1339
|
-
plot.w / 2;
|
|
1340
|
-
plot.h / 2;
|
|
1341
|
-
const padding = 14;
|
|
1342
|
-
const positions = {
|
|
1343
|
-
1: { x: plot.x0 + plot.w - padding, y: plot.y0 + padding + 14, anchor: "end" },
|
|
1344
|
-
// TR
|
|
1345
|
-
2: { x: plot.x0 + padding, y: plot.y0 + padding + 14, anchor: "start" },
|
|
1346
|
-
// TL
|
|
1347
|
-
3: { x: plot.x0 + padding, y: plot.y0 + plot.h - padding, anchor: "start" },
|
|
1348
|
-
// BL
|
|
1349
|
-
4: { x: plot.x0 + plot.w - padding, y: plot.y0 + plot.h - padding, anchor: "end" }
|
|
1350
|
-
// BR
|
|
1351
|
-
};
|
|
1352
|
-
const nodes = [];
|
|
1353
|
-
for (const a of ast.annotations) {
|
|
1354
|
-
const pos = positions[a.q];
|
|
1355
|
-
const growsUp = a.q === 3 || a.q === 4;
|
|
1356
|
-
const descLines = a.description ? wrapLabel(a.description, 28) : [];
|
|
1357
|
-
const labelY = growsUp && descLines.length > 0 ? pos.y - descLines.length * 12 : pos.y;
|
|
1358
|
-
nodes.push(
|
|
1359
|
-
chunkHDKDQAEQ_cjs.text(
|
|
1360
|
-
{ x: pos.x, y: labelY, class: "sx-matrix-quad-annot", "text-anchor": pos.anchor },
|
|
1361
|
-
a.label
|
|
1362
|
-
)
|
|
1363
|
-
);
|
|
1364
|
-
for (let i = 0; i < descLines.length; i++) {
|
|
1365
|
-
nodes.push(
|
|
1366
|
-
chunkHDKDQAEQ_cjs.text(
|
|
1367
|
-
{
|
|
1368
|
-
x: pos.x,
|
|
1369
|
-
y: labelY + 14 + i * 12,
|
|
1370
|
-
class: "sx-matrix-quad-desc",
|
|
1371
|
-
"text-anchor": pos.anchor
|
|
1372
|
-
},
|
|
1373
|
-
descLines[i]
|
|
1374
|
-
)
|
|
1375
|
-
);
|
|
1376
|
-
}
|
|
1377
|
-
}
|
|
1378
|
-
return chunkHDKDQAEQ_cjs.group({ id: "sx-matrix-quad-annot" }, nodes);
|
|
1379
|
-
}
|
|
1380
|
-
function wrapLabel(text2, maxChars) {
|
|
1381
|
-
const words = text2.split(/\s+/);
|
|
1382
|
-
const out = [];
|
|
1383
|
-
let cur = "";
|
|
1384
|
-
for (const w of words) {
|
|
1385
|
-
if ((cur + " " + w).trim().length > maxChars) {
|
|
1386
|
-
if (cur) out.push(cur);
|
|
1387
|
-
cur = w;
|
|
1388
|
-
} else {
|
|
1389
|
-
cur = (cur ? cur + " " : "") + w;
|
|
1390
|
-
}
|
|
1391
|
-
}
|
|
1392
|
-
if (cur) out.push(cur);
|
|
1393
|
-
return out;
|
|
1394
|
-
}
|
|
1395
|
-
function render3x3CellLabels(ast, lay) {
|
|
1396
|
-
if (ast.grid !== "3x3" || ast.cellLabels.length === 0) return "";
|
|
1397
|
-
const { plot } = lay;
|
|
1398
|
-
const cellW = plot.w / ast.cols;
|
|
1399
|
-
const cellH = plot.h / ast.rows;
|
|
1400
|
-
const nodes = ast.cellLabels.map((cl) => {
|
|
1401
|
-
const cx = plot.x0 + cellW * (cl.col + 0.5);
|
|
1402
|
-
const cy = plot.y0 + cellH * (ast.rows - 1 - cl.row + 0.5);
|
|
1403
|
-
return chunkHDKDQAEQ_cjs.text({ x: cx, y: cy, class: "sx-matrix-cell-label" }, cl.label);
|
|
1404
|
-
});
|
|
1405
|
-
return chunkHDKDQAEQ_cjs.group({ id: "sx-matrix-cell-labels" }, nodes);
|
|
1406
|
-
}
|
|
1407
|
-
function renderHeatmap(ast, lay) {
|
|
1408
|
-
if (ast.mode !== "heatmap") return "";
|
|
1409
|
-
const { plot } = lay;
|
|
1410
|
-
const cellW = plot.w / ast.cols;
|
|
1411
|
-
const cellH = plot.h / ast.rows;
|
|
1412
|
-
const maxVal = Math.max(
|
|
1413
|
-
1,
|
|
1414
|
-
...ast.cells.map((c) => c.value ?? (c.col + 1) * (c.row + 1))
|
|
1415
|
-
);
|
|
1416
|
-
const cells = [];
|
|
1417
|
-
for (let col = 0; col < ast.cols; col++) {
|
|
1418
|
-
for (let row = 0; row < ast.rows; row++) {
|
|
1419
|
-
const found = ast.cells.find((c) => c.col === col && c.row === row);
|
|
1420
|
-
const value = found?.value ?? (col + 1) * (row + 1);
|
|
1421
|
-
const ratio = Math.min(1, value / maxVal);
|
|
1422
|
-
const idx = Math.min(HEAT_RAMP.length - 1, Math.floor(ratio * HEAT_RAMP.length));
|
|
1423
|
-
const color = HEAT_RAMP[idx];
|
|
1424
|
-
const x = plot.x0 + col * cellW;
|
|
1425
|
-
const y = plot.y0 + (ast.rows - 1 - row) * cellH;
|
|
1426
|
-
cells.push(
|
|
1427
|
-
chunkHDKDQAEQ_cjs.rect({
|
|
1428
|
-
x,
|
|
1429
|
-
y,
|
|
1430
|
-
width: cellW,
|
|
1431
|
-
height: cellH,
|
|
1432
|
-
fill: color,
|
|
1433
|
-
stroke: "#fff",
|
|
1434
|
-
"stroke-width": 2
|
|
1435
|
-
})
|
|
1436
|
-
);
|
|
1437
|
-
}
|
|
1438
|
-
}
|
|
1439
|
-
if (ast.rowLabels) {
|
|
1440
|
-
for (let row = 0; row < ast.rows; row++) {
|
|
1441
|
-
const lbl = ast.rowLabels[row];
|
|
1442
|
-
if (!lbl) continue;
|
|
1443
|
-
const y = plot.y0 + (ast.rows - 1 - row + 0.5) * cellH;
|
|
1444
|
-
cells.push(
|
|
1445
|
-
chunkHDKDQAEQ_cjs.text(
|
|
1446
|
-
{
|
|
1447
|
-
x: plot.x0 - 8,
|
|
1448
|
-
y,
|
|
1449
|
-
class: "sx-matrix-axis-end",
|
|
1450
|
-
"text-anchor": "end",
|
|
1451
|
-
"dominant-baseline": "central"
|
|
1452
|
-
},
|
|
1453
|
-
lbl
|
|
1454
|
-
)
|
|
1455
|
-
);
|
|
1456
|
-
}
|
|
1457
|
-
}
|
|
1458
|
-
if (ast.colLabels) {
|
|
1459
|
-
for (let col = 0; col < ast.cols; col++) {
|
|
1460
|
-
const lbl = ast.colLabels[col];
|
|
1461
|
-
if (!lbl) continue;
|
|
1462
|
-
const x = plot.x0 + (col + 0.5) * cellW;
|
|
1463
|
-
cells.push(
|
|
1464
|
-
chunkHDKDQAEQ_cjs.text(
|
|
1465
|
-
{
|
|
1466
|
-
x,
|
|
1467
|
-
y: plot.y0 + plot.h + 16,
|
|
1468
|
-
class: "sx-matrix-axis-end",
|
|
1469
|
-
"text-anchor": "middle"
|
|
1470
|
-
},
|
|
1471
|
-
lbl
|
|
1472
|
-
)
|
|
1473
|
-
);
|
|
1474
|
-
}
|
|
1475
|
-
}
|
|
1476
|
-
for (const cl of ast.cellLabels) {
|
|
1477
|
-
const cx = plot.x0 + cellW * (cl.col + 0.5);
|
|
1478
|
-
const cy = plot.y0 + cellH * (ast.rows - 1 - cl.row + 0.5);
|
|
1479
|
-
const words = cl.label.split(/\s+/);
|
|
1480
|
-
const lines = [];
|
|
1481
|
-
let cur = "";
|
|
1482
|
-
for (const w of words) {
|
|
1483
|
-
if ((cur + " " + w).trim().length > 14) {
|
|
1484
|
-
if (cur) lines.push(cur);
|
|
1485
|
-
cur = w;
|
|
1486
|
-
} else {
|
|
1487
|
-
cur = (cur ? cur + " " : "") + w;
|
|
1488
|
-
}
|
|
1489
|
-
}
|
|
1490
|
-
if (cur) lines.push(cur);
|
|
1491
|
-
const lineH = 13;
|
|
1492
|
-
const startY = cy - (lines.length - 1) * lineH / 2;
|
|
1493
|
-
for (let i = 0; i < lines.length; i++) {
|
|
1494
|
-
cells.push(
|
|
1495
|
-
chunkHDKDQAEQ_cjs.text(
|
|
1496
|
-
{
|
|
1497
|
-
x: cx,
|
|
1498
|
-
y: startY + i * lineH,
|
|
1499
|
-
class: "sx-matrix-cell-label",
|
|
1500
|
-
"dominant-baseline": "central"
|
|
1501
|
-
},
|
|
1502
|
-
lines[i]
|
|
1503
|
-
)
|
|
1504
|
-
);
|
|
1505
|
-
}
|
|
1506
|
-
}
|
|
1507
|
-
return chunkHDKDQAEQ_cjs.group({ id: "sx-matrix-heatmap" }, cells);
|
|
1508
|
-
}
|
|
1509
|
-
var DOT_COLORS = {
|
|
1510
|
-
strong: "#16a34a",
|
|
1511
|
-
medium: "#86efac",
|
|
1512
|
-
weak: "#9ca3af"
|
|
1513
|
-
};
|
|
1514
|
-
function levelFromValue(v) {
|
|
1515
|
-
if (v >= 3) return "strong";
|
|
1516
|
-
if (v >= 2) return "medium";
|
|
1517
|
-
return "weak";
|
|
1518
|
-
}
|
|
1519
|
-
function renderCorrelation(ast, lay) {
|
|
1520
|
-
if (ast.mode !== "correlation") return "";
|
|
1521
|
-
const { plot } = lay;
|
|
1522
|
-
const marginCols = ast.config.margins ? 2 : 0;
|
|
1523
|
-
const marginRows = ast.config.margins ? 2 : 0;
|
|
1524
|
-
const cellW = plot.w / (ast.cols + marginCols);
|
|
1525
|
-
const cellH = plot.h / (ast.rows + marginRows);
|
|
1526
|
-
const gridW = cellW * ast.cols;
|
|
1527
|
-
const gridH = cellH * ast.rows;
|
|
1528
|
-
const nodes = [];
|
|
1529
|
-
for (let row = 0; row < ast.rows; row++) {
|
|
1530
|
-
const y = plot.y0 + (ast.rows - 1 - row) * cellH;
|
|
1531
|
-
nodes.push(
|
|
1532
|
-
chunkHDKDQAEQ_cjs.rect({
|
|
1533
|
-
x: plot.x0,
|
|
1534
|
-
y,
|
|
1535
|
-
width: gridW,
|
|
1536
|
-
height: cellH,
|
|
1537
|
-
class: row % 2 === 0 ? "sx-matrix-corr-rowbg-a" : "sx-matrix-corr-rowbg-b"
|
|
1538
|
-
})
|
|
1539
|
-
);
|
|
1540
|
-
}
|
|
1541
|
-
for (let i = 0; i <= ast.cols; i++) {
|
|
1542
|
-
const x = plot.x0 + i * cellW;
|
|
1543
|
-
nodes.push(chunkHDKDQAEQ_cjs.line({ x1: x, y1: plot.y0, x2: x, y2: plot.y0 + gridH, class: "sx-matrix-corr-grid" }));
|
|
1544
|
-
}
|
|
1545
|
-
for (let j = 0; j <= ast.rows; j++) {
|
|
1546
|
-
const y = plot.y0 + j * cellH;
|
|
1547
|
-
nodes.push(chunkHDKDQAEQ_cjs.line({ x1: plot.x0, y1: y, x2: plot.x0 + gridW, y2: y, class: "sx-matrix-corr-grid" }));
|
|
1548
|
-
}
|
|
1549
|
-
const dotR = Math.max(4, Math.min(cellW, cellH) * 0.28);
|
|
1550
|
-
const rowSums = new Array(ast.rows).fill(0);
|
|
1551
|
-
const colSums = new Array(ast.cols).fill(0);
|
|
1552
|
-
for (const c of ast.cells) {
|
|
1553
|
-
if (c.col < 0 || c.col >= ast.cols || c.row < 0 || c.row >= ast.rows) continue;
|
|
1554
|
-
const v = c.value ?? (c.level ? c.level === "strong" ? 3 : c.level === "medium" ? 2 : 1 : 0);
|
|
1555
|
-
if (v <= 0) continue;
|
|
1556
|
-
rowSums[c.row] += v;
|
|
1557
|
-
colSums[c.col] += v;
|
|
1558
|
-
const lvl = c.level ?? levelFromValue(v);
|
|
1559
|
-
const cx = plot.x0 + (c.col + 0.5) * cellW;
|
|
1560
|
-
const cy = plot.y0 + (ast.rows - 1 - c.row + 0.5) * cellH;
|
|
1561
|
-
nodes.push(
|
|
1562
|
-
chunkHDKDQAEQ_cjs.circle({
|
|
1563
|
-
cx,
|
|
1564
|
-
cy,
|
|
1565
|
-
r: dotR,
|
|
1566
|
-
fill: DOT_COLORS[lvl],
|
|
1567
|
-
stroke: DOT_COLORS[lvl],
|
|
1568
|
-
"stroke-width": 1
|
|
1569
|
-
})
|
|
1570
|
-
);
|
|
1571
|
-
}
|
|
1572
|
-
if (ast.colLabels) {
|
|
1573
|
-
for (let col = 0; col < ast.cols; col++) {
|
|
1574
|
-
const label = ast.colLabels[col];
|
|
1575
|
-
if (!label) continue;
|
|
1576
|
-
const cx = plot.x0 + (col + 0.5) * cellW;
|
|
1577
|
-
const lines = wrapLabel(label, 10);
|
|
1578
|
-
const startY = plot.y0 - 8 - (lines.length - 1) * 12;
|
|
1579
|
-
for (let i = 0; i < lines.length; i++) {
|
|
1580
|
-
nodes.push(
|
|
1581
|
-
chunkHDKDQAEQ_cjs.text(
|
|
1582
|
-
{ x: cx, y: startY + i * 12, class: "sx-matrix-corr-header" },
|
|
1583
|
-
lines[i]
|
|
1584
|
-
)
|
|
1585
|
-
);
|
|
1586
|
-
}
|
|
1587
|
-
}
|
|
1588
|
-
}
|
|
1589
|
-
if (ast.rowLabels) {
|
|
1590
|
-
for (let row = 0; row < ast.rows; row++) {
|
|
1591
|
-
const label = ast.rowLabels[row];
|
|
1592
|
-
if (!label) continue;
|
|
1593
|
-
const y = plot.y0 + (ast.rows - 1 - row + 0.5) * cellH;
|
|
1594
|
-
nodes.push(
|
|
1595
|
-
chunkHDKDQAEQ_cjs.text({ x: plot.x0 - 8, y, class: "sx-matrix-corr-rowlabel" }, label)
|
|
1596
|
-
);
|
|
1597
|
-
}
|
|
1598
|
-
}
|
|
1599
|
-
if (ast.config.margins) {
|
|
1600
|
-
const rowRanks = rankOf(rowSums);
|
|
1601
|
-
const colRanks = rankOf(colSums);
|
|
1602
|
-
const bestRow = rowSums.length > 0 ? Math.max(...rowSums) : 0;
|
|
1603
|
-
const bestCol = colSums.length > 0 ? Math.max(...colSums) : 0;
|
|
1604
|
-
const scoreColX = plot.x0 + gridW + cellW * 0.5;
|
|
1605
|
-
const rankColX = plot.x0 + gridW + cellW * 1.5;
|
|
1606
|
-
nodes.push(chunkHDKDQAEQ_cjs.text({ x: scoreColX, y: plot.y0 - 8, class: "sx-matrix-corr-header" }, "Score"));
|
|
1607
|
-
nodes.push(chunkHDKDQAEQ_cjs.text({ x: rankColX, y: plot.y0 - 8, class: "sx-matrix-corr-header" }, "Rank"));
|
|
1608
|
-
for (let row = 0; row < ast.rows; row++) {
|
|
1609
|
-
const y = plot.y0 + (ast.rows - 1 - row + 0.5) * cellH;
|
|
1610
|
-
const sum = rowSums[row];
|
|
1611
|
-
const rank = rowRanks[row];
|
|
1612
|
-
const cls = sum === bestRow && sum > 0 ? "sx-matrix-corr-margin-best" : "sx-matrix-corr-margin";
|
|
1613
|
-
nodes.push(chunkHDKDQAEQ_cjs.text({ x: scoreColX, y, class: cls }, String(sum)));
|
|
1614
|
-
nodes.push(
|
|
1615
|
-
chunkHDKDQAEQ_cjs.text({ x: rankColX, y, class: rank === 1 ? "sx-matrix-corr-margin-best" : "sx-matrix-corr-margin" }, String(rank))
|
|
1616
|
-
);
|
|
1617
|
-
}
|
|
1618
|
-
const scoreRowY = plot.y0 + gridH + cellH * 0.5;
|
|
1619
|
-
const rankRowY = plot.y0 + gridH + cellH * 1.5;
|
|
1620
|
-
nodes.push(
|
|
1621
|
-
chunkHDKDQAEQ_cjs.text(
|
|
1622
|
-
{ x: plot.x0 - 8, y: scoreRowY, class: "sx-matrix-corr-rowlabel" },
|
|
1623
|
-
"Score"
|
|
1624
|
-
)
|
|
1625
|
-
);
|
|
1626
|
-
nodes.push(
|
|
1627
|
-
chunkHDKDQAEQ_cjs.text(
|
|
1628
|
-
{ x: plot.x0 - 8, y: rankRowY, class: "sx-matrix-corr-rowlabel" },
|
|
1629
|
-
"Rank"
|
|
1630
|
-
)
|
|
1631
|
-
);
|
|
1632
|
-
for (let col = 0; col < ast.cols; col++) {
|
|
1633
|
-
const cx = plot.x0 + (col + 0.5) * cellW;
|
|
1634
|
-
const sum = colSums[col];
|
|
1635
|
-
const rank = colRanks[col];
|
|
1636
|
-
nodes.push(
|
|
1637
|
-
chunkHDKDQAEQ_cjs.text(
|
|
1638
|
-
{
|
|
1639
|
-
x: cx,
|
|
1640
|
-
y: scoreRowY,
|
|
1641
|
-
class: sum === bestCol && sum > 0 ? "sx-matrix-corr-margin-best" : "sx-matrix-corr-margin"
|
|
1642
|
-
},
|
|
1643
|
-
String(sum)
|
|
1644
|
-
)
|
|
1645
|
-
);
|
|
1646
|
-
nodes.push(
|
|
1647
|
-
chunkHDKDQAEQ_cjs.text(
|
|
1648
|
-
{
|
|
1649
|
-
x: cx,
|
|
1650
|
-
y: rankRowY,
|
|
1651
|
-
class: rank === 1 ? "sx-matrix-corr-margin-best" : "sx-matrix-corr-margin"
|
|
1652
|
-
},
|
|
1653
|
-
String(rank)
|
|
1654
|
-
)
|
|
1655
|
-
);
|
|
1656
|
-
}
|
|
1657
|
-
}
|
|
1658
|
-
return chunkHDKDQAEQ_cjs.group({ id: "sx-matrix-correlation" }, nodes);
|
|
1659
|
-
}
|
|
1660
|
-
function rankOf(vals) {
|
|
1661
|
-
const sorted = [...vals].map((v, i) => ({ v, i })).sort((a, b) => b.v - a.v);
|
|
1662
|
-
const ranks = new Array(vals.length).fill(0);
|
|
1663
|
-
let prev = -Infinity;
|
|
1664
|
-
let rank = 0;
|
|
1665
|
-
let seen = 0;
|
|
1666
|
-
for (const e of sorted) {
|
|
1667
|
-
seen++;
|
|
1668
|
-
if (e.v !== prev) {
|
|
1669
|
-
rank = seen;
|
|
1670
|
-
prev = e.v;
|
|
1671
|
-
}
|
|
1672
|
-
ranks[e.i] = rank;
|
|
1673
|
-
}
|
|
1674
|
-
return ranks;
|
|
1675
|
-
}
|
|
1676
|
-
function renderCorrelationLegend(ast, lay) {
|
|
1677
|
-
if (ast.mode !== "correlation") return "";
|
|
1678
|
-
const xBase = lay.plot.x0 + lay.plot.w + 20;
|
|
1679
|
-
const yBase = lay.plot.y0 + 8;
|
|
1680
|
-
const items = [
|
|
1681
|
-
["strong", "Strong (3)"],
|
|
1682
|
-
["medium", "Medium (2)"],
|
|
1683
|
-
["weak", "Weak (1)"]
|
|
1684
|
-
];
|
|
1685
|
-
const rows = items.map(
|
|
1686
|
-
(it, i) => chunkHDKDQAEQ_cjs.group({ transform: `translate(${xBase}, ${yBase + i * 18})` }, [
|
|
1687
|
-
chunkHDKDQAEQ_cjs.circle({ cx: 6, cy: 6, r: 5, fill: DOT_COLORS[it[0]], stroke: DOT_COLORS[it[0]] }),
|
|
1688
|
-
chunkHDKDQAEQ_cjs.text({ x: 18, y: 10, class: "sx-matrix-legend-text" }, it[1])
|
|
1689
|
-
])
|
|
1690
|
-
);
|
|
1691
|
-
return chunkHDKDQAEQ_cjs.group({ id: "sx-matrix-corr-legend" }, rows);
|
|
1692
|
-
}
|
|
1693
|
-
function renderPoints(ast, lay) {
|
|
1694
|
-
if (ast.mode !== "quadrant") return "";
|
|
1695
|
-
const nodes = [];
|
|
1696
|
-
for (const p of lay.points) {
|
|
1697
|
-
nodes.push(renderOnePoint(p, lay.categories));
|
|
1698
|
-
}
|
|
1699
|
-
return chunkHDKDQAEQ_cjs.group({ id: "sx-matrix-points" }, nodes);
|
|
1700
|
-
}
|
|
1701
|
-
function renderOnePoint(pl, categories) {
|
|
1702
|
-
const p = pl.point;
|
|
1703
|
-
const color = bubbleFill(p, categories);
|
|
1704
|
-
const shape = p.shape ?? "circle";
|
|
1705
|
-
let shapeEl;
|
|
1706
|
-
const stroke = p.highlight ? "#111" : color;
|
|
1707
|
-
const strokeWidth = p.highlight ? 2.2 : 1.5;
|
|
1708
|
-
const fillOpacity = p.size !== void 0 ? 0.45 : 0.75;
|
|
1709
|
-
if (shape === "circle") {
|
|
1710
|
-
shapeEl = chunkHDKDQAEQ_cjs.circle({
|
|
1711
|
-
cx: pl.px,
|
|
1712
|
-
cy: pl.py,
|
|
1713
|
-
r: pl.r,
|
|
1714
|
-
fill: color,
|
|
1715
|
-
"fill-opacity": fillOpacity,
|
|
1716
|
-
stroke,
|
|
1717
|
-
"stroke-width": strokeWidth,
|
|
1718
|
-
class: "sx-matrix-bubble"
|
|
1719
|
-
});
|
|
1720
|
-
} else if (shape === "square") {
|
|
1721
|
-
shapeEl = chunkHDKDQAEQ_cjs.rect({
|
|
1722
|
-
x: pl.px - pl.r,
|
|
1723
|
-
y: pl.py - pl.r,
|
|
1724
|
-
width: pl.r * 2,
|
|
1725
|
-
height: pl.r * 2,
|
|
1726
|
-
fill: color,
|
|
1727
|
-
"fill-opacity": fillOpacity,
|
|
1728
|
-
stroke,
|
|
1729
|
-
"stroke-width": strokeWidth,
|
|
1730
|
-
class: "sx-matrix-bubble"
|
|
1731
|
-
});
|
|
1732
|
-
} else if (shape === "diamond") {
|
|
1733
|
-
const r = pl.r;
|
|
1734
|
-
shapeEl = chunkHDKDQAEQ_cjs.polygon({
|
|
1735
|
-
points: `${pl.px},${pl.py - r} ${pl.px + r},${pl.py} ${pl.px},${pl.py + r} ${pl.px - r},${pl.py}`,
|
|
1736
|
-
fill: color,
|
|
1737
|
-
"fill-opacity": fillOpacity,
|
|
1738
|
-
stroke,
|
|
1739
|
-
"stroke-width": strokeWidth,
|
|
1740
|
-
class: "sx-matrix-bubble"
|
|
1741
|
-
});
|
|
1742
|
-
} else {
|
|
1743
|
-
const r = pl.r;
|
|
1744
|
-
shapeEl = chunkHDKDQAEQ_cjs.polygon({
|
|
1745
|
-
points: `${pl.px},${pl.py - r} ${pl.px + r},${pl.py + r * 0.8} ${pl.px - r},${pl.py + r * 0.8}`,
|
|
1746
|
-
fill: color,
|
|
1747
|
-
"fill-opacity": fillOpacity,
|
|
1748
|
-
stroke,
|
|
1749
|
-
"stroke-width": strokeWidth,
|
|
1750
|
-
class: "sx-matrix-bubble"
|
|
1751
|
-
});
|
|
1752
|
-
}
|
|
1753
|
-
const leader = pl.label.external ? chunkHDKDQAEQ_cjs.line({
|
|
1754
|
-
x1: pl.px,
|
|
1755
|
-
y1: pl.py,
|
|
1756
|
-
x2: pl.label.lx,
|
|
1757
|
-
y2: pl.label.ly,
|
|
1758
|
-
class: "sx-matrix-leader"
|
|
1759
|
-
}) : "";
|
|
1760
|
-
const label = chunkHDKDQAEQ_cjs.text(
|
|
1761
|
-
{ x: pl.label.lx, y: pl.label.ly, class: "sx-matrix-label" },
|
|
1762
|
-
pl.label.text
|
|
1763
|
-
);
|
|
1764
|
-
let badge = "";
|
|
1765
|
-
if (p.offChart) {
|
|
1766
|
-
const bx = pl.px;
|
|
1767
|
-
const by = pl.py;
|
|
1768
|
-
badge = chunkHDKDQAEQ_cjs.text(
|
|
1769
|
-
{ x: bx + pl.r + 4, y: by - pl.r - 2, class: "sx-matrix-offchart", "font-size": 14, "font-weight": 700 },
|
|
1770
|
-
"\u2197"
|
|
1771
|
-
);
|
|
1772
|
-
}
|
|
1773
|
-
const titleStr = p.note ? `${p.label} \xB7 (${p.origX ?? p.x}, ${p.origY ?? p.y}) \u2014 ${p.note}` : `${p.label} \xB7 (${(p.origX ?? p.x).toFixed(2)}, ${(p.origY ?? p.y).toFixed(2)})${p.size !== void 0 ? ` \xB7 size ${p.size}` : ""}`;
|
|
1774
|
-
return chunkHDKDQAEQ_cjs.group(
|
|
1775
|
-
{
|
|
1776
|
-
class: "sx-matrix-point",
|
|
1777
|
-
"data-point-id": p.id,
|
|
1778
|
-
"data-label": p.label,
|
|
1779
|
-
...p.category ? { "data-category": p.category } : {}
|
|
1780
|
-
},
|
|
1781
|
-
[chunkHDKDQAEQ_cjs.title(titleStr), shapeEl, leader, label, badge].filter((s) => s.length > 0)
|
|
1782
|
-
);
|
|
1783
|
-
}
|
|
1784
|
-
function renderLegend(ast, lay) {
|
|
1785
|
-
if (ast.config.legendPosition === "none") return "";
|
|
1786
|
-
if (ast.mode === "heatmap") {
|
|
1787
|
-
const x = lay.plot.x0 + lay.plot.w - 220;
|
|
1788
|
-
const y = lay.plot.y0 + lay.plot.h + 40;
|
|
1789
|
-
const w = 210;
|
|
1790
|
-
const h = 10;
|
|
1791
|
-
const stops = HEAT_RAMP.map(
|
|
1792
|
-
(c, i) => chunkHDKDQAEQ_cjs.el("stop", { offset: `${i / (HEAT_RAMP.length - 1) * 100}%`, "stop-color": c })
|
|
1793
|
-
);
|
|
1794
|
-
const grad = chunkHDKDQAEQ_cjs.el(
|
|
1795
|
-
"linearGradient",
|
|
1796
|
-
{ id: "sx-matrix-heatgrad", x1: "0%", x2: "100%" },
|
|
1797
|
-
stops
|
|
1798
|
-
);
|
|
1799
|
-
return chunkHDKDQAEQ_cjs.group({ id: "sx-matrix-legend" }, [
|
|
1800
|
-
chunkHDKDQAEQ_cjs.el("defs", {}, [grad]),
|
|
1801
|
-
chunkHDKDQAEQ_cjs.rect({ x, y, width: w, height: h, fill: "url(#sx-matrix-heatgrad)", stroke: "#d1d5db" }),
|
|
1802
|
-
chunkHDKDQAEQ_cjs.text({ x, y: y - 4, class: "sx-matrix-legend-text", "text-anchor": "start" }, "Low"),
|
|
1803
|
-
chunkHDKDQAEQ_cjs.text(
|
|
1804
|
-
{ x: x + w, y: y - 4, class: "sx-matrix-legend-text", "text-anchor": "end" },
|
|
1805
|
-
"High"
|
|
1806
|
-
)
|
|
1807
|
-
]);
|
|
1808
|
-
}
|
|
1809
|
-
if (lay.categories.length === 0) return "";
|
|
1810
|
-
const xBase = lay.plot.x0 + lay.plot.w + 12;
|
|
1811
|
-
const yBase = lay.plot.y0 + 8;
|
|
1812
|
-
const rows = lay.categories.map((cat, i) => {
|
|
1813
|
-
const color = CATEGORY_COLORS[i % CATEGORY_COLORS.length];
|
|
1814
|
-
return chunkHDKDQAEQ_cjs.group({ transform: `translate(${xBase}, ${yBase + i * 18})` }, [
|
|
1815
|
-
chunkHDKDQAEQ_cjs.circle({ cx: 6, cy: 6, r: 5, fill: color, "fill-opacity": 0.7, stroke: color }),
|
|
1816
|
-
chunkHDKDQAEQ_cjs.text({ x: 18, y: 10, class: "sx-matrix-legend-text" }, cat)
|
|
1817
|
-
]);
|
|
1818
|
-
});
|
|
1819
|
-
return chunkHDKDQAEQ_cjs.group({ id: "sx-matrix-legend" }, rows);
|
|
1820
|
-
}
|
|
1821
|
-
function renderTitle(ast, lay) {
|
|
1822
|
-
if (!ast.title) return "";
|
|
1823
|
-
return chunkHDKDQAEQ_cjs.text(
|
|
1824
|
-
{ x: lay.canvasWidth / 2, y: 28, class: "sx-matrix-title", "text-anchor": "middle" },
|
|
1825
|
-
ast.title
|
|
1826
|
-
);
|
|
1827
|
-
}
|
|
1828
|
-
function renderMatrixAST(ast) {
|
|
1829
|
-
const lay = layoutMatrix(ast);
|
|
1830
|
-
const needsLegendSpace = lay.categories.length > 0 || ast.mode === "correlation";
|
|
1831
|
-
const extraWidth = needsLegendSpace && lay.plot.x0 + lay.plot.w + 140 > lay.canvasWidth ? 160 : 0;
|
|
1832
|
-
const canvasWidth = lay.canvasWidth + extraWidth;
|
|
1833
|
-
const body = [
|
|
1834
|
-
renderTitle(ast, lay),
|
|
1835
|
-
renderQuadrantBackground(ast, lay),
|
|
1836
|
-
renderGrid(ast, lay),
|
|
1837
|
-
renderQuadAnnotations(ast, lay),
|
|
1838
|
-
render3x3CellLabels(ast, lay),
|
|
1839
|
-
renderHeatmap(ast, lay),
|
|
1840
|
-
renderCorrelation(ast, lay),
|
|
1841
|
-
renderAxes(ast, lay),
|
|
1842
|
-
renderPoints(ast, lay),
|
|
1843
|
-
renderLegend(ast, lay),
|
|
1844
|
-
renderCorrelationLegend(ast, lay)
|
|
1845
|
-
].filter((s) => s.length > 0);
|
|
1846
|
-
return chunkHDKDQAEQ_cjs.svgRoot(
|
|
1847
|
-
{
|
|
1848
|
-
class: "sx-matrix",
|
|
1849
|
-
"data-diagram-type": "matrix",
|
|
1850
|
-
"data-mode": ast.mode,
|
|
1851
|
-
width: canvasWidth,
|
|
1852
|
-
height: lay.canvasHeight,
|
|
1853
|
-
viewBox: `0 0 ${canvasWidth} ${lay.canvasHeight}`,
|
|
1854
|
-
role: "graphics-document"
|
|
1855
|
-
},
|
|
1856
|
-
[
|
|
1857
|
-
chunkHDKDQAEQ_cjs.title(ast.title ? `Matrix \u2014 ${chunkHDKDQAEQ_cjs.escapeXml(ast.title)}` : "Matrix diagram"),
|
|
1858
|
-
chunkHDKDQAEQ_cjs.desc(
|
|
1859
|
-
`Matrix diagram${ast.template ? ` (${ast.template} template)` : ""}, ${ast.mode} mode, ${ast.points.length} point(s)`
|
|
1860
|
-
),
|
|
1861
|
-
chunkHDKDQAEQ_cjs.defs([chunkHDKDQAEQ_cjs.el("style", {}, CSS), axisArrow()]),
|
|
1862
|
-
...body
|
|
1863
|
-
]
|
|
1864
|
-
);
|
|
1865
|
-
}
|
|
1866
|
-
function renderMatrix(text2) {
|
|
1867
|
-
const ast = parseMatrix(text2);
|
|
1868
|
-
return renderMatrixAST(ast);
|
|
1869
|
-
}
|
|
1870
|
-
|
|
1871
|
-
// src/diagrams/matrix/index.ts
|
|
1872
|
-
var matrix = {
|
|
1873
|
-
type: "matrix",
|
|
1874
|
-
detect(text2) {
|
|
1875
|
-
const first = text2.trim().split("\n")[0]?.trim().toLowerCase() ?? "";
|
|
1876
|
-
return first.startsWith("matrix");
|
|
1877
|
-
},
|
|
1878
|
-
render(text2) {
|
|
1879
|
-
return renderMatrix(text2);
|
|
1880
|
-
}
|
|
1881
|
-
};
|
|
1882
|
-
|
|
1883
|
-
// src/core/api.ts
|
|
1884
|
-
var plugins = [
|
|
1885
|
-
chunk2UKC6ZCY_cjs.genogram,
|
|
1886
|
-
chunkS6BK5DB6_cjs.ecomap,
|
|
1887
|
-
chunkDS47NTWZ_cjs.pedigree,
|
|
1888
|
-
chunkXQ52ICHU_cjs.phylo,
|
|
1889
|
-
chunkNYCIK4SU_cjs.sociogram,
|
|
1890
|
-
chunk2MQWZ2XY_cjs.timing,
|
|
1891
|
-
chunkBE5HNDA5_cjs.logic,
|
|
1892
|
-
chunkFGPTCDUT_cjs.circuit,
|
|
1893
|
-
chunk34X3ZJ6E_cjs.blockdiagram,
|
|
1894
|
-
chunk4DBRNOPA_cjs.ladder,
|
|
1895
|
-
chunkZX7QKZK2_cjs.sld,
|
|
1896
|
-
chunkV6WO7RK7_cjs.entity,
|
|
1897
|
-
chunk7FZSPKX3_cjs.fishbone,
|
|
1898
|
-
chunk3FTUWAXK_cjs.venn,
|
|
1899
|
-
chunkMDICUK6F_cjs.flowchart,
|
|
1900
|
-
mindmap,
|
|
1901
|
-
matrix,
|
|
1902
|
-
chunkUHLYS3W5_cjs.orgchart
|
|
1903
|
-
];
|
|
1904
|
-
function detectPlugin(text2, config) {
|
|
1905
|
-
if (config?.type) {
|
|
1906
|
-
const plugin = plugins.find((p) => p.type === config.type);
|
|
1907
|
-
if (plugin) return plugin;
|
|
1908
|
-
}
|
|
1909
|
-
for (const plugin of plugins) {
|
|
1910
|
-
if (plugin.detect(text2)) return plugin;
|
|
1911
|
-
}
|
|
1912
|
-
throw new Error(
|
|
1913
|
-
"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', or 'orgchart'."
|
|
1914
|
-
);
|
|
1915
|
-
}
|
|
1916
|
-
function render(text2, config) {
|
|
1917
|
-
const plugin = detectPlugin(text2, config);
|
|
1918
|
-
const renderConfig = {
|
|
1919
|
-
fontFamily: config?.fontFamily ?? "system-ui, -apple-system, sans-serif",
|
|
1920
|
-
fontSize: 12,
|
|
1921
|
-
theme: config?.theme ?? "default",
|
|
1922
|
-
padding: config?.padding ?? 20
|
|
1923
|
-
};
|
|
1924
|
-
return plugin.render(text2, renderConfig);
|
|
1925
|
-
}
|
|
1926
24
|
|
|
25
|
+
Object.defineProperty(exports, "decisiontree", {
|
|
26
|
+
enumerable: true,
|
|
27
|
+
get: function () { return chunk7HKXU7J2_cjs.decisiontree; }
|
|
28
|
+
});
|
|
29
|
+
Object.defineProperty(exports, "parse", {
|
|
30
|
+
enumerable: true,
|
|
31
|
+
get: function () { return chunk7HKXU7J2_cjs.parse; }
|
|
32
|
+
});
|
|
33
|
+
Object.defineProperty(exports, "render", {
|
|
34
|
+
enumerable: true,
|
|
35
|
+
get: function () { return chunk7HKXU7J2_cjs.render; }
|
|
36
|
+
});
|
|
37
|
+
Object.defineProperty(exports, "timeline", {
|
|
38
|
+
enumerable: true,
|
|
39
|
+
get: function () { return chunk7HKXU7J2_cjs.timeline; }
|
|
40
|
+
});
|
|
1927
41
|
Object.defineProperty(exports, "orgchart", {
|
|
1928
42
|
enumerable: true,
|
|
1929
|
-
get: function () { return
|
|
43
|
+
get: function () { return chunk7IRT3LOY_cjs.orgchart; }
|
|
1930
44
|
});
|
|
1931
45
|
Object.defineProperty(exports, "circuit", {
|
|
1932
46
|
enumerable: true,
|
|
1933
|
-
get: function () { return
|
|
47
|
+
get: function () { return chunk4S2WILLW_cjs.circuit; }
|
|
1934
48
|
});
|
|
1935
49
|
Object.defineProperty(exports, "blockdiagram", {
|
|
1936
50
|
enumerable: true,
|
|
1937
|
-
get: function () { return
|
|
51
|
+
get: function () { return chunkLXNFVHDT_cjs.blockdiagram; }
|
|
1938
52
|
});
|
|
1939
53
|
Object.defineProperty(exports, "ladder", {
|
|
1940
54
|
enumerable: true,
|
|
1941
|
-
get: function () { return
|
|
55
|
+
get: function () { return chunkISACNVFE_cjs.ladder; }
|
|
1942
56
|
});
|
|
1943
57
|
Object.defineProperty(exports, "sld", {
|
|
1944
58
|
enumerable: true,
|
|
1945
|
-
get: function () { return
|
|
59
|
+
get: function () { return chunkQR7VTCI4_cjs.sld; }
|
|
1946
60
|
});
|
|
1947
61
|
Object.defineProperty(exports, "entity", {
|
|
1948
62
|
enumerable: true,
|
|
1949
|
-
get: function () { return
|
|
63
|
+
get: function () { return chunkZNOD4VZT_cjs.entity; }
|
|
1950
64
|
});
|
|
1951
65
|
Object.defineProperty(exports, "fishbone", {
|
|
1952
66
|
enumerable: true,
|
|
1953
|
-
get: function () { return
|
|
67
|
+
get: function () { return chunkLKOBOVNL_cjs.fishbone; }
|
|
1954
68
|
});
|
|
1955
69
|
Object.defineProperty(exports, "venn", {
|
|
1956
70
|
enumerable: true,
|
|
1957
|
-
get: function () { return
|
|
71
|
+
get: function () { return chunkQSQX77S2_cjs.venn; }
|
|
1958
72
|
});
|
|
1959
73
|
Object.defineProperty(exports, "flowchart", {
|
|
1960
74
|
enumerable: true,
|
|
1961
|
-
get: function () { return
|
|
75
|
+
get: function () { return chunkCXHPP5BL_cjs.flowchart; }
|
|
1962
76
|
});
|
|
1963
77
|
Object.defineProperty(exports, "genogram", {
|
|
1964
78
|
enumerable: true,
|
|
1965
|
-
get: function () { return
|
|
79
|
+
get: function () { return chunkZ63XPA2V_cjs.genogram; }
|
|
1966
80
|
});
|
|
1967
81
|
Object.defineProperty(exports, "ecomap", {
|
|
1968
82
|
enumerable: true,
|
|
1969
|
-
get: function () { return
|
|
83
|
+
get: function () { return chunkXHZ7GXP2_cjs.ecomap; }
|
|
1970
84
|
});
|
|
1971
85
|
Object.defineProperty(exports, "pedigree", {
|
|
1972
86
|
enumerable: true,
|
|
1973
|
-
get: function () { return
|
|
87
|
+
get: function () { return chunkXVCAOGFL_cjs.pedigree; }
|
|
1974
88
|
});
|
|
1975
89
|
Object.defineProperty(exports, "phylo", {
|
|
1976
90
|
enumerable: true,
|
|
1977
|
-
get: function () { return
|
|
91
|
+
get: function () { return chunkX7RPFTTR_cjs.phylo; }
|
|
1978
92
|
});
|
|
1979
93
|
Object.defineProperty(exports, "sociogram", {
|
|
1980
94
|
enumerable: true,
|
|
1981
|
-
get: function () { return
|
|
95
|
+
get: function () { return chunkYXIIWLLB_cjs.sociogram; }
|
|
1982
96
|
});
|
|
1983
97
|
Object.defineProperty(exports, "timing", {
|
|
1984
98
|
enumerable: true,
|
|
1985
|
-
get: function () { return
|
|
99
|
+
get: function () { return chunkZO77FHBF_cjs.timing; }
|
|
1986
100
|
});
|
|
1987
101
|
Object.defineProperty(exports, "logic", {
|
|
1988
102
|
enumerable: true,
|
|
1989
|
-
get: function () { return
|
|
103
|
+
get: function () { return chunkWYFXOXVK_cjs.logic; }
|
|
1990
104
|
});
|
|
1991
105
|
Object.defineProperty(exports, "BASE_THEMES", {
|
|
1992
106
|
enumerable: true,
|
|
1993
|
-
get: function () { return
|
|
107
|
+
get: function () { return chunkD7EHZFK4_cjs.BASE_THEMES; }
|
|
1994
108
|
});
|
|
1995
109
|
Object.defineProperty(exports, "BIOLOGY_TOKENS", {
|
|
1996
110
|
enumerable: true,
|
|
1997
|
-
get: function () { return
|
|
111
|
+
get: function () { return chunkD7EHZFK4_cjs.BIOLOGY_TOKENS; }
|
|
1998
112
|
});
|
|
1999
113
|
Object.defineProperty(exports, "PERSON_TOKENS", {
|
|
2000
114
|
enumerable: true,
|
|
2001
|
-
get: function () { return
|
|
115
|
+
get: function () { return chunkD7EHZFK4_cjs.PERSON_TOKENS; }
|
|
2002
116
|
});
|
|
2003
117
|
Object.defineProperty(exports, "VENN_TOKENS", {
|
|
2004
118
|
enumerable: true,
|
|
2005
|
-
get: function () { return
|
|
119
|
+
get: function () { return chunkD7EHZFK4_cjs.VENN_TOKENS; }
|
|
2006
120
|
});
|
|
2007
121
|
Object.defineProperty(exports, "resolveBaseTheme", {
|
|
2008
122
|
enumerable: true,
|
|
2009
|
-
get: function () { return
|
|
123
|
+
get: function () { return chunkD7EHZFK4_cjs.resolveBaseTheme; }
|
|
2010
124
|
});
|
|
2011
125
|
Object.defineProperty(exports, "resolveBiologyTheme", {
|
|
2012
126
|
enumerable: true,
|
|
2013
|
-
get: function () { return
|
|
127
|
+
get: function () { return chunkD7EHZFK4_cjs.resolveBiologyTheme; }
|
|
2014
128
|
});
|
|
2015
129
|
Object.defineProperty(exports, "resolveFishboneTheme", {
|
|
2016
130
|
enumerable: true,
|
|
2017
|
-
get: function () { return
|
|
131
|
+
get: function () { return chunkD7EHZFK4_cjs.resolveFishboneTheme; }
|
|
2018
132
|
});
|
|
2019
133
|
Object.defineProperty(exports, "resolveGenogramTheme", {
|
|
2020
134
|
enumerable: true,
|
|
2021
|
-
get: function () { return
|
|
135
|
+
get: function () { return chunkD7EHZFK4_cjs.resolveGenogramTheme; }
|
|
2022
136
|
});
|
|
2023
137
|
Object.defineProperty(exports, "resolvePersonTheme", {
|
|
2024
138
|
enumerable: true,
|
|
2025
|
-
get: function () { return
|
|
139
|
+
get: function () { return chunkD7EHZFK4_cjs.resolvePersonTheme; }
|
|
140
|
+
});
|
|
141
|
+
Object.defineProperty(exports, "resolveTimelineTheme", {
|
|
142
|
+
enumerable: true,
|
|
143
|
+
get: function () { return chunkD7EHZFK4_cjs.resolveTimelineTheme; }
|
|
2026
144
|
});
|
|
2027
145
|
Object.defineProperty(exports, "resolveVennTheme", {
|
|
2028
146
|
enumerable: true,
|
|
2029
|
-
get: function () { return
|
|
147
|
+
get: function () { return chunkD7EHZFK4_cjs.resolveVennTheme; }
|
|
2030
148
|
});
|
|
2031
|
-
exports.render = render;
|
|
2032
149
|
//# sourceMappingURL=index.cjs.map
|
|
2033
150
|
//# sourceMappingURL=index.cjs.map
|