@umami/shiso 1.12.0 → 1.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. package/dist/chunks/App.js +76 -49
  2. package/dist/chunks/abnfDiagram-VCTEODGH.js +109 -0
  3. package/dist/chunks/arc.js +130 -0
  4. package/dist/chunks/architecture-7GRP2DOG.js +4 -0
  5. package/dist/chunks/architectureDiagram-5GKGNRK7.js +7466 -0
  6. package/dist/chunks/array.js +8 -0
  7. package/dist/chunks/blockDiagram-I7D4REHJ.js +2546 -0
  8. package/dist/chunks/c4Diagram-7LVT6UL2.js +3654 -0
  9. package/dist/chunks/channel.js +9 -0
  10. package/dist/chunks/chunk-2Q5K7J3B.js +21 -0
  11. package/dist/chunks/chunk-4HAMMTFA.js +6106 -0
  12. package/dist/chunks/chunk-5VM5RSS4.js +21 -0
  13. package/dist/chunks/chunk-75Z2AOVW.js +2185 -0
  14. package/dist/chunks/chunk-DU6HZSFF.js +8729 -0
  15. package/dist/chunks/chunk-F27PBJKO.js +95 -0
  16. package/dist/chunks/chunk-FOHPRMQF.js +27162 -0
  17. package/dist/chunks/chunk-GMAD6QVW.js +2369 -0
  18. package/dist/chunks/chunk-GVQU2GXP.js +58 -0
  19. package/dist/chunks/chunk-IMKFNOWR.js +2593 -0
  20. package/dist/chunks/chunk-JWPE2WC7.js +12 -0
  21. package/dist/chunks/chunk-L3NEJ4N5.js +420 -0
  22. package/dist/chunks/chunk-OSK3NFVY.js +1029 -0
  23. package/dist/chunks/chunk-P2QGCYS3.js +95 -0
  24. package/dist/chunks/chunk-POPQ4Y6H.js +33 -0
  25. package/dist/chunks/chunk-PWAF6VOD.js +467 -0
  26. package/dist/chunks/chunk-SHT3W25Y.js +4813 -0
  27. package/dist/chunks/chunk-SVP7TREG.js +686 -0
  28. package/dist/chunks/chunk-TICWLB2K.js +3800 -0
  29. package/dist/chunks/chunk-XXDRQBXY.js +12 -0
  30. package/dist/chunks/chunk-Y2CYZVJY.js +15 -0
  31. package/dist/chunks/classDiagram-ZZMXUADV.js +33 -0
  32. package/dist/chunks/classDiagram-v2-VYDZK3BY.js +33 -0
  33. package/dist/chunks/cose-bilkent-JH36ORCC.js +4268 -0
  34. package/dist/chunks/cynefin-OW5HDTMX.js +4 -0
  35. package/dist/chunks/cynefinDiagram-5FMLGOSQ.js +482 -0
  36. package/dist/chunks/cytoscape.esm.js +28282 -0
  37. package/dist/chunks/dagre-GXQ25YYZ.js +583 -0
  38. package/dist/chunks/dagre.js +4235 -0
  39. package/dist/chunks/defaultLocale.js +246 -0
  40. package/dist/chunks/diagram-S7CK7UJ4.js +402 -0
  41. package/dist/chunks/diagram-UQ7AKVKN.js +291 -0
  42. package/dist/chunks/diagram-VSXAHHWV.js +553 -0
  43. package/dist/chunks/diagram-VX7I27RA.js +798 -0
  44. package/dist/chunks/diagram-Z3DM3KII.js +186 -0
  45. package/dist/chunks/dist.js +92 -0
  46. package/dist/chunks/docs.js +987 -91
  47. package/dist/chunks/ebnfDiagram-PWID7BFC.js +123 -0
  48. package/dist/chunks/erDiagram-RLTQ6QDP.js +2295 -0
  49. package/dist/chunks/eventmodeling-NTZA5JFV.js +4 -0
  50. package/dist/chunks/flowDiagram-HODETNUW.js +17 -0
  51. package/dist/chunks/ganttDiagram-EL5Y4UJY.js +3928 -0
  52. package/dist/chunks/gitGraph-4MIJSDKK.js +4 -0
  53. package/dist/chunks/gitGraphDiagram-WWUBYQGX.js +1153 -0
  54. package/dist/chunks/graphlib.js +4194 -0
  55. package/dist/chunks/info-A6RAGUB7.js +4 -0
  56. package/dist/chunks/infoDiagram-27XIBGKW.js +25 -0
  57. package/dist/chunks/init.js +14 -0
  58. package/dist/chunks/ishikawaDiagram-5VMMS53U.js +971 -0
  59. package/dist/chunks/journeyDiagram-3NMN7TZE.js +1226 -0
  60. package/dist/chunks/kanban-definition-UXKFOSKX.js +1241 -0
  61. package/dist/chunks/katex.js +26463 -0
  62. package/dist/chunks/line.js +48 -0
  63. package/dist/chunks/linear.js +391 -0
  64. package/dist/chunks/mermaid-parser.core.js +754 -0
  65. package/dist/chunks/mermaid.core.js +4898 -0
  66. package/dist/chunks/mindmap-definition-YA3MSWOX.js +1309 -0
  67. package/dist/chunks/ordinal.js +84 -0
  68. package/dist/chunks/packet-AYTQ26CC.js +4 -0
  69. package/dist/chunks/path.js +106 -0
  70. package/dist/chunks/pegDiagram-XKGWAZYB.js +115 -0
  71. package/dist/chunks/pie-WAS4IAKB.js +4 -0
  72. package/dist/chunks/pieDiagram-E7YTZNPT.js +297 -0
  73. package/dist/chunks/quadrantDiagram-AXDQQJYC.js +2234 -0
  74. package/dist/chunks/radar-RG4KPBEZ.js +4 -0
  75. package/dist/chunks/railroad-74A4TZTK.js +4 -0
  76. package/dist/chunks/railroad-abnf-HS5TGJTU.js +4 -0
  77. package/dist/chunks/railroad-ebnf-LZEXJU2U.js +4 -0
  78. package/dist/chunks/railroad-peg-WCYAUIDC.js +4 -0
  79. package/dist/chunks/railroadDiagram-O6MQD6OU.js +89 -0
  80. package/dist/chunks/requirementDiagram-BXWQKSXE.js +2464 -0
  81. package/dist/chunks/rough.esm.js +1396 -0
  82. package/dist/chunks/sankeyDiagram-P5KCCOFB.js +1308 -0
  83. package/dist/chunks/sequenceDiagram-WJ2MYXX4.js +5445 -0
  84. package/dist/chunks/sizeCapture-INFHLROL.js +56 -0
  85. package/dist/chunks/src.js +2653 -0
  86. package/dist/chunks/stateDiagram-D77RDMKH.js +368 -0
  87. package/dist/chunks/stateDiagram-v2-MP3YSRHH.js +33 -0
  88. package/dist/chunks/swimlanes-42K2YHIH.js +6925 -0
  89. package/dist/chunks/swimlanesDiagram-VR7AAH4N.js +32 -0
  90. package/dist/chunks/timeline-definition-24CTP7MA.js +1507 -0
  91. package/dist/chunks/treeView-Q6P3EWNA.js +4 -0
  92. package/dist/chunks/treemap-WGGIJYW6.js +4 -0
  93. package/dist/chunks/vennDiagram-4TSXK5OY.js +2803 -0
  94. package/dist/chunks/wardley-WFR3VGLG.js +4 -0
  95. package/dist/chunks/wardleyDiagram-VM6X3IG4.js +877 -0
  96. package/dist/chunks/xychartDiagram-S5SC5T6Z.js +2698 -0
  97. package/dist/components.js +2 -2
  98. package/dist/entry-client.js +1 -1
  99. package/dist/entry-server.js +1 -1
  100. package/docs.schema.json +1 -1
  101. package/package.json +2 -1
  102. package/scripts/expand-navigation-globs.mjs +77 -8
  103. package/src/components/CodeBlock.tsx +36 -0
  104. package/src/components/Docs.tsx +44 -21
  105. package/src/components/OpenApiOperation.tsx +28 -20
  106. package/src/components/SideNav.tsx +8 -3
  107. package/src/components/docs/Changelog.tsx +163 -0
  108. package/src/components/docs/Mermaid.tsx +164 -0
  109. package/src/components/docs/Panel.tsx +23 -0
  110. package/src/components/docs/ParamField.tsx +17 -5
  111. package/src/components/docs/PropertiesTable.tsx +2 -2
  112. package/src/components/docs/ResponseField.tsx +17 -5
  113. package/src/components/docs/Tiles.tsx +59 -0
  114. package/src/components/docs/Tree.tsx +359 -0
  115. package/src/components/docs/Update.tsx +72 -0
  116. package/src/components/docs/index.ts +7 -0
  117. package/src/components/docs/panel-context.tsx +25 -0
  118. package/src/components/docs/styles.ts +49 -0
  119. package/src/components/icons/index.ts +4 -0
  120. package/src/lib/rehype-shiki.ts +18 -1
  121. package/types/components.d.ts +79 -0
@@ -0,0 +1,2803 @@
1
+ import { n as __name } from "./chunk-Y2CYZVJY.js";
2
+ import { p as select_default } from "./src.js";
3
+ import { H as setAccDescription, K as setDiagramTitle, U as setAccTitle, a as clear, b as getConfig, c as configureSvgSize, et as darken, f as defaultConfig_default, nt as adjustChannel, rt as isDark, tt as lighten, v as getAccDescription, w as getDiagramTitle, y as getAccTitle } from "./chunk-DU6HZSFF.js";
4
+ import { i as cleanAndMerge } from "./chunk-75Z2AOVW.js";
5
+ import { t as at } from "./rough.esm.js";
6
+ import { f as selectSvgElement } from "./mermaid.core.js";
7
+
8
+ //#region ../../node_modules/.pnpm/khroma@2.1.0/node_modules/khroma/dist/methods/transparentize.js
9
+ const transparentize = (color, amount) => {
10
+ return adjustChannel(color, "a", -amount);
11
+ };
12
+
13
+ //#endregion
14
+ //#region ../../node_modules/.pnpm/@upsetjs+venn.js@2.0.0/node_modules/@upsetjs/venn.js/build/venn.esm.js
15
+ const SMALL$1 = 1e-10;
16
+ /**
17
+ * Returns the intersection area of a bunch of circles (where each circle
18
+ * is an object having an x,y and radius property)
19
+ * @param {ReadonlyArray<{x: number, y: number, radius: number}>} circles
20
+ * @param {undefined | { area?: number, arcArea?: number, polygonArea?: number, arcs?: ReadonlyArray<{ circle: {x: number, y: number, radius: number}, width: number, p1: {x: number, y: number}, p2: {x: number, y: number} }>, innerPoints: ReadonlyArray<{
21
+ x: number;
22
+ y: number;
23
+ parentIndex: [number, number];
24
+ }>, intersectionPoints: ReadonlyArray<{
25
+ x: number;
26
+ y: number;
27
+ parentIndex: [number, number];
28
+ }> }} stats
29
+ * @returns {number}
30
+ */
31
+ function intersectionArea(circles, stats) {
32
+ const intersectionPoints = getIntersectionPoints(circles);
33
+ const innerPoints = intersectionPoints.filter((p) => containedInCircles(p, circles));
34
+ let arcArea = 0;
35
+ let polygonArea = 0;
36
+ /** @type {{ circle: {x: number, y: number, radius: number}, width: number, p1: {x: number, y: number}, p2: {x: number, y: number} }[]} */
37
+ const arcs = [];
38
+ if (innerPoints.length > 1) {
39
+ const center = getCenter(innerPoints);
40
+ for (let i = 0; i < innerPoints.length; ++i) {
41
+ const p = innerPoints[i];
42
+ p.angle = Math.atan2(p.x - center.x, p.y - center.y);
43
+ }
44
+ innerPoints.sort((a, b) => b.angle - a.angle);
45
+ let p2 = innerPoints[innerPoints.length - 1];
46
+ for (let i = 0; i < innerPoints.length; ++i) {
47
+ const p1 = innerPoints[i];
48
+ polygonArea += (p2.x + p1.x) * (p1.y - p2.y);
49
+ const midPoint = {
50
+ x: (p1.x + p2.x) / 2,
51
+ y: (p1.y + p2.y) / 2
52
+ };
53
+ /** @types null | { circle: {x: number, y: number, radius: number}, width: number, p1: {x: number, y: number}, p2: {x: number, y: number} } */
54
+ let arc = null;
55
+ for (let j = 0; j < p1.parentIndex.length; ++j) if (p2.parentIndex.includes(p1.parentIndex[j])) {
56
+ const circle = circles[p1.parentIndex[j]];
57
+ const a1 = Math.atan2(p1.x - circle.x, p1.y - circle.y);
58
+ const a2 = Math.atan2(p2.x - circle.x, p2.y - circle.y);
59
+ let angleDiff = a2 - a1;
60
+ if (angleDiff < 0) angleDiff += 2 * Math.PI;
61
+ const a = a2 - angleDiff / 2;
62
+ let width = distance(midPoint, {
63
+ x: circle.x + circle.radius * Math.sin(a),
64
+ y: circle.y + circle.radius * Math.cos(a)
65
+ });
66
+ if (width > circle.radius * 2) width = circle.radius * 2;
67
+ if (arc == null || arc.width > width) arc = {
68
+ circle,
69
+ width,
70
+ p1,
71
+ p2,
72
+ large: width > circle.radius,
73
+ sweep: true
74
+ };
75
+ }
76
+ if (arc != null) {
77
+ arcs.push(arc);
78
+ arcArea += circleArea(arc.circle.radius, arc.width);
79
+ p2 = p1;
80
+ }
81
+ }
82
+ } else {
83
+ let smallest = circles[0];
84
+ for (let i = 1; i < circles.length; ++i) if (circles[i].radius < smallest.radius) smallest = circles[i];
85
+ let disjoint = false;
86
+ for (let i = 0; i < circles.length; ++i) if (distance(circles[i], smallest) > Math.abs(smallest.radius - circles[i].radius)) {
87
+ disjoint = true;
88
+ break;
89
+ }
90
+ if (disjoint) arcArea = polygonArea = 0;
91
+ else {
92
+ arcArea = smallest.radius * smallest.radius * Math.PI;
93
+ arcs.push({
94
+ circle: smallest,
95
+ p1: {
96
+ x: smallest.x,
97
+ y: smallest.y + smallest.radius
98
+ },
99
+ p2: {
100
+ x: smallest.x - SMALL$1,
101
+ y: smallest.y + smallest.radius
102
+ },
103
+ width: smallest.radius * 2,
104
+ large: true,
105
+ sweep: true
106
+ });
107
+ }
108
+ }
109
+ polygonArea /= 2;
110
+ if (stats) {
111
+ stats.area = arcArea + polygonArea;
112
+ stats.arcArea = arcArea;
113
+ stats.polygonArea = polygonArea;
114
+ stats.arcs = arcs;
115
+ stats.innerPoints = innerPoints;
116
+ stats.intersectionPoints = intersectionPoints;
117
+ }
118
+ return arcArea + polygonArea;
119
+ }
120
+ /**
121
+ * returns whether a point is contained by all of a list of circles
122
+ * @param {{x: number, y: number}} point
123
+ * @param {ReadonlyArray<{x: number, y: number, radius: number}>} circles
124
+ * @returns {boolean}
125
+ */
126
+ function containedInCircles(point, circles) {
127
+ return circles.every((circle) => distance(point, circle) < circle.radius + SMALL$1);
128
+ }
129
+ /**
130
+ * Gets all intersection points between a bunch of circles
131
+ * @param {ReadonlyArray<{x: number, y: number, radius: number}>} circles
132
+ * @returns {ReadonlyArray<{x: number, y: number, parentIndex: [number, number]}>}
133
+ */
134
+ function getIntersectionPoints(circles) {
135
+ /** @type {{x: number, y: number, parentIndex: [number, number]}[]} */
136
+ const ret = [];
137
+ for (let i = 0; i < circles.length; ++i) for (let j = i + 1; j < circles.length; ++j) {
138
+ const intersect = circleCircleIntersection(circles[i], circles[j]);
139
+ for (const p of intersect) {
140
+ p.parentIndex = [i, j];
141
+ ret.push(p);
142
+ }
143
+ }
144
+ return ret;
145
+ }
146
+ /**
147
+ * Circular segment area calculation. See http://mathworld.wolfram.com/CircularSegment.html
148
+ * @param {number} r
149
+ * @param {number} width
150
+ * @returns {number}
151
+ **/
152
+ function circleArea(r, width) {
153
+ return r * r * Math.acos(1 - width / r) - (r - width) * Math.sqrt(width * (2 * r - width));
154
+ }
155
+ /**
156
+ * euclidean distance between two points
157
+ * @param {{x: number, y: number}} p1
158
+ * @param {{x: number, y: number}} p2
159
+ * @returns {number}
160
+ **/
161
+ function distance(p1, p2) {
162
+ return Math.sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
163
+ }
164
+ /**
165
+ * Returns the overlap area of two circles of radius r1 and r2 - that
166
+ * have their centers separated by distance d. Simpler faster
167
+ * circle intersection for only two circles
168
+ * @param {number} r1
169
+ * @param {number} r2
170
+ * @param {number} d
171
+ * @returns {number}
172
+ */
173
+ function circleOverlap(r1, r2, d) {
174
+ if (d >= r1 + r2) return 0;
175
+ if (d <= Math.abs(r1 - r2)) return Math.PI * Math.min(r1, r2) * Math.min(r1, r2);
176
+ const w1 = r1 - (d * d - r2 * r2 + r1 * r1) / (2 * d);
177
+ const w2 = r2 - (d * d - r1 * r1 + r2 * r2) / (2 * d);
178
+ return circleArea(r1, w1) + circleArea(r2, w2);
179
+ }
180
+ /**
181
+ * Given two circles (containing a x/y/radius attributes),
182
+ * returns the intersecting points if possible
183
+ * note: doesn't handle cases where there are infinitely many
184
+ * intersection points (circles are equivalent):, or only one intersection point
185
+ * @param {{x: number, y: number, radius: number}} p1
186
+ * @param {{x: number, y: number, radius: number}} p2
187
+ * @returns {ReadonlyArray<{x: number, y: number}>}
188
+ **/
189
+ function circleCircleIntersection(p1, p2) {
190
+ const d = distance(p1, p2);
191
+ const r1 = p1.radius;
192
+ const r2 = p2.radius;
193
+ if (d >= r1 + r2 || d <= Math.abs(r1 - r2)) return [];
194
+ const a = (r1 * r1 - r2 * r2 + d * d) / (2 * d);
195
+ const h = Math.sqrt(r1 * r1 - a * a);
196
+ const x0 = p1.x + a * (p2.x - p1.x) / d;
197
+ const y0 = p1.y + a * (p2.y - p1.y) / d;
198
+ const rx = -(p2.y - p1.y) * (h / d);
199
+ const ry = -(p2.x - p1.x) * (h / d);
200
+ return [{
201
+ x: x0 + rx,
202
+ y: y0 - ry
203
+ }, {
204
+ x: x0 - rx,
205
+ y: y0 + ry
206
+ }];
207
+ }
208
+ /**
209
+ * Returns the center of a bunch of points
210
+ * @param {ReadonlyArray<{x: number, y: number}>} points
211
+ * @returns {{x: number, y: number}}
212
+ */
213
+ function getCenter(points) {
214
+ const center = {
215
+ x: 0,
216
+ y: 0
217
+ };
218
+ for (const point of points) {
219
+ center.x += point.x;
220
+ center.y += point.y;
221
+ }
222
+ center.x /= points.length;
223
+ center.y /= points.length;
224
+ return center;
225
+ }
226
+ /** finds the zeros of a function, given two starting points (which must
227
+ * have opposite signs */
228
+ function bisect(f, a, b, parameters) {
229
+ parameters = parameters || {};
230
+ const maxIterations = parameters.maxIterations || 100;
231
+ const tolerance = parameters.tolerance || 1e-10;
232
+ const fA = f(a);
233
+ const fB = f(b);
234
+ let delta = b - a;
235
+ if (fA * fB > 0) throw "Initial bisect points must have opposite signs";
236
+ if (fA === 0) return a;
237
+ if (fB === 0) return b;
238
+ for (let i = 0; i < maxIterations; ++i) {
239
+ delta /= 2;
240
+ const mid = a + delta;
241
+ const fMid = f(mid);
242
+ if (fMid * fA >= 0) a = mid;
243
+ if (Math.abs(delta) < tolerance || fMid === 0) return mid;
244
+ }
245
+ return a + delta;
246
+ }
247
+ function zeros(x) {
248
+ const r = new Array(x);
249
+ for (let i = 0; i < x; ++i) r[i] = 0;
250
+ return r;
251
+ }
252
+ function zerosM(x, y) {
253
+ return zeros(x).map(() => zeros(y));
254
+ }
255
+ function dot(a, b) {
256
+ let ret = 0;
257
+ for (let i = 0; i < a.length; ++i) ret += a[i] * b[i];
258
+ return ret;
259
+ }
260
+ function norm2(a) {
261
+ return Math.sqrt(dot(a, a));
262
+ }
263
+ function scale(ret, value, c) {
264
+ for (let i = 0; i < value.length; ++i) ret[i] = value[i] * c;
265
+ }
266
+ function weightedSum(ret, w1, v1, w2, v2) {
267
+ for (let j = 0; j < ret.length; ++j) ret[j] = w1 * v1[j] + w2 * v2[j];
268
+ }
269
+ /** minimizes a function using the downhill simplex method */
270
+ function nelderMead(f, x0, parameters) {
271
+ parameters = parameters || {};
272
+ const maxIterations = parameters.maxIterations || x0.length * 200;
273
+ const nonZeroDelta = parameters.nonZeroDelta || 1.05;
274
+ const zeroDelta = parameters.zeroDelta || .001;
275
+ const minErrorDelta = parameters.minErrorDelta || 1e-6;
276
+ const minTolerance = parameters.minErrorDelta || 1e-5;
277
+ const rho = parameters.rho !== void 0 ? parameters.rho : 1;
278
+ const chi = parameters.chi !== void 0 ? parameters.chi : 2;
279
+ const psi = parameters.psi !== void 0 ? parameters.psi : -.5;
280
+ const sigma = parameters.sigma !== void 0 ? parameters.sigma : .5;
281
+ let maxDiff;
282
+ const N = x0.length;
283
+ const simplex = new Array(N + 1);
284
+ simplex[0] = x0;
285
+ simplex[0].fx = f(x0);
286
+ simplex[0].id = 0;
287
+ for (let i = 0; i < N; ++i) {
288
+ const point = x0.slice();
289
+ point[i] = point[i] ? point[i] * nonZeroDelta : zeroDelta;
290
+ simplex[i + 1] = point;
291
+ simplex[i + 1].fx = f(point);
292
+ simplex[i + 1].id = i + 1;
293
+ }
294
+ function updateSimplex(value) {
295
+ for (let i = 0; i < value.length; i++) simplex[N][i] = value[i];
296
+ simplex[N].fx = value.fx;
297
+ }
298
+ const sortOrder = (a, b) => a.fx - b.fx;
299
+ const centroid = x0.slice();
300
+ const reflected = x0.slice();
301
+ const contracted = x0.slice();
302
+ const expanded = x0.slice();
303
+ for (let iteration = 0; iteration < maxIterations; ++iteration) {
304
+ simplex.sort(sortOrder);
305
+ if (parameters.history) {
306
+ const sortedSimplex = simplex.map((x) => {
307
+ const state = x.slice();
308
+ state.fx = x.fx;
309
+ state.id = x.id;
310
+ return state;
311
+ });
312
+ sortedSimplex.sort((a, b) => a.id - b.id);
313
+ parameters.history.push({
314
+ x: simplex[0].slice(),
315
+ fx: simplex[0].fx,
316
+ simplex: sortedSimplex
317
+ });
318
+ }
319
+ maxDiff = 0;
320
+ for (let i = 0; i < N; ++i) maxDiff = Math.max(maxDiff, Math.abs(simplex[0][i] - simplex[1][i]));
321
+ if (Math.abs(simplex[0].fx - simplex[N].fx) < minErrorDelta && maxDiff < minTolerance) break;
322
+ for (let i = 0; i < N; ++i) {
323
+ centroid[i] = 0;
324
+ for (let j = 0; j < N; ++j) centroid[i] += simplex[j][i];
325
+ centroid[i] /= N;
326
+ }
327
+ const worst = simplex[N];
328
+ weightedSum(reflected, 1 + rho, centroid, -rho, worst);
329
+ reflected.fx = f(reflected);
330
+ if (reflected.fx < simplex[0].fx) {
331
+ weightedSum(expanded, 1 + chi, centroid, -chi, worst);
332
+ expanded.fx = f(expanded);
333
+ if (expanded.fx < reflected.fx) updateSimplex(expanded);
334
+ else updateSimplex(reflected);
335
+ } else if (reflected.fx >= simplex[N - 1].fx) {
336
+ let shouldReduce = false;
337
+ if (reflected.fx > worst.fx) {
338
+ weightedSum(contracted, 1 + psi, centroid, -psi, worst);
339
+ contracted.fx = f(contracted);
340
+ if (contracted.fx < worst.fx) updateSimplex(contracted);
341
+ else shouldReduce = true;
342
+ } else {
343
+ weightedSum(contracted, 1 - psi * rho, centroid, psi * rho, worst);
344
+ contracted.fx = f(contracted);
345
+ if (contracted.fx < reflected.fx) updateSimplex(contracted);
346
+ else shouldReduce = true;
347
+ }
348
+ if (shouldReduce) {
349
+ if (sigma >= 1) break;
350
+ for (let i = 1; i < simplex.length; ++i) {
351
+ weightedSum(simplex[i], 1 - sigma, simplex[0], sigma, simplex[i]);
352
+ simplex[i].fx = f(simplex[i]);
353
+ }
354
+ }
355
+ } else updateSimplex(reflected);
356
+ }
357
+ simplex.sort(sortOrder);
358
+ return {
359
+ fx: simplex[0].fx,
360
+ x: simplex[0]
361
+ };
362
+ }
363
+ function wolfeLineSearch(f, pk, current, next, a, c1, c2) {
364
+ const phi0 = current.fx;
365
+ const phiPrime0 = dot(current.fxprime, pk);
366
+ let phi = phi0;
367
+ let phi_old = phi0;
368
+ let phiPrime = phiPrime0;
369
+ let a0 = 0;
370
+ a = a || 1;
371
+ c1 = c1 || 1e-6;
372
+ c2 = c2 || .1;
373
+ function zoom(a_lo, a_high, phi_lo) {
374
+ for (let iteration = 0; iteration < 16; ++iteration) {
375
+ a = (a_lo + a_high) / 2;
376
+ weightedSum(next.x, 1, current.x, a, pk);
377
+ phi = next.fx = f(next.x, next.fxprime);
378
+ phiPrime = dot(next.fxprime, pk);
379
+ if (phi > phi0 + c1 * a * phiPrime0 || phi >= phi_lo) a_high = a;
380
+ else {
381
+ if (Math.abs(phiPrime) <= -c2 * phiPrime0) return a;
382
+ if (phiPrime * (a_high - a_lo) >= 0) a_high = a_lo;
383
+ a_lo = a;
384
+ phi_lo = phi;
385
+ }
386
+ }
387
+ return 0;
388
+ }
389
+ for (let iteration = 0; iteration < 10; ++iteration) {
390
+ weightedSum(next.x, 1, current.x, a, pk);
391
+ phi = next.fx = f(next.x, next.fxprime);
392
+ phiPrime = dot(next.fxprime, pk);
393
+ if (phi > phi0 + c1 * a * phiPrime0 || iteration && phi >= phi_old) return zoom(a0, a, phi_old);
394
+ if (Math.abs(phiPrime) <= -c2 * phiPrime0) return a;
395
+ if (phiPrime >= 0) return zoom(a, a0, phi);
396
+ phi_old = phi;
397
+ a0 = a;
398
+ a *= 2;
399
+ }
400
+ return a;
401
+ }
402
+ function conjugateGradient(f, initial, params) {
403
+ let current = {
404
+ x: initial.slice(),
405
+ fx: 0,
406
+ fxprime: initial.slice()
407
+ };
408
+ let next = {
409
+ x: initial.slice(),
410
+ fx: 0,
411
+ fxprime: initial.slice()
412
+ };
413
+ const yk = initial.slice();
414
+ let pk;
415
+ let temp;
416
+ let a = 1;
417
+ let maxIterations;
418
+ params = params || {};
419
+ maxIterations = params.maxIterations || initial.length * 20;
420
+ current.fx = f(current.x, current.fxprime);
421
+ pk = current.fxprime.slice();
422
+ scale(pk, current.fxprime, -1);
423
+ for (let i = 0; i < maxIterations; ++i) {
424
+ a = wolfeLineSearch(f, pk, current, next, a);
425
+ if (params.history) params.history.push({
426
+ x: current.x.slice(),
427
+ fx: current.fx,
428
+ fxprime: current.fxprime.slice(),
429
+ alpha: a
430
+ });
431
+ if (!a) scale(pk, current.fxprime, -1);
432
+ else {
433
+ weightedSum(yk, 1, next.fxprime, -1, current.fxprime);
434
+ const delta_k = dot(current.fxprime, current.fxprime);
435
+ const beta_k = Math.max(0, dot(yk, next.fxprime) / delta_k);
436
+ weightedSum(pk, beta_k, pk, -1, next.fxprime);
437
+ temp = current;
438
+ current = next;
439
+ next = temp;
440
+ }
441
+ if (norm2(current.fxprime) <= 1e-5) break;
442
+ }
443
+ if (params.history) params.history.push({
444
+ x: current.x.slice(),
445
+ fx: current.fx,
446
+ fxprime: current.fxprime.slice(),
447
+ alpha: a
448
+ });
449
+ return current;
450
+ }
451
+ /**
452
+ * given a list of set objects, and their corresponding overlaps
453
+ * updates the (x, y, radius) attribute on each set such that their positions
454
+ * roughly correspond to the desired overlaps
455
+ * @param {readonly {sets: readonly string[]; size: number; weight?: number}[]} sets
456
+ * @returns {{[setid: string]: {x: number, y: number, radius: number}}}
457
+ */
458
+ function venn(sets, parameters = {}) {
459
+ parameters.maxIterations = parameters.maxIterations || 500;
460
+ const initialLayout = parameters.initialLayout || bestInitialLayout;
461
+ const loss = parameters.lossFunction || lossFunction;
462
+ const areas = addMissingAreas(sets, parameters);
463
+ const circles = initialLayout(areas, parameters);
464
+ const setids = Object.keys(circles);
465
+ /** @type {number[]} */
466
+ const initial = [];
467
+ for (const setid of setids) {
468
+ initial.push(circles[setid].x);
469
+ initial.push(circles[setid].y);
470
+ }
471
+ const positions = nelderMead((values) => {
472
+ const current = {};
473
+ for (let i = 0; i < setids.length; ++i) {
474
+ const setid = setids[i];
475
+ current[setid] = {
476
+ x: values[2 * i],
477
+ y: values[2 * i + 1],
478
+ radius: circles[setid].radius
479
+ };
480
+ }
481
+ return loss(current, areas);
482
+ }, initial, parameters).x;
483
+ for (let i = 0; i < setids.length; ++i) {
484
+ const setid = setids[i];
485
+ circles[setid].x = positions[2 * i];
486
+ circles[setid].y = positions[2 * i + 1];
487
+ }
488
+ return circles;
489
+ }
490
+ const SMALL = 1e-10;
491
+ /**
492
+ * Returns the distance necessary for two circles of radius r1 + r2 to
493
+ * have the overlap area 'overlap'
494
+ * @param {number} r1
495
+ * @param {number} r2
496
+ * @param {number} overlap
497
+ * @returns {number}
498
+ */
499
+ function distanceFromIntersectArea(r1, r2, overlap) {
500
+ if (Math.min(r1, r2) * Math.min(r1, r2) * Math.PI <= overlap + SMALL) return Math.abs(r1 - r2);
501
+ return bisect((distance) => circleOverlap(r1, r2, distance) - overlap, 0, r1 + r2);
502
+ }
503
+ /**
504
+ * Missing pair-wise intersection area data can cause problems:
505
+ * treating as an unknown means that sets will be laid out overlapping,
506
+ * which isn't what people expect. To reflect that we want disjoint sets
507
+ * here, set the overlap to 0 for all missing pairwise set intersections
508
+ * @param {ReadonlyArray<{sets: ReadonlyArray<string>, size: number}>} areas
509
+ * @returns {ReadonlyArray<{sets: ReadonlyArray<string>, size: number}>}
510
+ */
511
+ function addMissingAreas(areas, parameters = {}) {
512
+ const distinct = parameters.distinct;
513
+ const r = areas.map((s) => Object.assign({}, s));
514
+ function toKey(arr) {
515
+ return arr.join(";");
516
+ }
517
+ if (distinct) {
518
+ /** @types Map<string, number> */
519
+ const count = /* @__PURE__ */ new Map();
520
+ for (const area of r) for (let i = 0; i < area.sets.length; i++) {
521
+ const si = String(area.sets[i]);
522
+ count.set(si, area.size + (count.get(si) || 0));
523
+ for (let j = i + 1; j < area.sets.length; j++) {
524
+ const sj = String(area.sets[j]);
525
+ const k1 = `${si};${sj}`;
526
+ const k2 = `${sj};${si}`;
527
+ count.set(k1, area.size + (count.get(k1) || 0));
528
+ count.set(k2, area.size + (count.get(k2) || 0));
529
+ }
530
+ }
531
+ for (const area of r) if (area.sets.length < 3) area.size = count.get(toKey(area.sets));
532
+ }
533
+ const ids = [];
534
+ /** @type {Set<string>} */
535
+ const pairs = /* @__PURE__ */ new Set();
536
+ for (const area of r) if (area.sets.length === 1) ids.push(area.sets[0]);
537
+ else if (area.sets.length === 2) {
538
+ const a = area.sets[0];
539
+ const b = area.sets[1];
540
+ pairs.add(toKey(area.sets));
541
+ pairs.add(toKey([b, a]));
542
+ }
543
+ ids.sort((a, b) => a === b ? 0 : a < b ? -1 : 1);
544
+ for (let i = 0; i < ids.length; ++i) {
545
+ const a = ids[i];
546
+ for (let j = i + 1; j < ids.length; ++j) {
547
+ const b = ids[j];
548
+ if (!pairs.has(toKey([a, b]))) r.push({
549
+ sets: [a, b],
550
+ size: 0
551
+ });
552
+ }
553
+ }
554
+ return r;
555
+ }
556
+ /**
557
+ * Returns two matrices, one of the euclidean distances between the sets
558
+ * and the other indicating if there are subset or disjoint set relationships
559
+ * @param {ReadonlyArray<{sets: ReadonlyArray<number>}>} areas
560
+ * @param {ReadonlyArray<{size: number}>} sets
561
+ * @param {ReadonlyArray<number>} setids
562
+ */
563
+ function getDistanceMatrices(areas, sets, setids) {
564
+ /**
565
+ * @type {number[][]}
566
+ */
567
+ const distances = zerosM(sets.length, sets.length);
568
+ /**
569
+ * @type {number[][]}
570
+ */
571
+ const constraints = zerosM(sets.length, sets.length);
572
+ areas.filter((x) => x.sets.length === 2).forEach((current) => {
573
+ const left = setids[current.sets[0]];
574
+ const right = setids[current.sets[1]];
575
+ const distance = distanceFromIntersectArea(Math.sqrt(sets[left].size / Math.PI), Math.sqrt(sets[right].size / Math.PI), current.size);
576
+ distances[left][right] = distances[right][left] = distance;
577
+ let c = 0;
578
+ if (current.size + 1e-10 >= Math.min(sets[left].size, sets[right].size)) c = 1;
579
+ else if (current.size <= 1e-10) c = -1;
580
+ constraints[left][right] = constraints[right][left] = c;
581
+ });
582
+ return {
583
+ distances,
584
+ constraints
585
+ };
586
+ }
587
+ function constrainedMDSGradient(x, fxprime, distances, constraints) {
588
+ for (let i = 0; i < fxprime.length; ++i) fxprime[i] = 0;
589
+ let loss = 0;
590
+ for (let i = 0; i < distances.length; ++i) {
591
+ const xi = x[2 * i];
592
+ const yi = x[2 * i + 1];
593
+ for (let j = i + 1; j < distances.length; ++j) {
594
+ const xj = x[2 * j];
595
+ const yj = x[2 * j + 1];
596
+ const dij = distances[i][j];
597
+ const constraint = constraints[i][j];
598
+ const squaredDistance = (xj - xi) * (xj - xi) + (yj - yi) * (yj - yi);
599
+ const distance = Math.sqrt(squaredDistance);
600
+ const delta = squaredDistance - dij * dij;
601
+ if (constraint > 0 && distance <= dij || constraint < 0 && distance >= dij) continue;
602
+ loss += 2 * delta * delta;
603
+ fxprime[2 * i] += 4 * delta * (xi - xj);
604
+ fxprime[2 * i + 1] += 4 * delta * (yi - yj);
605
+ fxprime[2 * j] += 4 * delta * (xj - xi);
606
+ fxprime[2 * j + 1] += 4 * delta * (yj - yi);
607
+ }
608
+ }
609
+ return loss;
610
+ }
611
+ /**
612
+ * takes the best working variant of either constrained MDS or greedy
613
+ * @param {ReadonlyArray<{sets: ReadonlyArray<string>, size: number}>} areas
614
+ */
615
+ function bestInitialLayout(areas, params = {}) {
616
+ let initial = greedyLayout(areas, params);
617
+ const loss = params.lossFunction || lossFunction;
618
+ if (areas.length >= 8) {
619
+ const constrained = constrainedMDSLayout(areas, params);
620
+ const constrainedLoss = loss(constrained, areas);
621
+ const greedyLoss = loss(initial, areas);
622
+ if (constrainedLoss + 1e-8 < greedyLoss) initial = constrained;
623
+ }
624
+ return initial;
625
+ }
626
+ /**
627
+ * use the constrained MDS variant to generate an initial layout
628
+ * @param {ReadonlyArray<{sets: ReadonlyArray<string>, size: number}>} areas
629
+ * @returns {{[key: string]: {x: number, y: number, radius: number}}}
630
+ */
631
+ function constrainedMDSLayout(areas, params = {}) {
632
+ const restarts = params.restarts || 10;
633
+ const sets = [];
634
+ const setids = {};
635
+ for (const area of areas) if (area.sets.length === 1) {
636
+ setids[area.sets[0]] = sets.length;
637
+ sets.push(area);
638
+ }
639
+ let { distances, constraints } = getDistanceMatrices(areas, sets, setids);
640
+ const norm = norm2(distances.map(norm2)) / distances.length;
641
+ distances = distances.map((row) => row.map((value) => value / norm));
642
+ const obj = (x, fxprime) => constrainedMDSGradient(x, fxprime, distances, constraints);
643
+ let best = null;
644
+ for (let i = 0; i < restarts; ++i) {
645
+ const current = conjugateGradient(obj, zeros(distances.length * 2).map(Math.random), params);
646
+ if (!best || current.fx < best.fx) best = current;
647
+ }
648
+ const positions = best.x;
649
+ /** @type {{[key: string]: {x: number, y: number, radius: number}}} */
650
+ const circles = {};
651
+ for (let i = 0; i < sets.length; ++i) {
652
+ const set = sets[i];
653
+ circles[set.sets[0]] = {
654
+ x: positions[2 * i] * norm,
655
+ y: positions[2 * i + 1] * norm,
656
+ radius: Math.sqrt(set.size / Math.PI)
657
+ };
658
+ }
659
+ if (params.history) for (const h of params.history) scale(h.x, norm);
660
+ return circles;
661
+ }
662
+ /**
663
+ * Lays out a Venn diagram greedily, going from most overlapped sets to
664
+ * least overlapped, attempting to position each new set such that the
665
+ * overlapping areas to already positioned sets are basically right
666
+ * @param {ReadonlyArray<{size: number, sets: ReadonlyArray<string>}>} areas
667
+ * @return {{[key: string]: {x: number, y: number, radius: number}}}
668
+ */
669
+ function greedyLayout(areas, params) {
670
+ const loss = params && params.lossFunction ? params.lossFunction : lossFunction;
671
+ /** @type {{[key: string]: {x: number, y: number, radius: number}}} */
672
+ const circles = {};
673
+ /** @type {{[key: string]: {set: string, size: number, weight: number}[]}} */
674
+ const setOverlaps = {};
675
+ for (const area of areas) if (area.sets.length === 1) {
676
+ const set = area.sets[0];
677
+ circles[set] = {
678
+ x: 1e10,
679
+ y: 1e10,
680
+ rowid: circles.length,
681
+ size: area.size,
682
+ radius: Math.sqrt(area.size / Math.PI)
683
+ };
684
+ setOverlaps[set] = [];
685
+ }
686
+ areas = areas.filter((a) => a.sets.length === 2);
687
+ for (const current of areas) {
688
+ let weight = current.weight != null ? current.weight : 1;
689
+ const left = current.sets[0];
690
+ const right = current.sets[1];
691
+ if (current.size + SMALL >= Math.min(circles[left].size, circles[right].size)) weight = 0;
692
+ setOverlaps[left].push({
693
+ set: right,
694
+ size: current.size,
695
+ weight
696
+ });
697
+ setOverlaps[right].push({
698
+ set: left,
699
+ size: current.size,
700
+ weight
701
+ });
702
+ }
703
+ const mostOverlapped = [];
704
+ Object.keys(setOverlaps).forEach((set) => {
705
+ let size = 0;
706
+ for (let i = 0; i < setOverlaps[set].length; ++i) size += setOverlaps[set][i].size * setOverlaps[set][i].weight;
707
+ mostOverlapped.push({
708
+ set,
709
+ size
710
+ });
711
+ });
712
+ function sortOrder(a, b) {
713
+ return b.size - a.size;
714
+ }
715
+ mostOverlapped.sort(sortOrder);
716
+ const positioned = {};
717
+ function isPositioned(element) {
718
+ return element.set in positioned;
719
+ }
720
+ /**
721
+ * adds a point to the output
722
+ * @param {{x: number, y: number}} point
723
+ * @param {number} index
724
+ */
725
+ function positionSet(point, index) {
726
+ circles[index].x = point.x;
727
+ circles[index].y = point.y;
728
+ positioned[index] = true;
729
+ }
730
+ positionSet({
731
+ x: 0,
732
+ y: 0
733
+ }, mostOverlapped[0].set);
734
+ for (let i = 1; i < mostOverlapped.length; ++i) {
735
+ const setIndex = mostOverlapped[i].set;
736
+ const overlap = setOverlaps[setIndex].filter(isPositioned);
737
+ const set = circles[setIndex];
738
+ overlap.sort(sortOrder);
739
+ if (overlap.length === 0) throw "ERROR: missing pairwise overlap information";
740
+ /** @type {{x: number, y: number}[]} */
741
+ const points = [];
742
+ for (var j = 0; j < overlap.length; ++j) {
743
+ const p1 = circles[overlap[j].set];
744
+ const d1 = distanceFromIntersectArea(set.radius, p1.radius, overlap[j].size);
745
+ points.push({
746
+ x: p1.x + d1,
747
+ y: p1.y
748
+ });
749
+ points.push({
750
+ x: p1.x - d1,
751
+ y: p1.y
752
+ });
753
+ points.push({
754
+ y: p1.y + d1,
755
+ x: p1.x
756
+ });
757
+ points.push({
758
+ y: p1.y - d1,
759
+ x: p1.x
760
+ });
761
+ for (let k = j + 1; k < overlap.length; ++k) {
762
+ const p2 = circles[overlap[k].set];
763
+ const d2 = distanceFromIntersectArea(set.radius, p2.radius, overlap[k].size);
764
+ const extraPoints = circleCircleIntersection({
765
+ x: p1.x,
766
+ y: p1.y,
767
+ radius: d1
768
+ }, {
769
+ x: p2.x,
770
+ y: p2.y,
771
+ radius: d2
772
+ });
773
+ points.push(...extraPoints);
774
+ }
775
+ }
776
+ let bestLoss = 1e50;
777
+ let bestPoint = points[0];
778
+ for (const point of points) {
779
+ circles[setIndex].x = point.x;
780
+ circles[setIndex].y = point.y;
781
+ const localLoss = loss(circles, areas);
782
+ if (localLoss < bestLoss) {
783
+ bestLoss = localLoss;
784
+ bestPoint = point;
785
+ }
786
+ }
787
+ positionSet(bestPoint, setIndex);
788
+ }
789
+ return circles;
790
+ }
791
+ /**
792
+ * Given a bunch of sets, and the desired overlaps between these sets - computes
793
+ * the distance from the actual overlaps to the desired overlaps. Note that
794
+ * this method ignores overlaps of more than 2 circles
795
+ * @param {{[key: string]: <{x: number, y: number, radius: number}>}} circles
796
+ * @param {ReadonlyArray<{size: number, sets: ReadonlyArray<string>, weight?: number}>} overlaps
797
+ * @returns {number}
798
+ */
799
+ function lossFunction(circles, overlaps) {
800
+ let output = 0;
801
+ for (const area of overlaps) {
802
+ if (area.sets.length === 1) continue;
803
+ /** @type {number} */
804
+ let overlap;
805
+ if (area.sets.length === 2) {
806
+ const left = circles[area.sets[0]];
807
+ const right = circles[area.sets[1]];
808
+ overlap = circleOverlap(left.radius, right.radius, distance(left, right));
809
+ } else overlap = intersectionArea(area.sets.map((d) => circles[d]));
810
+ const weight = area.weight != null ? area.weight : 1;
811
+ output += weight * (overlap - area.size) * (overlap - area.size);
812
+ }
813
+ return output;
814
+ }
815
+ function logRatioLossFunction(circles, overlaps) {
816
+ let output = 0;
817
+ for (const area of overlaps) {
818
+ if (area.sets.length === 1) continue;
819
+ /** @type {number} */
820
+ let overlap;
821
+ if (area.sets.length === 2) {
822
+ const left = circles[area.sets[0]];
823
+ const right = circles[area.sets[1]];
824
+ overlap = circleOverlap(left.radius, right.radius, distance(left, right));
825
+ } else overlap = intersectionArea(area.sets.map((d) => circles[d]));
826
+ const weight = area.weight != null ? area.weight : 1;
827
+ const differenceFromIdeal = Math.log((overlap + 1) / (area.size + 1));
828
+ output += weight * differenceFromIdeal * differenceFromIdeal;
829
+ }
830
+ return output;
831
+ }
832
+ /**
833
+ * orientates a bunch of circles to point in orientation
834
+ * @param {{x :number, y: number, radius: number}[]} circles
835
+ * @param {number | undefined} orientation
836
+ * @param {((a: {x :number, y: number, radius: number}, b: {x :number, y: number, radius: number}) => number) | undefined} orientationOrder
837
+ */
838
+ function orientateCircles(circles, orientation, orientationOrder) {
839
+ if (orientationOrder == null) circles.sort((a, b) => b.radius - a.radius);
840
+ else circles.sort(orientationOrder);
841
+ if (circles.length > 0) {
842
+ const largestX = circles[0].x;
843
+ const largestY = circles[0].y;
844
+ for (const circle of circles) {
845
+ circle.x -= largestX;
846
+ circle.y -= largestY;
847
+ }
848
+ }
849
+ if (circles.length === 2) {
850
+ if (distance(circles[0], circles[1]) < Math.abs(circles[1].radius - circles[0].radius)) {
851
+ circles[1].x = circles[0].x + circles[0].radius - circles[1].radius - 1e-10;
852
+ circles[1].y = circles[0].y;
853
+ }
854
+ }
855
+ if (circles.length > 1) {
856
+ const rotation = Math.atan2(circles[1].x, circles[1].y) - orientation;
857
+ const c = Math.cos(rotation);
858
+ const s = Math.sin(rotation);
859
+ for (const circle of circles) {
860
+ const x = circle.x;
861
+ const y = circle.y;
862
+ circle.x = c * x - s * y;
863
+ circle.y = s * x + c * y;
864
+ }
865
+ }
866
+ if (circles.length > 2) {
867
+ let angle = Math.atan2(circles[2].x, circles[2].y) - orientation;
868
+ while (angle < 0) angle += 2 * Math.PI;
869
+ while (angle > 2 * Math.PI) angle -= 2 * Math.PI;
870
+ if (angle > Math.PI) {
871
+ const slope = circles[1].y / (1e-10 + circles[1].x);
872
+ for (const circle of circles) {
873
+ var d = (circle.x + slope * circle.y) / (1 + slope * slope);
874
+ circle.x = 2 * d - circle.x;
875
+ circle.y = 2 * d * slope - circle.y;
876
+ }
877
+ }
878
+ }
879
+ }
880
+ /**
881
+ *
882
+ * @param {ReadonlyArray<{x: number, y: number, radius: number}>} circles
883
+ * @returns {{x: number, y: number, radius: number}[][]}
884
+ */
885
+ function disjointCluster(circles) {
886
+ circles.forEach((circle) => {
887
+ circle.parent = circle;
888
+ });
889
+ function find(circle) {
890
+ if (circle.parent !== circle) circle.parent = find(circle.parent);
891
+ return circle.parent;
892
+ }
893
+ function union(x, y) {
894
+ const xRoot = find(x);
895
+ xRoot.parent = find(y);
896
+ }
897
+ for (let i = 0; i < circles.length; ++i) for (let j = i + 1; j < circles.length; ++j) {
898
+ const maxDistance = circles[i].radius + circles[j].radius;
899
+ if (distance(circles[i], circles[j]) + 1e-10 < maxDistance) union(circles[j], circles[i]);
900
+ }
901
+ /** @type {Map<string, {x: number, y: number, radius: number}[]>} */
902
+ const disjointClusters = /* @__PURE__ */ new Map();
903
+ for (let i = 0; i < circles.length; ++i) {
904
+ const setid = find(circles[i]).parent.setid;
905
+ if (!disjointClusters.has(setid)) disjointClusters.set(setid, []);
906
+ disjointClusters.get(setid).push(circles[i]);
907
+ }
908
+ circles.forEach((circle) => {
909
+ delete circle.parent;
910
+ });
911
+ return Array.from(disjointClusters.values());
912
+ }
913
+ /**
914
+ * @param {ReadonlyArray<{x :number, y: number, radius: number}>} circles
915
+ * @returns {{xRange: [number, number], yRange: [number, number]}}
916
+ */
917
+ function getBoundingBox(circles) {
918
+ const minMax = (d) => {
919
+ return {
920
+ max: circles.reduce((acc, c) => Math.max(acc, c[d] + c.radius), Number.NEGATIVE_INFINITY),
921
+ min: circles.reduce((acc, c) => Math.min(acc, c[d] - c.radius), Number.POSITIVE_INFINITY)
922
+ };
923
+ };
924
+ return {
925
+ xRange: minMax("x"),
926
+ yRange: minMax("y")
927
+ };
928
+ }
929
+ /**
930
+ *
931
+ * @param {{[setid: string]: {x: number, y: number, radius: number}}} solution
932
+ * @param {undefined | number} orientation
933
+ * @param {((a: {x :number, y: number, radius: number}, b: {x :number, y: number, radius: number}) => number) | undefined} orientationOrder
934
+ * @returns {{[setid: string]: {x: number, y: number, radius: number}}}
935
+ */
936
+ function normalizeSolution(solution, orientation, orientationOrder) {
937
+ if (orientation == null) orientation = Math.PI / 2;
938
+ let circles = fromObjectNotation(solution).map((d) => Object.assign({}, d));
939
+ const clusters = disjointCluster(circles);
940
+ for (const cluster of clusters) {
941
+ orientateCircles(cluster, orientation, orientationOrder);
942
+ const bounds = getBoundingBox(cluster);
943
+ cluster.size = (bounds.xRange.max - bounds.xRange.min) * (bounds.yRange.max - bounds.yRange.min);
944
+ cluster.bounds = bounds;
945
+ }
946
+ clusters.sort((a, b) => b.size - a.size);
947
+ circles = clusters[0];
948
+ let returnBounds = circles.bounds;
949
+ const spacing = (returnBounds.xRange.max - returnBounds.xRange.min) / 50;
950
+ /**
951
+ * @param {ReadonlyArray<{x: number, y: number, radius: number, setid: string}>} cluster
952
+ * @param {boolean} right
953
+ * @param {boolean} bottom
954
+ */
955
+ function addCluster(cluster, right, bottom) {
956
+ if (!cluster) return;
957
+ const bounds = cluster.bounds;
958
+ /** @type {number} */
959
+ let xOffset;
960
+ /** @type {number} */
961
+ let yOffset;
962
+ if (right) xOffset = returnBounds.xRange.max - bounds.xRange.min + spacing;
963
+ else {
964
+ xOffset = returnBounds.xRange.max - bounds.xRange.max;
965
+ const centreing = (bounds.xRange.max - bounds.xRange.min) / 2 - (returnBounds.xRange.max - returnBounds.xRange.min) / 2;
966
+ if (centreing < 0) xOffset += centreing;
967
+ }
968
+ if (bottom) yOffset = returnBounds.yRange.max - bounds.yRange.min + spacing;
969
+ else {
970
+ yOffset = returnBounds.yRange.max - bounds.yRange.max;
971
+ const centreing = (bounds.yRange.max - bounds.yRange.min) / 2 - (returnBounds.yRange.max - returnBounds.yRange.min) / 2;
972
+ if (centreing < 0) yOffset += centreing;
973
+ }
974
+ for (const c of cluster) {
975
+ c.x += xOffset;
976
+ c.y += yOffset;
977
+ circles.push(c);
978
+ }
979
+ }
980
+ let index = 1;
981
+ while (index < clusters.length) {
982
+ addCluster(clusters[index], true, false);
983
+ addCluster(clusters[index + 1], false, true);
984
+ addCluster(clusters[index + 2], true, true);
985
+ index += 3;
986
+ returnBounds = getBoundingBox(circles);
987
+ }
988
+ return toObjectNotation(circles);
989
+ }
990
+ /**
991
+ * Scales a solution from venn.venn or venn.greedyLayout such that it fits in
992
+ * a rectangle of width/height - with padding around the borders. also
993
+ * centers the diagram in the available space at the same time.
994
+ * If the scale parameter is not null, this automatic scaling is ignored in favor of this custom one
995
+ * @param {{[setid: string]: {x: number, y: number, radius: number}}} solution
996
+ * @param {number} width
997
+ * @param {number} height
998
+ * @param {number} padding
999
+ * @param {boolean} scaleToFit
1000
+ * @returns {{[setid: string]: {x: number, y: number, radius: number}}}
1001
+ */
1002
+ function scaleSolution(solution, width, height, padding, scaleToFit) {
1003
+ const circles = fromObjectNotation(solution);
1004
+ width -= 2 * padding;
1005
+ height -= 2 * padding;
1006
+ const { xRange, yRange } = getBoundingBox(circles);
1007
+ if (xRange.max === xRange.min || yRange.max === yRange.min) {
1008
+ console.log("not scaling solution: zero size detected");
1009
+ return solution;
1010
+ }
1011
+ /** @type {number} */
1012
+ let xScaling;
1013
+ /** @type {number} */
1014
+ let yScaling;
1015
+ if (scaleToFit) {
1016
+ const toScaleDiameter = Math.sqrt(scaleToFit / Math.PI) * 2;
1017
+ xScaling = width / toScaleDiameter;
1018
+ yScaling = height / toScaleDiameter;
1019
+ } else {
1020
+ xScaling = width / (xRange.max - xRange.min);
1021
+ yScaling = height / (yRange.max - yRange.min);
1022
+ }
1023
+ const scaling = Math.min(yScaling, xScaling);
1024
+ const xOffset = (width - (xRange.max - xRange.min) * scaling) / 2;
1025
+ const yOffset = (height - (yRange.max - yRange.min) * scaling) / 2;
1026
+ return toObjectNotation(circles.map((circle) => ({
1027
+ radius: scaling * circle.radius,
1028
+ x: padding + xOffset + (circle.x - xRange.min) * scaling,
1029
+ y: padding + yOffset + (circle.y - yRange.min) * scaling,
1030
+ setid: circle.setid
1031
+ })));
1032
+ }
1033
+ /**
1034
+ * @param {readonly {x: number, y: number, radius: number, setid: string}[]} circles
1035
+ * @returns {{[setid: string]: {x: number, y: number, radius: number, setid: string}}}
1036
+ */
1037
+ function toObjectNotation(circles) {
1038
+ /** @type {{[setid: string]: {x: number, y: number, radius: number, setid: string}}} */
1039
+ const r = {};
1040
+ for (const circle of circles) r[circle.setid] = circle;
1041
+ return r;
1042
+ }
1043
+ /**
1044
+ * @param {{[setid: string]: {x: number, y: number, radius: number}}} solution
1045
+ * @returns {{x: number, y: number, radius: number, setid: string}[]}}
1046
+ */
1047
+ function fromObjectNotation(solution) {
1048
+ return Object.keys(solution).map((id) => Object.assign(solution[id], { setid: id }));
1049
+ }
1050
+ /**
1051
+ * VennDiagram includes an optional `options` parameter containing the following option(s):
1052
+ *
1053
+ * `colourScheme: Array<String>`
1054
+ * A list of color values to be applied when coloring diagram circles.
1055
+ *
1056
+ * `symmetricalTextCentre: Boolean`
1057
+ * Whether to symmetrically center each circle's text horizontally and vertically.
1058
+ * Defaults to `false`.
1059
+ *
1060
+ * `textFill: String`
1061
+ * The color to be applied to the text within each circle.
1062
+ *
1063
+ * @param {object} options
1064
+ */
1065
+ function VennDiagram(options = {}) {
1066
+ let useViewBox = false, width = 600, height = 350, padding = 15, duration = 1e3, orientation = Math.PI / 2, normalize = true, scaleToFit = null, wrap = true, styled = true, fontSize = null, orientationOrder = null, distinct = false, round = null, symmetricalTextCentre = options && options.symmetricalTextCentre ? options.symmetricalTextCentre : false, colourMap = {}, colourScheme = options && options.colourScheme ? options.colourScheme : options && options.colorScheme ? options.colorScheme : [
1067
+ "#1f77b4",
1068
+ "#ff7f0e",
1069
+ "#2ca02c",
1070
+ "#d62728",
1071
+ "#9467bd",
1072
+ "#8c564b",
1073
+ "#e377c2",
1074
+ "#7f7f7f",
1075
+ "#bcbd22",
1076
+ "#17becf"
1077
+ ], colourIndex = 0, colours = function(key) {
1078
+ if (key in colourMap) return colourMap[key];
1079
+ var ret = colourMap[key] = colourScheme[colourIndex];
1080
+ colourIndex += 1;
1081
+ if (colourIndex >= colourScheme.length) colourIndex = 0;
1082
+ return ret;
1083
+ }, layoutFunction = venn, loss = lossFunction;
1084
+ function chart(selection) {
1085
+ let data = selection.datum();
1086
+ const toRemove = /* @__PURE__ */ new Set();
1087
+ data.forEach((datum) => {
1088
+ if (datum.size == 0 && datum.sets.length == 1) toRemove.add(datum.sets[0]);
1089
+ });
1090
+ data = data.filter((datum) => !datum.sets.some((set) => toRemove.has(set)));
1091
+ let circles = {};
1092
+ let textCentres = {};
1093
+ if (data.length > 0) {
1094
+ let solution = layoutFunction(data, {
1095
+ lossFunction: loss,
1096
+ distinct
1097
+ });
1098
+ if (normalize) solution = normalizeSolution(solution, orientation, orientationOrder);
1099
+ circles = scaleSolution(solution, width, height, padding, scaleToFit);
1100
+ textCentres = computeTextCentres(circles, data, symmetricalTextCentre);
1101
+ }
1102
+ const labels = {};
1103
+ data.forEach((datum) => {
1104
+ if (datum.label) labels[datum.sets] = datum.label;
1105
+ });
1106
+ function label(d) {
1107
+ if (d.sets in labels) return labels[d.sets];
1108
+ if (d.sets.length == 1) return "" + d.sets[0];
1109
+ }
1110
+ selection.selectAll("svg").data([circles]).enter().append("svg");
1111
+ const svg = selection.select("svg");
1112
+ if (useViewBox) svg.attr("viewBox", `0 0 ${width} ${height}`);
1113
+ else svg.attr("width", width).attr("height", height);
1114
+ const previous = {};
1115
+ let hasPrevious = false;
1116
+ svg.selectAll(".venn-area path").each(function(d) {
1117
+ const path = this.getAttribute("d");
1118
+ if (d.sets.length == 1 && path && !distinct) {
1119
+ hasPrevious = true;
1120
+ previous[d.sets[0]] = circleFromPath(path);
1121
+ }
1122
+ });
1123
+ function pathTween(d) {
1124
+ return (t) => {
1125
+ return intersectionAreaPath(d.sets.map((set) => {
1126
+ let start = previous[set];
1127
+ let end = circles[set];
1128
+ if (!start) start = {
1129
+ x: width / 2,
1130
+ y: height / 2,
1131
+ radius: 1
1132
+ };
1133
+ if (!end) end = {
1134
+ x: width / 2,
1135
+ y: height / 2,
1136
+ radius: 1
1137
+ };
1138
+ return {
1139
+ x: start.x * (1 - t) + end.x * t,
1140
+ y: start.y * (1 - t) + end.y * t,
1141
+ radius: start.radius * (1 - t) + end.radius * t
1142
+ };
1143
+ }), round);
1144
+ };
1145
+ }
1146
+ const nodes = svg.selectAll(".venn-area").data(data, (d) => d.sets);
1147
+ const enter = nodes.enter().append("g").attr("class", (d) => `venn-area venn-${d.sets.length == 1 ? "circle" : "intersection"}${d.colour || d.color ? " venn-coloured" : ""}`).attr("data-venn-sets", (d) => d.sets.join("_"));
1148
+ const enterPath = enter.append("path");
1149
+ const enterText = enter.append("text").attr("class", "label").text((d) => label(d)).attr("text-anchor", "middle").attr("dy", ".35em").attr("x", width / 2).attr("y", height / 2);
1150
+ if (styled) {
1151
+ enterPath.style("fill-opacity", "0").filter((d) => d.sets.length == 1).style("fill", (d) => d.colour ? d.colour : d.color ? d.color : colours(d.sets)).style("fill-opacity", ".25");
1152
+ enterText.style("fill", (d) => {
1153
+ if (d.colour || d.color) return "#FFF";
1154
+ if (options.textFill) return options.textFill;
1155
+ return d.sets.length == 1 ? colours(d.sets) : "#444";
1156
+ });
1157
+ }
1158
+ function asTransition(s) {
1159
+ if (typeof s.transition === "function") return s.transition("venn").duration(duration);
1160
+ return s;
1161
+ }
1162
+ let update = selection;
1163
+ if (hasPrevious && typeof update.transition === "function") {
1164
+ update = asTransition(selection);
1165
+ update.selectAll("path").attrTween("d", pathTween);
1166
+ } else update.selectAll("path").attr("d", (d) => intersectionAreaPath(d.sets.map((set) => circles[set])), round);
1167
+ const updateText = update.selectAll("text").filter((d) => d.sets in textCentres).text((d) => label(d)).attr("x", (d) => Math.floor(textCentres[d.sets].x)).attr("y", (d) => Math.floor(textCentres[d.sets].y));
1168
+ if (wrap) if (hasPrevious) if ("on" in updateText) updateText.on("end", wrapText(circles, label));
1169
+ else updateText.each("end", wrapText(circles, label));
1170
+ else updateText.each(wrapText(circles, label));
1171
+ const exit = asTransition(nodes.exit()).remove();
1172
+ if (typeof nodes.transition === "function") exit.selectAll("path").attrTween("d", pathTween);
1173
+ const exitText = exit.selectAll("text").attr("x", width / 2).attr("y", height / 2);
1174
+ if (fontSize !== null) {
1175
+ enterText.style("font-size", "0px");
1176
+ updateText.style("font-size", fontSize);
1177
+ exitText.style("font-size", "0px");
1178
+ }
1179
+ return {
1180
+ circles,
1181
+ textCentres,
1182
+ nodes,
1183
+ enter,
1184
+ update,
1185
+ exit
1186
+ };
1187
+ }
1188
+ chart.wrap = function(_) {
1189
+ if (!arguments.length) return wrap;
1190
+ wrap = _;
1191
+ return chart;
1192
+ };
1193
+ chart.useViewBox = function() {
1194
+ useViewBox = true;
1195
+ return chart;
1196
+ };
1197
+ chart.width = function(_) {
1198
+ if (!arguments.length) return width;
1199
+ width = _;
1200
+ return chart;
1201
+ };
1202
+ chart.height = function(_) {
1203
+ if (!arguments.length) return height;
1204
+ height = _;
1205
+ return chart;
1206
+ };
1207
+ chart.padding = function(_) {
1208
+ if (!arguments.length) return padding;
1209
+ padding = _;
1210
+ return chart;
1211
+ };
1212
+ chart.distinct = function(_) {
1213
+ if (!arguments.length) return distinct;
1214
+ distinct = _;
1215
+ return chart;
1216
+ };
1217
+ chart.colours = function(_) {
1218
+ if (!arguments.length) return colours;
1219
+ colours = _;
1220
+ return chart;
1221
+ };
1222
+ chart.colors = function(_) {
1223
+ if (!arguments.length) return colours;
1224
+ colours = _;
1225
+ return chart;
1226
+ };
1227
+ chart.fontSize = function(_) {
1228
+ if (!arguments.length) return fontSize;
1229
+ fontSize = _;
1230
+ return chart;
1231
+ };
1232
+ chart.round = function(_) {
1233
+ if (!arguments.length) return round;
1234
+ round = _;
1235
+ return chart;
1236
+ };
1237
+ chart.duration = function(_) {
1238
+ if (!arguments.length) return duration;
1239
+ duration = _;
1240
+ return chart;
1241
+ };
1242
+ chart.layoutFunction = function(_) {
1243
+ if (!arguments.length) return layoutFunction;
1244
+ layoutFunction = _;
1245
+ return chart;
1246
+ };
1247
+ chart.normalize = function(_) {
1248
+ if (!arguments.length) return normalize;
1249
+ normalize = _;
1250
+ return chart;
1251
+ };
1252
+ chart.scaleToFit = function(_) {
1253
+ if (!arguments.length) return scaleToFit;
1254
+ scaleToFit = _;
1255
+ return chart;
1256
+ };
1257
+ chart.styled = function(_) {
1258
+ if (!arguments.length) return styled;
1259
+ styled = _;
1260
+ return chart;
1261
+ };
1262
+ chart.orientation = function(_) {
1263
+ if (!arguments.length) return orientation;
1264
+ orientation = _;
1265
+ return chart;
1266
+ };
1267
+ chart.orientationOrder = function(_) {
1268
+ if (!arguments.length) return orientationOrder;
1269
+ orientationOrder = _;
1270
+ return chart;
1271
+ };
1272
+ chart.lossFunction = function(_) {
1273
+ if (!arguments.length) return loss;
1274
+ loss = _ === "default" ? lossFunction : _ === "logRatio" ? logRatioLossFunction : _;
1275
+ return chart;
1276
+ };
1277
+ return chart;
1278
+ }
1279
+ function wrapText(circles, labeller) {
1280
+ return function(data) {
1281
+ const text = this;
1282
+ const width = circles[data.sets[0]].radius || 50;
1283
+ const label = labeller(data) || "";
1284
+ const words = label.split(/\s+/).reverse();
1285
+ const minChars = (label.length + words.length) / 3;
1286
+ let word = words.pop();
1287
+ let line = [word];
1288
+ let lineNumber = 0;
1289
+ const lineHeight = 1.1;
1290
+ text.textContent = null;
1291
+ const tspans = [];
1292
+ function append(word) {
1293
+ const tspan = text.ownerDocument.createElementNS(text.namespaceURI, "tspan");
1294
+ tspan.textContent = word;
1295
+ tspans.push(tspan);
1296
+ text.append(tspan);
1297
+ return tspan;
1298
+ }
1299
+ let tspan = append(word);
1300
+ while (true) {
1301
+ word = words.pop();
1302
+ if (!word) break;
1303
+ line.push(word);
1304
+ const joined = line.join(" ");
1305
+ tspan.textContent = joined;
1306
+ if (joined.length > minChars && tspan.getComputedTextLength() > width) {
1307
+ line.pop();
1308
+ tspan.textContent = line.join(" ");
1309
+ line = [word];
1310
+ tspan = append(word);
1311
+ lineNumber++;
1312
+ }
1313
+ }
1314
+ const initial = .35 - lineNumber * lineHeight / 2;
1315
+ const x = text.getAttribute("x");
1316
+ const y = text.getAttribute("y");
1317
+ tspans.forEach((t, i) => {
1318
+ t.setAttribute("x", x);
1319
+ t.setAttribute("y", y);
1320
+ t.setAttribute("dy", `${initial + i * lineHeight}em`);
1321
+ });
1322
+ };
1323
+ }
1324
+ /**
1325
+ *
1326
+ * @param {{x: number, y: number}} current
1327
+ * @param {ReadonlyArray<{x: number, y: number}>} interior
1328
+ * @param {ReadonlyArray<{x: number, y: number}>} exterior
1329
+ * @returns {number}
1330
+ */
1331
+ function circleMargin(current, interior, exterior) {
1332
+ let margin = interior[0].radius - distance(interior[0], current);
1333
+ for (let i = 1; i < interior.length; ++i) {
1334
+ const m = interior[i].radius - distance(interior[i], current);
1335
+ if (m <= margin) margin = m;
1336
+ }
1337
+ for (let i = 0; i < exterior.length; ++i) {
1338
+ const m = distance(exterior[i], current) - exterior[i].radius;
1339
+ if (m <= margin) margin = m;
1340
+ }
1341
+ return margin;
1342
+ }
1343
+ /**
1344
+ * compute the center of some circles by maximizing the margin of
1345
+ * the center point relative to the circles (interior) after subtracting
1346
+ * nearby circles (exterior)
1347
+ * @param {readonly {x: number, y: number, radius: number}[]} interior
1348
+ * @param {readonly {x: number, y: number, radius: number}[]} exterior
1349
+ * @param {boolean} symmetricalTextCentre
1350
+ * @returns {{x:number, y: number}}
1351
+ */
1352
+ function computeTextCentre(interior, exterior, symmetricalTextCentre) {
1353
+ /** @type {{x: number, y: number}[]} */
1354
+ const points = [];
1355
+ for (const c of interior) {
1356
+ points.push({
1357
+ x: c.x,
1358
+ y: c.y
1359
+ });
1360
+ points.push({
1361
+ x: c.x + c.radius / 2,
1362
+ y: c.y
1363
+ });
1364
+ points.push({
1365
+ x: c.x - c.radius / 2,
1366
+ y: c.y
1367
+ });
1368
+ points.push({
1369
+ x: c.x,
1370
+ y: c.y + c.radius / 2
1371
+ });
1372
+ points.push({
1373
+ x: c.x,
1374
+ y: c.y - c.radius / 2
1375
+ });
1376
+ }
1377
+ let initial = points[0];
1378
+ let margin = circleMargin(points[0], interior, exterior);
1379
+ for (let i = 1; i < points.length; ++i) {
1380
+ const m = circleMargin(points[i], interior, exterior);
1381
+ if (m >= margin) {
1382
+ initial = points[i];
1383
+ margin = m;
1384
+ }
1385
+ }
1386
+ const solution = nelderMead((p) => -1 * circleMargin({
1387
+ x: p[0],
1388
+ y: p[1]
1389
+ }, interior, exterior), [initial.x, initial.y], {
1390
+ maxIterations: 500,
1391
+ minErrorDelta: 1e-10
1392
+ }).x;
1393
+ const ret = {
1394
+ x: symmetricalTextCentre ? 0 : solution[0],
1395
+ y: solution[1]
1396
+ };
1397
+ let valid = true;
1398
+ for (const i of interior) if (distance(ret, i) > i.radius) {
1399
+ valid = false;
1400
+ break;
1401
+ }
1402
+ for (const e of exterior) if (distance(ret, e) < e.radius) {
1403
+ valid = false;
1404
+ break;
1405
+ }
1406
+ if (valid) return ret;
1407
+ if (interior.length == 1) return {
1408
+ x: interior[0].x,
1409
+ y: interior[0].y
1410
+ };
1411
+ const areaStats = {};
1412
+ intersectionArea(interior, areaStats);
1413
+ if (areaStats.arcs.length === 0) return {
1414
+ x: 0,
1415
+ y: -1e3,
1416
+ disjoint: true
1417
+ };
1418
+ if (areaStats.arcs.length == 1) return {
1419
+ x: areaStats.arcs[0].circle.x,
1420
+ y: areaStats.arcs[0].circle.y
1421
+ };
1422
+ if (exterior.length) return computeTextCentre(interior, []);
1423
+ return getCenter(areaStats.arcs.map((a) => a.p1));
1424
+ }
1425
+ function getOverlappingCircles(circles) {
1426
+ const ret = {};
1427
+ const circleids = Object.keys(circles);
1428
+ for (const circleid of circleids) ret[circleid] = [];
1429
+ for (let i = 0; i < circleids.length; i++) {
1430
+ const ci = circleids[i];
1431
+ const a = circles[ci];
1432
+ for (let j = i + 1; j < circleids.length; ++j) {
1433
+ const cj = circleids[j];
1434
+ const b = circles[cj];
1435
+ const d = distance(a, b);
1436
+ if (d + b.radius <= a.radius + 1e-10) ret[cj].push(ci);
1437
+ else if (d + a.radius <= b.radius + 1e-10) ret[ci].push(cj);
1438
+ }
1439
+ }
1440
+ return ret;
1441
+ }
1442
+ function computeTextCentres(circles, areas, symmetricalTextCentre) {
1443
+ const ret = {};
1444
+ const overlapped = getOverlappingCircles(circles);
1445
+ for (let i = 0; i < areas.length; ++i) {
1446
+ const area = areas[i].sets;
1447
+ const areaids = {};
1448
+ const exclude = {};
1449
+ for (let j = 0; j < area.length; ++j) {
1450
+ areaids[area[j]] = true;
1451
+ const overlaps = overlapped[area[j]];
1452
+ for (let k = 0; k < overlaps.length; ++k) exclude[overlaps[k]] = true;
1453
+ }
1454
+ const interior = [];
1455
+ const exterior = [];
1456
+ for (let setid in circles) if (setid in areaids) interior.push(circles[setid]);
1457
+ else if (!(setid in exclude)) exterior.push(circles[setid]);
1458
+ const centre = computeTextCentre(interior, exterior, symmetricalTextCentre);
1459
+ ret[area] = centre;
1460
+ if (centre.disjoint && areas[i].size > 0) console.log("WARNING: area " + area + " not represented on screen");
1461
+ }
1462
+ return ret;
1463
+ }
1464
+ /**
1465
+ * @param {number} x
1466
+ * @param {number} y
1467
+ * @param {number} r
1468
+ * @returns {string}
1469
+ */
1470
+ function circlePath(x, y, r) {
1471
+ const ret = [];
1472
+ ret.push("\nM", x, y);
1473
+ ret.push("\nm", -r, 0);
1474
+ ret.push("\na", r, r, 0, 1, 0, r * 2, 0);
1475
+ ret.push("\na", r, r, 0, 1, 0, -r * 2, 0);
1476
+ return ret.join(" ");
1477
+ }
1478
+ /**
1479
+ * inverse of the circlePath function, returns a circle object from an svg path
1480
+ * @param {string} path
1481
+ * @returns {{x: number, y: number, radius: number}}
1482
+ */
1483
+ function circleFromPath(path) {
1484
+ const tokens = path.split(" ");
1485
+ return {
1486
+ x: Number.parseFloat(tokens[1]),
1487
+ y: Number.parseFloat(tokens[2]),
1488
+ radius: -Number.parseFloat(tokens[4])
1489
+ };
1490
+ }
1491
+ function intersectionAreaArcs(circles) {
1492
+ if (circles.length === 0) return [];
1493
+ const stats = {};
1494
+ intersectionArea(circles, stats);
1495
+ return stats.arcs;
1496
+ }
1497
+ function arcsToPath(arcs, round) {
1498
+ if (arcs.length === 0) return "M 0 0";
1499
+ const rFactor = Math.pow(10, round || 0);
1500
+ const r = round != null ? (v) => Math.round(v * rFactor) / rFactor : (v) => v;
1501
+ if (arcs.length == 1) {
1502
+ const circle = arcs[0].circle;
1503
+ return circlePath(r(circle.x), r(circle.y), r(circle.radius));
1504
+ }
1505
+ const ret = [
1506
+ "\nM",
1507
+ r(arcs[0].p2.x),
1508
+ r(arcs[0].p2.y)
1509
+ ];
1510
+ for (const arc of arcs) {
1511
+ const radius = r(arc.circle.radius);
1512
+ ret.push("\nA", radius, radius, 0, arc.large ? 1 : 0, arc.sweep ? 1 : 0, r(arc.p1.x), r(arc.p1.y));
1513
+ }
1514
+ return ret.join(" ");
1515
+ }
1516
+ /**
1517
+ * returns a svg path of the intersection area of a bunch of circles
1518
+ * @param {ReadonlyArray<{x: number, y: number, radius: number}>} circles
1519
+ * @returns {string}
1520
+ */
1521
+ function intersectionAreaPath(circles, round) {
1522
+ return arcsToPath(intersectionAreaArcs(circles), round);
1523
+ }
1524
+ function layout(data, options = {}) {
1525
+ const { lossFunction: loss, layoutFunction: layout = venn, normalize = true, orientation = Math.PI / 2, orientationOrder, width = 600, height = 350, padding = 15, scaleToFit = false, symmetricalTextCentre = false, distinct, round = 2 } = options;
1526
+ let solution = layout(data, {
1527
+ lossFunction: loss === "default" || !loss ? lossFunction : loss === "logRatio" ? logRatioLossFunction : loss,
1528
+ distinct
1529
+ });
1530
+ if (normalize) solution = normalizeSolution(solution, orientation, orientationOrder);
1531
+ const circles = scaleSolution(solution, width, height, padding, scaleToFit);
1532
+ const textCentres = computeTextCentres(circles, data, symmetricalTextCentre);
1533
+ const circleLookup = new Map(Object.keys(circles).map((set) => [set, {
1534
+ set,
1535
+ x: circles[set].x,
1536
+ y: circles[set].y,
1537
+ radius: circles[set].radius
1538
+ }]));
1539
+ const helpers = data.map((area) => {
1540
+ const circles = area.sets.map((s) => circleLookup.get(s));
1541
+ const arcs = intersectionAreaArcs(circles);
1542
+ return {
1543
+ circles,
1544
+ arcs,
1545
+ path: arcsToPath(arcs, round),
1546
+ area,
1547
+ has: new Set(area.sets)
1548
+ };
1549
+ });
1550
+ function genDistinctPath(sets) {
1551
+ let r = "";
1552
+ for (const e of helpers) if (e.has.size > sets.length && sets.every((s) => e.has.has(s))) r += " " + e.path;
1553
+ return r;
1554
+ }
1555
+ return helpers.map(({ circles, arcs, path, area }) => {
1556
+ return {
1557
+ data: area,
1558
+ text: textCentres[area.sets],
1559
+ circles,
1560
+ arcs,
1561
+ path,
1562
+ distinctPath: path + genDistinctPath(area.sets)
1563
+ };
1564
+ });
1565
+ }
1566
+
1567
+ //#endregion
1568
+ //#region ../../node_modules/.pnpm/mermaid@11.17.2/node_modules/mermaid/dist/chunks/mermaid.core/vennDiagram-4TSXK5OY.mjs
1569
+ var parser = (function() {
1570
+ var o = /* @__PURE__ */ __name(function(k, v, o2, l) {
1571
+ for (o2 = o2 || {}, l = k.length; l--; o2[k[l]] = v);
1572
+ return o2;
1573
+ }, "o"), $V0 = [5, 8], $V1 = [
1574
+ 7,
1575
+ 8,
1576
+ 11,
1577
+ 12,
1578
+ 17,
1579
+ 19,
1580
+ 22,
1581
+ 24
1582
+ ], $V2 = [1, 17], $V3 = [1, 18], $V4 = [
1583
+ 7,
1584
+ 8,
1585
+ 11,
1586
+ 12,
1587
+ 14,
1588
+ 15,
1589
+ 16,
1590
+ 17,
1591
+ 19,
1592
+ 20,
1593
+ 21,
1594
+ 22,
1595
+ 24,
1596
+ 27
1597
+ ], $V5 = [1, 31], $V6 = [1, 39], $V7 = [
1598
+ 7,
1599
+ 8,
1600
+ 11,
1601
+ 12,
1602
+ 17,
1603
+ 19,
1604
+ 22,
1605
+ 24,
1606
+ 27
1607
+ ], $V8 = [1, 57], $V9 = [1, 56], $Va = [1, 58], $Vb = [1, 59], $Vc = [1, 60], $Vd = [
1608
+ 7,
1609
+ 8,
1610
+ 11,
1611
+ 12,
1612
+ 16,
1613
+ 17,
1614
+ 19,
1615
+ 20,
1616
+ 22,
1617
+ 24,
1618
+ 27,
1619
+ 31,
1620
+ 32,
1621
+ 33
1622
+ ];
1623
+ var parser2 = {
1624
+ trace: /* @__PURE__ */ __name(function trace() {}, "trace"),
1625
+ yy: {},
1626
+ symbols_: {
1627
+ "error": 2,
1628
+ "start": 3,
1629
+ "optNewlines": 4,
1630
+ "VENN": 5,
1631
+ "document": 6,
1632
+ "EOF": 7,
1633
+ "NEWLINE": 8,
1634
+ "line": 9,
1635
+ "statement": 10,
1636
+ "TITLE": 11,
1637
+ "SET": 12,
1638
+ "identifier": 13,
1639
+ "BRACKET_LABEL": 14,
1640
+ "COLON": 15,
1641
+ "NUMERIC": 16,
1642
+ "UNION": 17,
1643
+ "identifierList": 18,
1644
+ "TEXT": 19,
1645
+ "IDENTIFIER": 20,
1646
+ "STRING": 21,
1647
+ "INDENT_TEXT": 22,
1648
+ "indentedTextTail": 23,
1649
+ "STYLE": 24,
1650
+ "stylesOpt": 25,
1651
+ "styleField": 26,
1652
+ "COMMA": 27,
1653
+ "styleValue": 28,
1654
+ "valueTokens": 29,
1655
+ "valueToken": 30,
1656
+ "HEXCOLOR": 31,
1657
+ "RGBCOLOR": 32,
1658
+ "RGBACOLOR": 33,
1659
+ "$accept": 0,
1660
+ "$end": 1
1661
+ },
1662
+ terminals_: {
1663
+ 2: "error",
1664
+ 5: "VENN",
1665
+ 7: "EOF",
1666
+ 8: "NEWLINE",
1667
+ 11: "TITLE",
1668
+ 12: "SET",
1669
+ 14: "BRACKET_LABEL",
1670
+ 15: "COLON",
1671
+ 16: "NUMERIC",
1672
+ 17: "UNION",
1673
+ 19: "TEXT",
1674
+ 20: "IDENTIFIER",
1675
+ 21: "STRING",
1676
+ 22: "INDENT_TEXT",
1677
+ 24: "STYLE",
1678
+ 27: "COMMA",
1679
+ 31: "HEXCOLOR",
1680
+ 32: "RGBCOLOR",
1681
+ 33: "RGBACOLOR"
1682
+ },
1683
+ productions_: [
1684
+ 0,
1685
+ [3, 4],
1686
+ [4, 0],
1687
+ [4, 2],
1688
+ [6, 0],
1689
+ [6, 2],
1690
+ [9, 1],
1691
+ [9, 1],
1692
+ [10, 1],
1693
+ [10, 2],
1694
+ [10, 3],
1695
+ [10, 4],
1696
+ [10, 5],
1697
+ [10, 2],
1698
+ [10, 3],
1699
+ [10, 4],
1700
+ [10, 5],
1701
+ [10, 3],
1702
+ [10, 3],
1703
+ [10, 3],
1704
+ [10, 4],
1705
+ [10, 4],
1706
+ [10, 2],
1707
+ [10, 3],
1708
+ [23, 1],
1709
+ [23, 1],
1710
+ [23, 1],
1711
+ [23, 2],
1712
+ [23, 2],
1713
+ [25, 1],
1714
+ [25, 3],
1715
+ [26, 3],
1716
+ [28, 1],
1717
+ [28, 1],
1718
+ [29, 1],
1719
+ [29, 2],
1720
+ [30, 1],
1721
+ [30, 1],
1722
+ [30, 1],
1723
+ [30, 1],
1724
+ [30, 1],
1725
+ [18, 1],
1726
+ [18, 3],
1727
+ [13, 1],
1728
+ [13, 1]
1729
+ ],
1730
+ performAction: /* @__PURE__ */ __name(function anonymous(yytext, yyleng, yylineno, yy, yystate, $$, _$) {
1731
+ var $0 = $$.length - 1;
1732
+ switch (yystate) {
1733
+ case 1: return $$[$0 - 1];
1734
+ case 2:
1735
+ case 3:
1736
+ case 4:
1737
+ this.$ = [];
1738
+ break;
1739
+ case 5:
1740
+ $$[$0 - 1].push($$[$0]);
1741
+ this.$ = $$[$0 - 1];
1742
+ break;
1743
+ case 6:
1744
+ this.$ = [];
1745
+ break;
1746
+ case 7:
1747
+ case 22:
1748
+ case 32:
1749
+ case 36:
1750
+ case 37:
1751
+ case 38:
1752
+ case 39:
1753
+ case 40:
1754
+ this.$ = $$[$0];
1755
+ break;
1756
+ case 8:
1757
+ yy.setDiagramTitle($$[$0].substr(6));
1758
+ this.$ = $$[$0].substr(6);
1759
+ break;
1760
+ case 9:
1761
+ yy.addSubsetData([$$[$0]], void 0, void 0);
1762
+ if (yy.setIndentMode) yy.setIndentMode(true);
1763
+ break;
1764
+ case 10:
1765
+ yy.addSubsetData([$$[$0 - 1]], $$[$0], void 0);
1766
+ if (yy.setIndentMode) yy.setIndentMode(true);
1767
+ break;
1768
+ case 11:
1769
+ yy.addSubsetData([$$[$0 - 2]], void 0, parseFloat($$[$0]));
1770
+ if (yy.setIndentMode) yy.setIndentMode(true);
1771
+ break;
1772
+ case 12:
1773
+ yy.addSubsetData([$$[$0 - 3]], $$[$0 - 2], parseFloat($$[$0]));
1774
+ if (yy.setIndentMode) yy.setIndentMode(true);
1775
+ break;
1776
+ case 13:
1777
+ if ($$[$0].length < 2) throw new Error("union requires multiple identifiers");
1778
+ if (yy.validateUnionIdentifiers) yy.validateUnionIdentifiers($$[$0]);
1779
+ yy.addSubsetData($$[$0], void 0, void 0);
1780
+ if (yy.setIndentMode) yy.setIndentMode(true);
1781
+ break;
1782
+ case 14:
1783
+ if ($$[$0 - 1].length < 2) throw new Error("union requires multiple identifiers");
1784
+ if (yy.validateUnionIdentifiers) yy.validateUnionIdentifiers($$[$0 - 1]);
1785
+ yy.addSubsetData($$[$0 - 1], $$[$0], void 0);
1786
+ if (yy.setIndentMode) yy.setIndentMode(true);
1787
+ break;
1788
+ case 15:
1789
+ if ($$[$0 - 2].length < 2) throw new Error("union requires multiple identifiers");
1790
+ if (yy.validateUnionIdentifiers) yy.validateUnionIdentifiers($$[$0 - 2]);
1791
+ yy.addSubsetData($$[$0 - 2], void 0, parseFloat($$[$0]));
1792
+ if (yy.setIndentMode) yy.setIndentMode(true);
1793
+ break;
1794
+ case 16:
1795
+ if ($$[$0 - 3].length < 2) throw new Error("union requires multiple identifiers");
1796
+ if (yy.validateUnionIdentifiers) yy.validateUnionIdentifiers($$[$0 - 3]);
1797
+ yy.addSubsetData($$[$0 - 3], $$[$0 - 2], parseFloat($$[$0]));
1798
+ if (yy.setIndentMode) yy.setIndentMode(true);
1799
+ break;
1800
+ case 17:
1801
+ case 18:
1802
+ case 19:
1803
+ yy.addTextData($$[$0 - 1], $$[$0], void 0);
1804
+ break;
1805
+ case 20:
1806
+ case 21:
1807
+ yy.addTextData($$[$0 - 2], $$[$0 - 1], $$[$0]);
1808
+ break;
1809
+ case 23:
1810
+ yy.addStyleData($$[$0 - 1], $$[$0]);
1811
+ break;
1812
+ case 24:
1813
+ case 25:
1814
+ case 26:
1815
+ var cs = yy.getCurrentSets();
1816
+ if (!cs) throw new Error("text requires set");
1817
+ yy.addTextData(cs, $$[$0], void 0);
1818
+ break;
1819
+ case 27:
1820
+ case 28:
1821
+ var cs = yy.getCurrentSets();
1822
+ if (!cs) throw new Error("text requires set");
1823
+ yy.addTextData(cs, $$[$0 - 1], $$[$0]);
1824
+ break;
1825
+ case 29:
1826
+ case 41:
1827
+ this.$ = [$$[$0]];
1828
+ break;
1829
+ case 30:
1830
+ case 42:
1831
+ this.$ = [...$$[$0 - 2], $$[$0]];
1832
+ break;
1833
+ case 31:
1834
+ this.$ = [$$[$0 - 2], $$[$0]];
1835
+ break;
1836
+ case 33:
1837
+ this.$ = $$[$0].join(" ");
1838
+ break;
1839
+ case 34:
1840
+ this.$ = [$$[$0]];
1841
+ break;
1842
+ case 35:
1843
+ $$[$0 - 1].push($$[$0]);
1844
+ this.$ = $$[$0 - 1];
1845
+ break;
1846
+ case 43:
1847
+ case 44: this.$ = $$[$0];
1848
+ }
1849
+ }, "anonymous"),
1850
+ table: [
1851
+ o($V0, [2, 2], {
1852
+ 3: 1,
1853
+ 4: 2
1854
+ }),
1855
+ { 1: [3] },
1856
+ {
1857
+ 5: [1, 3],
1858
+ 8: [1, 4]
1859
+ },
1860
+ o($V1, [2, 4], { 6: 5 }),
1861
+ o($V0, [2, 3]),
1862
+ {
1863
+ 7: [1, 6],
1864
+ 8: [1, 8],
1865
+ 9: 7,
1866
+ 10: 9,
1867
+ 11: [1, 10],
1868
+ 12: [1, 11],
1869
+ 17: [1, 12],
1870
+ 19: [1, 13],
1871
+ 22: [1, 14],
1872
+ 24: [1, 15]
1873
+ },
1874
+ { 1: [2, 1] },
1875
+ o($V1, [2, 5]),
1876
+ o($V1, [2, 6]),
1877
+ o($V1, [2, 7]),
1878
+ o($V1, [2, 8]),
1879
+ {
1880
+ 13: 16,
1881
+ 20: $V2,
1882
+ 21: $V3
1883
+ },
1884
+ {
1885
+ 13: 20,
1886
+ 18: 19,
1887
+ 20: $V2,
1888
+ 21: $V3
1889
+ },
1890
+ {
1891
+ 13: 20,
1892
+ 18: 21,
1893
+ 20: $V2,
1894
+ 21: $V3
1895
+ },
1896
+ {
1897
+ 16: [1, 25],
1898
+ 20: [1, 23],
1899
+ 21: [1, 24],
1900
+ 23: 22
1901
+ },
1902
+ {
1903
+ 13: 20,
1904
+ 18: 26,
1905
+ 20: $V2,
1906
+ 21: $V3
1907
+ },
1908
+ o($V1, [2, 9], {
1909
+ 14: [1, 27],
1910
+ 15: [1, 28]
1911
+ }),
1912
+ o($V4, [2, 43]),
1913
+ o($V4, [2, 44]),
1914
+ o($V1, [2, 13], {
1915
+ 14: [1, 29],
1916
+ 15: [1, 30],
1917
+ 27: $V5
1918
+ }),
1919
+ o($V4, [2, 41]),
1920
+ {
1921
+ 16: [1, 34],
1922
+ 20: [1, 32],
1923
+ 21: [1, 33],
1924
+ 27: $V5
1925
+ },
1926
+ o($V1, [2, 22]),
1927
+ o($V1, [2, 24], { 14: [1, 35] }),
1928
+ o($V1, [2, 25], { 14: [1, 36] }),
1929
+ o($V1, [2, 26]),
1930
+ {
1931
+ 20: $V6,
1932
+ 25: 37,
1933
+ 26: 38,
1934
+ 27: $V5
1935
+ },
1936
+ o($V1, [2, 10], { 15: [1, 40] }),
1937
+ { 16: [1, 41] },
1938
+ o($V1, [2, 14], { 15: [1, 42] }),
1939
+ { 16: [1, 43] },
1940
+ {
1941
+ 13: 44,
1942
+ 20: $V2,
1943
+ 21: $V3
1944
+ },
1945
+ o($V1, [2, 17], { 14: [1, 45] }),
1946
+ o($V1, [2, 18], { 14: [1, 46] }),
1947
+ o($V1, [2, 19]),
1948
+ o($V1, [2, 27]),
1949
+ o($V1, [2, 28]),
1950
+ o($V1, [2, 23], { 27: [1, 47] }),
1951
+ o($V7, [2, 29]),
1952
+ { 15: [1, 48] },
1953
+ { 16: [1, 49] },
1954
+ o($V1, [2, 11]),
1955
+ { 16: [1, 50] },
1956
+ o($V1, [2, 15]),
1957
+ o($V4, [2, 42]),
1958
+ o($V1, [2, 20]),
1959
+ o($V1, [2, 21]),
1960
+ {
1961
+ 20: $V6,
1962
+ 26: 51
1963
+ },
1964
+ {
1965
+ 16: $V8,
1966
+ 20: $V9,
1967
+ 21: [1, 53],
1968
+ 28: 52,
1969
+ 29: 54,
1970
+ 30: 55,
1971
+ 31: $Va,
1972
+ 32: $Vb,
1973
+ 33: $Vc
1974
+ },
1975
+ o($V1, [2, 12]),
1976
+ o($V1, [2, 16]),
1977
+ o($V7, [2, 30]),
1978
+ o($V7, [2, 31]),
1979
+ o($V7, [2, 32]),
1980
+ o($V7, [2, 33], {
1981
+ 30: 61,
1982
+ 16: $V8,
1983
+ 20: $V9,
1984
+ 31: $Va,
1985
+ 32: $Vb,
1986
+ 33: $Vc
1987
+ }),
1988
+ o($Vd, [2, 34]),
1989
+ o($Vd, [2, 36]),
1990
+ o($Vd, [2, 37]),
1991
+ o($Vd, [2, 38]),
1992
+ o($Vd, [2, 39]),
1993
+ o($Vd, [2, 40]),
1994
+ o($Vd, [2, 35])
1995
+ ],
1996
+ defaultActions: { 6: [2, 1] },
1997
+ parseError: /* @__PURE__ */ __name(function parseError(str, hash) {
1998
+ if (hash.recoverable) this.trace(str);
1999
+ else {
2000
+ var error = new Error(str);
2001
+ error.hash = hash;
2002
+ throw error;
2003
+ }
2004
+ }, "parseError"),
2005
+ parse: /* @__PURE__ */ __name(function parse(input) {
2006
+ var self = this, stack = [0], tstack = [], vstack = [null], lstack = [], table = this.table, yytext = "", yylineno = 0, yyleng = 0, recovering = 0, TERROR = 2, EOF = 1;
2007
+ var args = lstack.slice.call(arguments, 1);
2008
+ var lexer2 = Object.create(this.lexer);
2009
+ var sharedState = { yy: {} };
2010
+ for (var k in this.yy) if (Object.prototype.hasOwnProperty.call(this.yy, k)) sharedState.yy[k] = this.yy[k];
2011
+ lexer2.setInput(input, sharedState.yy);
2012
+ sharedState.yy.lexer = lexer2;
2013
+ sharedState.yy.parser = this;
2014
+ if (typeof lexer2.yylloc == "undefined") lexer2.yylloc = {};
2015
+ var yyloc = lexer2.yylloc;
2016
+ lstack.push(yyloc);
2017
+ var ranges = lexer2.options && lexer2.options.ranges;
2018
+ if (typeof sharedState.yy.parseError === "function") this.parseError = sharedState.yy.parseError;
2019
+ else this.parseError = Object.getPrototypeOf(this).parseError;
2020
+ function popStack(n) {
2021
+ stack.length = stack.length - 2 * n;
2022
+ vstack.length = vstack.length - n;
2023
+ lstack.length = lstack.length - n;
2024
+ }
2025
+ __name(popStack, "popStack");
2026
+ function lex() {
2027
+ var token = tstack.pop() || lexer2.lex() || EOF;
2028
+ if (typeof token !== "number") {
2029
+ if (token instanceof Array) {
2030
+ tstack = token;
2031
+ token = tstack.pop();
2032
+ }
2033
+ token = self.symbols_[token] || token;
2034
+ }
2035
+ return token;
2036
+ }
2037
+ __name(lex, "lex");
2038
+ var symbol, preErrorSymbol, state, action, r, yyval = {}, p, len, newState, expected;
2039
+ while (true) {
2040
+ state = stack[stack.length - 1];
2041
+ if (this.defaultActions[state]) action = this.defaultActions[state];
2042
+ else {
2043
+ if (symbol === null || typeof symbol == "undefined") symbol = lex();
2044
+ action = table[state] && table[state][symbol];
2045
+ }
2046
+ if (typeof action === "undefined" || !action.length || !action[0]) {
2047
+ var errStr = "";
2048
+ expected = [];
2049
+ for (p in table[state]) if (this.terminals_[p] && p > TERROR) expected.push("'" + this.terminals_[p] + "'");
2050
+ if (lexer2.showPosition) errStr = "Parse error on line " + (yylineno + 1) + ":\n" + lexer2.showPosition() + "\nExpecting " + expected.join(", ") + ", got '" + (this.terminals_[symbol] || symbol) + "'";
2051
+ else errStr = "Parse error on line " + (yylineno + 1) + ": Unexpected " + (symbol == EOF ? "end of input" : "'" + (this.terminals_[symbol] || symbol) + "'");
2052
+ this.parseError(errStr, {
2053
+ text: lexer2.match,
2054
+ token: this.terminals_[symbol] || symbol,
2055
+ line: lexer2.yylineno,
2056
+ loc: yyloc,
2057
+ expected
2058
+ });
2059
+ }
2060
+ if (action[0] instanceof Array && action.length > 1) throw new Error("Parse Error: multiple actions possible at state: " + state + ", token: " + symbol);
2061
+ switch (action[0]) {
2062
+ case 1:
2063
+ stack.push(symbol);
2064
+ vstack.push(lexer2.yytext);
2065
+ lstack.push(lexer2.yylloc);
2066
+ stack.push(action[1]);
2067
+ symbol = null;
2068
+ if (!preErrorSymbol) {
2069
+ yyleng = lexer2.yyleng;
2070
+ yytext = lexer2.yytext;
2071
+ yylineno = lexer2.yylineno;
2072
+ yyloc = lexer2.yylloc;
2073
+ if (recovering > 0) recovering--;
2074
+ } else {
2075
+ symbol = preErrorSymbol;
2076
+ preErrorSymbol = null;
2077
+ }
2078
+ break;
2079
+ case 2:
2080
+ len = this.productions_[action[1]][1];
2081
+ yyval.$ = vstack[vstack.length - len];
2082
+ yyval._$ = {
2083
+ first_line: lstack[lstack.length - (len || 1)].first_line,
2084
+ last_line: lstack[lstack.length - 1].last_line,
2085
+ first_column: lstack[lstack.length - (len || 1)].first_column,
2086
+ last_column: lstack[lstack.length - 1].last_column
2087
+ };
2088
+ if (ranges) yyval._$.range = [lstack[lstack.length - (len || 1)].range[0], lstack[lstack.length - 1].range[1]];
2089
+ r = this.performAction.apply(yyval, [
2090
+ yytext,
2091
+ yyleng,
2092
+ yylineno,
2093
+ sharedState.yy,
2094
+ action[1],
2095
+ vstack,
2096
+ lstack
2097
+ ].concat(args));
2098
+ if (typeof r !== "undefined") return r;
2099
+ if (len) {
2100
+ stack = stack.slice(0, -1 * len * 2);
2101
+ vstack = vstack.slice(0, -1 * len);
2102
+ lstack = lstack.slice(0, -1 * len);
2103
+ }
2104
+ stack.push(this.productions_[action[1]][0]);
2105
+ vstack.push(yyval.$);
2106
+ lstack.push(yyval._$);
2107
+ newState = table[stack[stack.length - 2]][stack[stack.length - 1]];
2108
+ stack.push(newState);
2109
+ break;
2110
+ case 3: return true;
2111
+ }
2112
+ }
2113
+ return true;
2114
+ }, "parse")
2115
+ };
2116
+ parser2.lexer = /* @__PURE__ */ (function() {
2117
+ return {
2118
+ EOF: 1,
2119
+ parseError: /* @__PURE__ */ __name(function parseError(str, hash) {
2120
+ if (this.yy.parser) this.yy.parser.parseError(str, hash);
2121
+ else throw new Error(str);
2122
+ }, "parseError"),
2123
+ setInput: /* @__PURE__ */ __name(function(input, yy) {
2124
+ this.yy = yy || this.yy || {};
2125
+ this._input = input;
2126
+ this._more = this._backtrack = this.done = false;
2127
+ this.yylineno = this.yyleng = 0;
2128
+ this.yytext = this.matched = this.match = "";
2129
+ this.conditionStack = ["INITIAL"];
2130
+ this.yylloc = {
2131
+ first_line: 1,
2132
+ first_column: 0,
2133
+ last_line: 1,
2134
+ last_column: 0
2135
+ };
2136
+ if (this.options.ranges) this.yylloc.range = [0, 0];
2137
+ this.offset = 0;
2138
+ return this;
2139
+ }, "setInput"),
2140
+ input: /* @__PURE__ */ __name(function() {
2141
+ var ch = this._input[0];
2142
+ this.yytext += ch;
2143
+ this.yyleng++;
2144
+ this.offset++;
2145
+ this.match += ch;
2146
+ this.matched += ch;
2147
+ if (ch.match(/(?:\r\n?|\n).*/g)) {
2148
+ this.yylineno++;
2149
+ this.yylloc.last_line++;
2150
+ } else this.yylloc.last_column++;
2151
+ if (this.options.ranges) this.yylloc.range[1]++;
2152
+ this._input = this._input.slice(1);
2153
+ return ch;
2154
+ }, "input"),
2155
+ unput: /* @__PURE__ */ __name(function(ch) {
2156
+ var len = ch.length;
2157
+ var lines = ch.split(/(?:\r\n?|\n)/g);
2158
+ this._input = ch + this._input;
2159
+ this.yytext = this.yytext.substr(0, this.yytext.length - len);
2160
+ this.offset -= len;
2161
+ var oldLines = this.match.split(/(?:\r\n?|\n)/g);
2162
+ this.match = this.match.substr(0, this.match.length - 1);
2163
+ this.matched = this.matched.substr(0, this.matched.length - 1);
2164
+ if (lines.length - 1) this.yylineno -= lines.length - 1;
2165
+ var r = this.yylloc.range;
2166
+ this.yylloc = {
2167
+ first_line: this.yylloc.first_line,
2168
+ last_line: this.yylineno + 1,
2169
+ first_column: this.yylloc.first_column,
2170
+ last_column: lines ? (lines.length === oldLines.length ? this.yylloc.first_column : 0) + oldLines[oldLines.length - lines.length].length - lines[0].length : this.yylloc.first_column - len
2171
+ };
2172
+ if (this.options.ranges) this.yylloc.range = [r[0], r[0] + this.yyleng - len];
2173
+ this.yyleng = this.yytext.length;
2174
+ return this;
2175
+ }, "unput"),
2176
+ more: /* @__PURE__ */ __name(function() {
2177
+ this._more = true;
2178
+ return this;
2179
+ }, "more"),
2180
+ reject: /* @__PURE__ */ __name(function() {
2181
+ if (this.options.backtrack_lexer) this._backtrack = true;
2182
+ else return this.parseError("Lexical error on line " + (this.yylineno + 1) + ". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n" + this.showPosition(), {
2183
+ text: "",
2184
+ token: null,
2185
+ line: this.yylineno
2186
+ });
2187
+ return this;
2188
+ }, "reject"),
2189
+ less: /* @__PURE__ */ __name(function(n) {
2190
+ this.unput(this.match.slice(n));
2191
+ }, "less"),
2192
+ pastInput: /* @__PURE__ */ __name(function() {
2193
+ var past = this.matched.substr(0, this.matched.length - this.match.length);
2194
+ return (past.length > 20 ? "..." : "") + past.substr(-20).replace(/\n/g, "");
2195
+ }, "pastInput"),
2196
+ upcomingInput: /* @__PURE__ */ __name(function() {
2197
+ var next = this.match;
2198
+ if (next.length < 20) next += this._input.substr(0, 20 - next.length);
2199
+ return (next.substr(0, 20) + (next.length > 20 ? "..." : "")).replace(/\n/g, "");
2200
+ }, "upcomingInput"),
2201
+ showPosition: /* @__PURE__ */ __name(function() {
2202
+ var pre = this.pastInput();
2203
+ var c = new Array(pre.length + 1).join("-");
2204
+ return pre + this.upcomingInput() + "\n" + c + "^";
2205
+ }, "showPosition"),
2206
+ test_match: /* @__PURE__ */ __name(function(match, indexed_rule) {
2207
+ var token, lines, backup;
2208
+ if (this.options.backtrack_lexer) {
2209
+ backup = {
2210
+ yylineno: this.yylineno,
2211
+ yylloc: {
2212
+ first_line: this.yylloc.first_line,
2213
+ last_line: this.last_line,
2214
+ first_column: this.yylloc.first_column,
2215
+ last_column: this.yylloc.last_column
2216
+ },
2217
+ yytext: this.yytext,
2218
+ match: this.match,
2219
+ matches: this.matches,
2220
+ matched: this.matched,
2221
+ yyleng: this.yyleng,
2222
+ offset: this.offset,
2223
+ _more: this._more,
2224
+ _input: this._input,
2225
+ yy: this.yy,
2226
+ conditionStack: this.conditionStack.slice(0),
2227
+ done: this.done
2228
+ };
2229
+ if (this.options.ranges) backup.yylloc.range = this.yylloc.range.slice(0);
2230
+ }
2231
+ lines = match[0].match(/(?:\r\n?|\n).*/g);
2232
+ if (lines) this.yylineno += lines.length;
2233
+ this.yylloc = {
2234
+ first_line: this.yylloc.last_line,
2235
+ last_line: this.yylineno + 1,
2236
+ first_column: this.yylloc.last_column,
2237
+ last_column: lines ? lines[lines.length - 1].length - lines[lines.length - 1].match(/\r?\n?/)[0].length : this.yylloc.last_column + match[0].length
2238
+ };
2239
+ this.yytext += match[0];
2240
+ this.match += match[0];
2241
+ this.matches = match;
2242
+ this.yyleng = this.yytext.length;
2243
+ if (this.options.ranges) this.yylloc.range = [this.offset, this.offset += this.yyleng];
2244
+ this._more = false;
2245
+ this._backtrack = false;
2246
+ this._input = this._input.slice(match[0].length);
2247
+ this.matched += match[0];
2248
+ token = this.performAction.call(this, this.yy, this, indexed_rule, this.conditionStack[this.conditionStack.length - 1]);
2249
+ if (this.done && this._input) this.done = false;
2250
+ if (token) return token;
2251
+ else if (this._backtrack) {
2252
+ for (var k in backup) this[k] = backup[k];
2253
+ return false;
2254
+ }
2255
+ return false;
2256
+ }, "test_match"),
2257
+ next: /* @__PURE__ */ __name(function() {
2258
+ if (this.done) return this.EOF;
2259
+ if (!this._input) this.done = true;
2260
+ var token, match, tempMatch, index;
2261
+ if (!this._more) {
2262
+ this.yytext = "";
2263
+ this.match = "";
2264
+ }
2265
+ var rules = this._currentRules();
2266
+ for (var i = 0; i < rules.length; i++) {
2267
+ tempMatch = this._input.match(this.rules[rules[i]]);
2268
+ if (tempMatch && (!match || tempMatch[0].length > match[0].length)) {
2269
+ match = tempMatch;
2270
+ index = i;
2271
+ if (this.options.backtrack_lexer) {
2272
+ token = this.test_match(tempMatch, rules[i]);
2273
+ if (token !== false) return token;
2274
+ else if (this._backtrack) {
2275
+ match = false;
2276
+ continue;
2277
+ } else return false;
2278
+ } else if (!this.options.flex) break;
2279
+ }
2280
+ }
2281
+ if (match) {
2282
+ token = this.test_match(match, rules[index]);
2283
+ if (token !== false) return token;
2284
+ return false;
2285
+ }
2286
+ if (this._input === "") return this.EOF;
2287
+ else return this.parseError("Lexical error on line " + (this.yylineno + 1) + ". Unrecognized text.\n" + this.showPosition(), {
2288
+ text: "",
2289
+ token: null,
2290
+ line: this.yylineno
2291
+ });
2292
+ }, "next"),
2293
+ lex: /* @__PURE__ */ __name(function lex() {
2294
+ var r = this.next();
2295
+ if (r) return r;
2296
+ else return this.lex();
2297
+ }, "lex"),
2298
+ begin: /* @__PURE__ */ __name(function begin(condition) {
2299
+ this.conditionStack.push(condition);
2300
+ }, "begin"),
2301
+ popState: /* @__PURE__ */ __name(function popState() {
2302
+ if (this.conditionStack.length - 1 > 0) return this.conditionStack.pop();
2303
+ else return this.conditionStack[0];
2304
+ }, "popState"),
2305
+ _currentRules: /* @__PURE__ */ __name(function _currentRules() {
2306
+ if (this.conditionStack.length && this.conditionStack[this.conditionStack.length - 1]) return this.conditions[this.conditionStack[this.conditionStack.length - 1]].rules;
2307
+ else return this.conditions["INITIAL"].rules;
2308
+ }, "_currentRules"),
2309
+ topState: /* @__PURE__ */ __name(function topState(n) {
2310
+ n = this.conditionStack.length - 1 - Math.abs(n || 0);
2311
+ if (n >= 0) return this.conditionStack[n];
2312
+ else return "INITIAL";
2313
+ }, "topState"),
2314
+ pushState: /* @__PURE__ */ __name(function pushState(condition) {
2315
+ this.begin(condition);
2316
+ }, "pushState"),
2317
+ stateStackSize: /* @__PURE__ */ __name(function stateStackSize() {
2318
+ return this.conditionStack.length;
2319
+ }, "stateStackSize"),
2320
+ options: { "case-insensitive": true },
2321
+ performAction: /* @__PURE__ */ __name(function anonymous(yy, yy_, $avoiding_name_collisions, YY_START) {
2322
+ switch ($avoiding_name_collisions) {
2323
+ case 0: break;
2324
+ case 1: break;
2325
+ case 2: break;
2326
+ case 3:
2327
+ if (yy.getIndentMode && yy.getIndentMode()) {
2328
+ yy.consumeIndentText = true;
2329
+ this.begin("INITIAL");
2330
+ return 22;
2331
+ }
2332
+ break;
2333
+ case 4: break;
2334
+ case 5:
2335
+ if (yy.setIndentMode) yy.setIndentMode(false);
2336
+ this.begin("INITIAL");
2337
+ this.unput(yy_.yytext);
2338
+ break;
2339
+ case 6:
2340
+ this.begin("bol");
2341
+ return 8;
2342
+ case 7: break;
2343
+ case 8: break;
2344
+ case 9: return 7;
2345
+ case 10: return 11;
2346
+ case 11: return 5;
2347
+ case 12: return 12;
2348
+ case 13: return 17;
2349
+ case 14:
2350
+ if (yy.consumeIndentText) yy.consumeIndentText = false;
2351
+ else return 19;
2352
+ break;
2353
+ case 15: return 24;
2354
+ case 16:
2355
+ yy_.yytext = yy_.yytext.slice(2, -2);
2356
+ return 14;
2357
+ case 17:
2358
+ yy_.yytext = yy_.yytext.slice(1, -1).trim();
2359
+ return 14;
2360
+ case 18: return 16;
2361
+ case 19: return 31;
2362
+ case 20: return 33;
2363
+ case 21: return 32;
2364
+ case 22: return 20;
2365
+ case 23: return 21;
2366
+ case 24: return 27;
2367
+ case 25: return 15;
2368
+ }
2369
+ }, "anonymous"),
2370
+ rules: [
2371
+ /^(?:%%(?!\{)[^\n]*)/i,
2372
+ /^(?:[^\}]%%[^\n]*)/i,
2373
+ /^(?:[ \t]+(?=[\n\r]))/i,
2374
+ /^(?:[ \t]+(?=text\b))/i,
2375
+ /^(?:[ \t]+)/i,
2376
+ /^(?:[^ \t\n\r])/i,
2377
+ /^(?:[\n\r]+)/i,
2378
+ /^(?:%%[^\n]*)/i,
2379
+ /^(?:[ \t]+)/i,
2380
+ /^(?:$)/i,
2381
+ /^(?:title\s[^#\n;]+)/i,
2382
+ /^(?:venn-beta\b)/i,
2383
+ /^(?:set\b)/i,
2384
+ /^(?:union\b)/i,
2385
+ /^(?:text\b)/i,
2386
+ /^(?:style\b)/i,
2387
+ /^(?:\["[^\"]*"\])/i,
2388
+ /^(?:\[[^\]\"]+\])/i,
2389
+ /^(?:[+-]?(\d+(\.\d+)?|\.\d+))/i,
2390
+ /^(?:#[0-9a-fA-F]{3,8})/i,
2391
+ /^(?:rgba\(\s*[0-9.]+\s*[,]\s*[0-9.]+\s*[,]\s*[0-9.]+\s*[,]\s*[0-9.]+\s*\))/i,
2392
+ /^(?:rgb\(\s*[0-9.]+\s*[,]\s*[0-9.]+\s*[,]\s*[0-9.]+\s*\))/i,
2393
+ /^(?:[A-Za-z_][A-Za-z0-9\-_]*)/i,
2394
+ /^(?:"[^\"]*")/i,
2395
+ /^(?:,)/i,
2396
+ /^(?::)/i
2397
+ ],
2398
+ conditions: {
2399
+ "bol": {
2400
+ "rules": [
2401
+ 0,
2402
+ 1,
2403
+ 2,
2404
+ 3,
2405
+ 4,
2406
+ 5,
2407
+ 6,
2408
+ 7,
2409
+ 8,
2410
+ 9,
2411
+ 10,
2412
+ 11,
2413
+ 12,
2414
+ 13,
2415
+ 14,
2416
+ 15,
2417
+ 16,
2418
+ 17,
2419
+ 18,
2420
+ 19,
2421
+ 20,
2422
+ 21,
2423
+ 22,
2424
+ 23,
2425
+ 24,
2426
+ 25
2427
+ ],
2428
+ "inclusive": true
2429
+ },
2430
+ "INITIAL": {
2431
+ "rules": [
2432
+ 0,
2433
+ 1,
2434
+ 6,
2435
+ 7,
2436
+ 8,
2437
+ 9,
2438
+ 10,
2439
+ 11,
2440
+ 12,
2441
+ 13,
2442
+ 14,
2443
+ 15,
2444
+ 16,
2445
+ 17,
2446
+ 18,
2447
+ 19,
2448
+ 20,
2449
+ 21,
2450
+ 22,
2451
+ 23,
2452
+ 24,
2453
+ 25
2454
+ ],
2455
+ "inclusive": true
2456
+ }
2457
+ }
2458
+ };
2459
+ })();
2460
+ function Parser() {
2461
+ this.yy = {};
2462
+ }
2463
+ __name(Parser, "Parser");
2464
+ Parser.prototype = parser2;
2465
+ parser2.Parser = Parser;
2466
+ return new Parser();
2467
+ })();
2468
+ parser.parser = parser;
2469
+ var venn_default = parser;
2470
+ var subsets = [];
2471
+ var textNodes = [];
2472
+ var styleEntries = [];
2473
+ var knownSets = /* @__PURE__ */ new Set();
2474
+ var currentSets;
2475
+ var indentMode = false;
2476
+ var addSubsetData = /* @__PURE__ */ __name((identifierList, label, size) => {
2477
+ const sets = normalizeIdentifierList(identifierList).sort();
2478
+ const resolvedSize = size ?? 10 / Math.pow(identifierList.length, 2);
2479
+ currentSets = sets;
2480
+ if (sets.length === 1) knownSets.add(sets[0]);
2481
+ subsets.push({
2482
+ sets,
2483
+ size: resolvedSize,
2484
+ label: label ? normalizeText(label) : void 0
2485
+ });
2486
+ }, "addSubsetData");
2487
+ var getSubsetData = /* @__PURE__ */ __name(() => {
2488
+ return subsets;
2489
+ }, "getSubsetData");
2490
+ var normalizeText = /* @__PURE__ */ __name((text) => {
2491
+ const trimmed = text.trim();
2492
+ if (trimmed.length >= 2 && trimmed.startsWith("\"") && trimmed.endsWith("\"")) return trimmed.slice(1, -1);
2493
+ return trimmed;
2494
+ }, "normalizeText");
2495
+ var normalizeStyleValue = /* @__PURE__ */ __name((value) => {
2496
+ return value ? normalizeText(value) : value;
2497
+ }, "normalizeStyleValue");
2498
+ var addTextData = /* @__PURE__ */ __name((identifierList, id, label) => {
2499
+ const normalizedId = normalizeText(id);
2500
+ textNodes.push({
2501
+ sets: normalizeIdentifierList(identifierList).sort(),
2502
+ id: normalizedId,
2503
+ label: label ? normalizeText(label) : void 0
2504
+ });
2505
+ }, "addTextData");
2506
+ var addStyleData = /* @__PURE__ */ __name((identifierList, data) => {
2507
+ const targets = normalizeIdentifierList(identifierList).sort();
2508
+ const styles = {};
2509
+ for (const [key, value] of data) styles[key] = normalizeStyleValue(value) ?? value;
2510
+ styleEntries.push({
2511
+ targets,
2512
+ styles
2513
+ });
2514
+ }, "addStyleData");
2515
+ var getStyleData = /* @__PURE__ */ __name(() => {
2516
+ return styleEntries;
2517
+ }, "getStyleData");
2518
+ var normalizeIdentifierList = /* @__PURE__ */ __name((identifierList) => {
2519
+ return identifierList.map((identifier) => normalizeText(identifier));
2520
+ }, "normalizeIdentifierList");
2521
+ var validateUnionIdentifiers = /* @__PURE__ */ __name((identifierList) => {
2522
+ const unknown = normalizeIdentifierList(identifierList).filter((identifier) => !knownSets.has(identifier));
2523
+ if (unknown.length > 0) throw new Error(`unknown set identifier: ${unknown.join(", ")}`);
2524
+ }, "validateUnionIdentifiers");
2525
+ var getTextData = /* @__PURE__ */ __name(() => {
2526
+ return textNodes;
2527
+ }, "getTextData");
2528
+ var getCurrentSets = /* @__PURE__ */ __name(() => currentSets, "getCurrentSets");
2529
+ var getIndentMode = /* @__PURE__ */ __name(() => indentMode, "getIndentMode");
2530
+ var setIndentMode = /* @__PURE__ */ __name((enabled) => {
2531
+ indentMode = enabled;
2532
+ }, "setIndentMode");
2533
+ var DEFAULT_VENN_CONFIG = defaultConfig_default.venn;
2534
+ function getConfig2() {
2535
+ return cleanAndMerge(DEFAULT_VENN_CONFIG, getConfig().venn);
2536
+ }
2537
+ __name(getConfig2, "getConfig");
2538
+ var db = {
2539
+ getConfig: getConfig2,
2540
+ clear: /* @__PURE__ */ __name(() => {
2541
+ clear();
2542
+ subsets.length = 0;
2543
+ textNodes.length = 0;
2544
+ styleEntries.length = 0;
2545
+ knownSets.clear();
2546
+ currentSets = void 0;
2547
+ indentMode = false;
2548
+ }, "customClear"),
2549
+ setAccTitle,
2550
+ getAccTitle,
2551
+ setDiagramTitle,
2552
+ getDiagramTitle,
2553
+ getAccDescription,
2554
+ setAccDescription,
2555
+ addSubsetData,
2556
+ getSubsetData,
2557
+ addTextData,
2558
+ addStyleData,
2559
+ validateUnionIdentifiers,
2560
+ getTextData,
2561
+ getStyleData,
2562
+ getCurrentSets,
2563
+ getIndentMode,
2564
+ setIndentMode
2565
+ };
2566
+ var styles_default = /* @__PURE__ */ __name((options) => `
2567
+ .venn-title {
2568
+ font-size: 32px;
2569
+ fill: ${options.vennTitleTextColor};
2570
+ font-family: ${options.fontFamily};
2571
+ }
2572
+
2573
+ .venn-circle text {
2574
+ font-size: 48px;
2575
+ font-family: ${options.fontFamily};
2576
+ }
2577
+
2578
+ .venn-intersection text {
2579
+ font-size: 48px;
2580
+ fill: ${options.vennSetTextColor};
2581
+ font-family: ${options.fontFamily};
2582
+ }
2583
+
2584
+ .venn-text-node {
2585
+ font-family: ${options.fontFamily};
2586
+ color: ${options.vennSetTextColor};
2587
+ }
2588
+ `, "getStyles");
2589
+ function buildStyleByKey(styleData) {
2590
+ const map = /* @__PURE__ */ new Map();
2591
+ for (const entry of styleData) {
2592
+ const key = entry.targets.join("|");
2593
+ const existing = map.get(key);
2594
+ if (existing) Object.assign(existing, entry.styles);
2595
+ else map.set(key, { ...entry.styles });
2596
+ }
2597
+ return map;
2598
+ }
2599
+ __name(buildStyleByKey, "buildStyleByKey");
2600
+ var draw = /* @__PURE__ */ __name((_text, id, _version, diagObj) => {
2601
+ const db2 = diagObj.db;
2602
+ const config = db2.getConfig?.();
2603
+ const { themeVariables, look, handDrawnSeed } = getConfig();
2604
+ const isHandDrawn = look === "handDrawn";
2605
+ const themeColors = [
2606
+ themeVariables.venn1,
2607
+ themeVariables.venn2,
2608
+ themeVariables.venn3,
2609
+ themeVariables.venn4,
2610
+ themeVariables.venn5,
2611
+ themeVariables.venn6,
2612
+ themeVariables.venn7,
2613
+ themeVariables.venn8
2614
+ ].filter(Boolean);
2615
+ const title = db2.getDiagramTitle?.();
2616
+ const sets = db2.getSubsetData();
2617
+ const textNodes2 = db2.getTextData();
2618
+ const styleByKey = buildStyleByKey(db2.getStyleData());
2619
+ const renderSets = ensurePairwiseSubsets(sets);
2620
+ const svgWidth = config?.width ?? 800;
2621
+ const svgHeight = config?.height ?? 450;
2622
+ const scale = svgWidth / 1600;
2623
+ const titleHeight = title ? 48 * scale : 0;
2624
+ const defaultTextColor = themeVariables.primaryTextColor ?? themeVariables.textColor;
2625
+ const svg = selectSvgElement(id);
2626
+ svg.attr("viewBox", `0 0 ${svgWidth} ${svgHeight}`);
2627
+ if (title) svg.append("text").text(title).attr("class", "venn-title").attr("font-size", `${32 * scale}px`).attr("text-anchor", "middle").attr("dominant-baseline", "middle").attr("x", "50%").attr("y", 32 * scale).style("fill", themeVariables.vennTitleTextColor || themeVariables.titleColor);
2628
+ const dummyD3root = select_default(document.createElement("div"));
2629
+ const vennDiagram = VennDiagram().width(svgWidth).height(svgHeight - titleHeight);
2630
+ dummyD3root.datum(renderSets).call(vennDiagram);
2631
+ const roughSvg = isHandDrawn ? at.svg(dummyD3root.select("svg").node()) : void 0;
2632
+ const layoutAreas = layout(renderSets, {
2633
+ width: svgWidth,
2634
+ height: svgHeight - titleHeight,
2635
+ padding: config?.padding ?? 15
2636
+ });
2637
+ const layoutByKey = /* @__PURE__ */ new Map();
2638
+ for (const area of layoutAreas) {
2639
+ const key = stableSetsKey([...area.data.sets].sort());
2640
+ layoutByKey.set(key, area);
2641
+ }
2642
+ if (textNodes2.length > 0) renderTextNodes(config, layoutByKey, dummyD3root, textNodes2, scale, styleByKey);
2643
+ const themeDark = isDark(themeVariables.background || "#f4f4f4");
2644
+ dummyD3root.selectAll(".venn-circle").each(function(d, i) {
2645
+ const group = select_default(this);
2646
+ const setsKey = stableSetsKey([...d.sets].sort());
2647
+ const customStyle = styleByKey.get(setsKey);
2648
+ const baseColor = customStyle?.fill || themeColors[i % themeColors.length] || themeVariables.primaryColor;
2649
+ group.classed(`venn-set-${i % 8}`, true);
2650
+ const fillOpacity = customStyle?.["fill-opacity"] ?? .1;
2651
+ const strokeColor = customStyle?.stroke || baseColor;
2652
+ const strokeWidthVal = customStyle?.["stroke-width"] || `${5 * scale}`;
2653
+ if (isHandDrawn && roughSvg) {
2654
+ const layoutArea = layoutByKey.get(setsKey);
2655
+ if (layoutArea && layoutArea.circles.length > 0) {
2656
+ const c = layoutArea.circles[0];
2657
+ const roughNode = roughSvg.circle(c.x, c.y, c.radius * 2, {
2658
+ roughness: .7,
2659
+ seed: handDrawnSeed,
2660
+ fill: transparentize(baseColor, .7),
2661
+ fillStyle: "hachure",
2662
+ fillWeight: 2,
2663
+ hachureGap: 8,
2664
+ hachureAngle: -41 + i * 60,
2665
+ stroke: strokeColor,
2666
+ strokeWidth: parseFloat(String(strokeWidthVal))
2667
+ });
2668
+ group.select("path").remove();
2669
+ group.node()?.insertBefore(roughNode, group.select("text").node());
2670
+ }
2671
+ } else group.select("path").style("fill", baseColor).style("fill-opacity", fillOpacity).style("stroke", strokeColor).style("stroke-width", strokeWidthVal).style("stroke-opacity", .95);
2672
+ const textColor = customStyle?.color || (themeDark ? lighten(baseColor, 30) : darken(baseColor, 30));
2673
+ group.select("text").style("font-size", `${48 * scale}px`).style("fill", textColor);
2674
+ });
2675
+ if (isHandDrawn && roughSvg) dummyD3root.selectAll(".venn-intersection").each(function(d) {
2676
+ const group = select_default(this);
2677
+ const setsKey = stableSetsKey([...d.sets].sort());
2678
+ const customStyle = styleByKey.get(setsKey);
2679
+ const customFill = customStyle?.fill;
2680
+ if (customFill) {
2681
+ const pathEl = group.select("path");
2682
+ const pathD = pathEl.attr("d");
2683
+ if (pathD) {
2684
+ const roughNode = roughSvg.path(pathD, {
2685
+ roughness: .7,
2686
+ seed: handDrawnSeed,
2687
+ fill: transparentize(customFill, .3),
2688
+ fillStyle: "cross-hatch",
2689
+ fillWeight: 2,
2690
+ hachureGap: 6,
2691
+ hachureAngle: 60,
2692
+ stroke: "none"
2693
+ });
2694
+ const existingPath = pathEl.node();
2695
+ existingPath?.parentNode?.insertBefore(roughNode, existingPath);
2696
+ pathEl.remove();
2697
+ }
2698
+ } else group.select("path").style("fill-opacity", 0);
2699
+ group.select("text").style("font-size", `${48 * scale}px`).style("fill", customStyle?.color ?? themeVariables.vennSetTextColor ?? defaultTextColor);
2700
+ });
2701
+ else {
2702
+ dummyD3root.selectAll(".venn-intersection text").style("font-size", `${48 * scale}px`).style("fill", (e) => {
2703
+ const setsKey = stableSetsKey([...e.sets].sort());
2704
+ return styleByKey.get(setsKey)?.color ?? themeVariables.vennSetTextColor ?? defaultTextColor;
2705
+ });
2706
+ dummyD3root.selectAll(".venn-intersection path").style("fill-opacity", (e) => {
2707
+ const setsKey = stableSetsKey([...e.sets].sort());
2708
+ return styleByKey.get(setsKey)?.fill ? 1 : 0;
2709
+ }).style("fill", (e) => {
2710
+ const setsKey = stableSetsKey([...e.sets].sort());
2711
+ return styleByKey.get(setsKey)?.fill ?? "transparent";
2712
+ });
2713
+ }
2714
+ const vennGroup = svg.append("g").attr("transform", `translate(0, ${titleHeight})`);
2715
+ const dummySvg = dummyD3root.select("svg").node();
2716
+ if (dummySvg && "childNodes" in dummySvg) for (const child of [...dummySvg.childNodes]) vennGroup.node()?.appendChild(child);
2717
+ configureSvgSize(svg, svgHeight, svgWidth, config?.useMaxWidth ?? true);
2718
+ }, "draw");
2719
+ function stableSetsKey(setIds) {
2720
+ return setIds.join("|");
2721
+ }
2722
+ __name(stableSetsKey, "stableSetsKey");
2723
+ function renderTextNodes(config, layoutByKey, dummyD3root, textNodes2, scale, styleByKey) {
2724
+ const useDebugLayout = config?.useDebugLayout ?? false;
2725
+ const textGroup = dummyD3root.select("svg").append("g").attr("class", "venn-text-nodes");
2726
+ const nodesByArea = /* @__PURE__ */ new Map();
2727
+ for (const node of textNodes2) {
2728
+ const key = stableSetsKey(node.sets);
2729
+ const existing = nodesByArea.get(key);
2730
+ if (existing) existing.push(node);
2731
+ else nodesByArea.set(key, [node]);
2732
+ }
2733
+ for (const [key, nodes] of nodesByArea.entries()) {
2734
+ const area = layoutByKey.get(key);
2735
+ if (!area?.text) continue;
2736
+ const centerX = area.text.x;
2737
+ const centerY = area.text.y;
2738
+ const minCircleRadius = Math.min(...area.circles.map((c) => c.radius));
2739
+ const innerRadiusRaw = Math.min(...area.circles.map((c) => c.radius - Math.hypot(centerX - c.x, centerY - c.y)));
2740
+ let innerRadius = Number.isFinite(innerRadiusRaw) ? Math.max(0, innerRadiusRaw) : 0;
2741
+ if (innerRadius === 0 && Number.isFinite(minCircleRadius)) innerRadius = minCircleRadius * .6;
2742
+ const areaGroup = textGroup.append("g").attr("class", "venn-text-area").attr("font-size", `${40 * scale}px`);
2743
+ if (useDebugLayout) areaGroup.append("circle").attr("class", "venn-text-debug-circle").attr("cx", centerX).attr("cy", centerY).attr("r", innerRadius).attr("fill", "none").attr("stroke", "purple").attr("stroke-width", 1.5 * scale).attr("stroke-dasharray", `${6 * scale} ${4 * scale}`);
2744
+ const innerWidth = Math.max(80 * scale, innerRadius * 2 * .95);
2745
+ const innerHeight = Math.max(60 * scale, innerRadius * 2 * .95);
2746
+ const labelOffset = (area.data.label && area.data.label.length > 0 ? Math.min(32 * scale, innerRadius * .25) : 0) + (nodes.length <= 2 ? 30 * scale : 0);
2747
+ const startX = centerX - innerWidth / 2;
2748
+ const startY = centerY - innerHeight / 2 + labelOffset;
2749
+ const cols = Math.max(1, Math.ceil(Math.sqrt(nodes.length)));
2750
+ const rows = Math.max(1, Math.ceil(nodes.length / cols));
2751
+ const cellWidth = innerWidth / cols;
2752
+ const cellHeight = innerHeight / rows;
2753
+ for (const [i, node] of nodes.entries()) {
2754
+ const col = i % cols;
2755
+ const row = Math.floor(i / cols);
2756
+ const x = startX + cellWidth * (col + .5);
2757
+ const y = startY + cellHeight * (row + .5);
2758
+ if (useDebugLayout) areaGroup.append("rect").attr("class", "venn-text-debug-cell").attr("x", startX + cellWidth * col).attr("y", startY + cellHeight * row).attr("width", cellWidth).attr("height", cellHeight).attr("fill", "none").attr("stroke", "teal").attr("stroke-width", 1 * scale).attr("stroke-dasharray", `${4 * scale} ${3 * scale}`);
2759
+ const boxWidth = cellWidth * .9;
2760
+ const boxHeight = cellHeight * .9;
2761
+ const container = areaGroup.append("foreignObject").attr("class", "venn-text-node-fo").attr("width", boxWidth).attr("height", boxHeight).attr("x", x - boxWidth / 2).attr("y", y - boxHeight / 2).attr("overflow", "visible");
2762
+ const textColor = styleByKey.get(node.id)?.color;
2763
+ const text = container.append("xhtml:span").attr("class", "venn-text-node").style("display", "flex").style("width", "100%").style("height", "100%").style("white-space", "normal").style("align-items", "center").style("justify-content", "center").style("text-align", "center").style("overflow-wrap", "normal").style("word-break", "normal").text(node.label ?? node.id);
2764
+ if (textColor) text.style("color", textColor);
2765
+ }
2766
+ }
2767
+ }
2768
+ __name(renderTextNodes, "renderTextNodes");
2769
+ function ensurePairwiseSubsets(subsets2) {
2770
+ const existingKeys = new Set(subsets2.map((s) => [...s.sets].sort().join("|")));
2771
+ const individualSetSizes = new Map(subsets2.filter((s) => s.sets.length === 1 && s.size !== void 0).map((s) => [s.sets[0], s.size]));
2772
+ const synthetic = [];
2773
+ for (const subset of subsets2) {
2774
+ if (subset.sets.length < 3) continue;
2775
+ const members = [...subset.sets].sort();
2776
+ for (let i = 0; i < members.length - 1; i++) for (let j = i + 1; j < members.length; j++) {
2777
+ const pair = [members[i], members[j]];
2778
+ const key = pair.join("|");
2779
+ if (!existingKeys.has(key)) {
2780
+ existingKeys.add(key);
2781
+ const sizeA = individualSetSizes.get(pair[0]);
2782
+ const sizeB = individualSetSizes.get(pair[1]);
2783
+ const pairSize = sizeA !== void 0 && sizeB !== void 0 ? Math.min(sizeA, sizeB) / 4 : 2.5;
2784
+ synthetic.push({
2785
+ sets: pair,
2786
+ size: pairSize,
2787
+ label: ""
2788
+ });
2789
+ }
2790
+ }
2791
+ }
2792
+ return synthetic.length > 0 ? [...subsets2, ...synthetic] : subsets2;
2793
+ }
2794
+ __name(ensurePairwiseSubsets, "ensurePairwiseSubsets");
2795
+ var diagram = {
2796
+ parser: venn_default,
2797
+ db,
2798
+ renderer: { draw },
2799
+ styles: styles_default
2800
+ };
2801
+
2802
+ //#endregion
2803
+ export { diagram };