@diagrammo/dgmo 0.15.0 → 0.15.1

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 (64) hide show
  1. package/README.md +14 -1
  2. package/dist/advanced.cjs +53069 -0
  3. package/dist/advanced.d.cts +4691 -0
  4. package/dist/advanced.d.ts +4691 -0
  5. package/dist/advanced.js +52823 -0
  6. package/dist/auto.cjs +1495 -1288
  7. package/dist/auto.js +132 -109
  8. package/dist/auto.mjs +1491 -1284
  9. package/dist/cli.cjs +173 -150
  10. package/dist/index.cjs +1486 -1276
  11. package/dist/index.d.cts +45 -1
  12. package/dist/index.d.ts +45 -1
  13. package/dist/index.js +1481 -1272
  14. package/dist/internal.cjs +1497 -1289
  15. package/dist/internal.d.cts +80 -79
  16. package/dist/internal.d.ts +80 -79
  17. package/dist/internal.js +1492 -1285
  18. package/dist/pert.cjs +325 -0
  19. package/dist/pert.d.cts +542 -0
  20. package/dist/pert.d.ts +542 -0
  21. package/dist/pert.js +294 -0
  22. package/package.json +28 -3
  23. package/src/advanced.ts +731 -0
  24. package/src/auto/index.ts +14 -13
  25. package/src/boxes-and-lines/layout.ts +481 -445
  26. package/src/c4/parser.ts +7 -7
  27. package/src/chart-types.ts +0 -5
  28. package/src/class/parser.ts +1 -9
  29. package/src/cli.ts +9 -7
  30. package/src/completion-types.ts +28 -0
  31. package/src/completion.ts +15 -18
  32. package/src/cycle/layout.ts +2 -2
  33. package/src/d3.ts +1455 -1122
  34. package/src/echarts.ts +11 -11
  35. package/src/er/parser.ts +1 -9
  36. package/src/er/renderer.ts +1 -1
  37. package/src/gantt/calculator.ts +1 -11
  38. package/src/gantt/parser.ts +16 -16
  39. package/src/gantt/renderer.ts +2 -2
  40. package/src/graph/flowchart-parser.ts +1 -1
  41. package/src/graph/flowchart-renderer.ts +1 -1
  42. package/src/graph/state-renderer.ts +1 -1
  43. package/src/index.ts +17 -1
  44. package/src/infra/parser.ts +19 -19
  45. package/src/infra/renderer.ts +2 -2
  46. package/src/internal.ts +9 -721
  47. package/src/kanban/parser.ts +2 -2
  48. package/src/mindmap/layout.ts +1 -1
  49. package/src/mindmap/parser.ts +1 -1
  50. package/src/org/parser.ts +1 -1
  51. package/src/org/renderer.ts +1 -1
  52. package/src/pert/layout.ts +1 -1
  53. package/src/pert/monte-carlo.ts +2 -2
  54. package/src/pert/parser.ts +3 -3
  55. package/src/raci/parser.ts +4 -4
  56. package/src/raci/renderer.ts +1 -1
  57. package/src/sequence/renderer.ts +1 -4
  58. package/src/sitemap/parser.ts +1 -1
  59. package/src/tech-radar/interactive.ts +1 -1
  60. package/src/tech-radar/renderer.ts +1 -1
  61. package/src/utils/tag-groups.ts +11 -12
  62. package/src/wireframe/layout.ts +11 -7
  63. package/src/wireframe/parser.ts +2 -2
  64. package/src/wireframe/renderer.ts +5 -2
package/dist/index.cjs CHANGED
@@ -2238,7 +2238,7 @@ function injectDefaultTagMetadata(entities, tagGroups, skip) {
2238
2238
  }
2239
2239
  }
2240
2240
  }
2241
- function resolveActiveTagGroup(_tagGroups, explicitActiveTag, programmaticOverride) {
2241
+ function resolveActiveTagGroup(tagGroups, explicitActiveTag, programmaticOverride) {
2242
2242
  if (programmaticOverride !== void 0) {
2243
2243
  if (!programmaticOverride) return null;
2244
2244
  if (programmaticOverride.toLowerCase() === "none") return null;
@@ -2248,6 +2248,7 @@ function resolveActiveTagGroup(_tagGroups, explicitActiveTag, programmaticOverri
2248
2248
  if (explicitActiveTag.toLowerCase() === "none") return null;
2249
2249
  return explicitActiveTag;
2250
2250
  }
2251
+ if (tagGroups.length > 0) return tagGroups[0].name;
2251
2252
  return null;
2252
2253
  }
2253
2254
  function matchTagBlockHeading(trimmed) {
@@ -5328,12 +5329,6 @@ function parseClassDiagram(content, palette) {
5328
5329
  diagnostics: [],
5329
5330
  error: null
5330
5331
  };
5331
- const _fail = (line12, message) => {
5332
- const diag = makeDgmoError(line12, message);
5333
- result.diagnostics.push(diag);
5334
- result.error = formatDgmoError(diag);
5335
- return result;
5336
- };
5337
5332
  const classMap = /* @__PURE__ */ new Map();
5338
5333
  const nameAliasMap = /* @__PURE__ */ new Map();
5339
5334
  function resolveAliasName(token) {
@@ -5728,12 +5723,6 @@ function parseERDiagram(content, palette) {
5728
5723
  diagnostics: [],
5729
5724
  error: null
5730
5725
  };
5731
- const _fail = (line12, message) => {
5732
- const diag = makeDgmoError(line12, message);
5733
- result.diagnostics.push(diag);
5734
- result.error = formatDgmoError(diag);
5735
- return result;
5736
- };
5737
5726
  const pushError = (line12, message) => {
5738
5727
  const diag = makeDgmoError(line12, message);
5739
5728
  result.diagnostics.push(diag);
@@ -7170,7 +7159,7 @@ function buildSankeyOption(parsed, textColor, colors, bg, titleConfig) {
7170
7159
  ]
7171
7160
  };
7172
7161
  }
7173
- function buildChordOption(parsed, palette, isDark, textColor, colors, bg, titleConfig) {
7162
+ function buildChordOption(parsed, palette, isDark, textColor, colors, _bg, titleConfig) {
7174
7163
  const nodeSet = /* @__PURE__ */ new Set();
7175
7164
  if (parsed.links) {
7176
7165
  for (const link of parsed.links) {
@@ -7284,7 +7273,7 @@ function evaluateExpression(expr, x) {
7284
7273
  return NaN;
7285
7274
  }
7286
7275
  }
7287
- function buildFunctionOption(parsed, palette, isDark, textColor, axisLineColor, gridOpacity, colors, titleConfig) {
7276
+ function buildFunctionOption(parsed, palette, _isDark, textColor, axisLineColor, gridOpacity, colors, titleConfig) {
7288
7277
  const xRange = parsed.xRange ?? { min: -10, max: 10 };
7289
7278
  const samples = 200;
7290
7279
  const step = (xRange.max - xRange.min) / samples;
@@ -7957,7 +7946,7 @@ function buildHeatmapOption(parsed, palette, isDark, textColor, axisLineColor, t
7957
7946
  ]
7958
7947
  };
7959
7948
  }
7960
- function buildFunnelOption(parsed, palette, isDark, textColor, colors, bg, titleConfig) {
7949
+ function buildFunnelOption(parsed, palette, isDark, textColor, colors, _bg, titleConfig) {
7961
7950
  const sorted = [...parsed.data].sort((a, b) => b.value - a.value);
7962
7951
  const data = sorted.map((d) => {
7963
7952
  const stroke2 = d.color ?? colors[parsed.data.indexOf(d) % colors.length];
@@ -8240,7 +8229,7 @@ function wrapLabel(text, maxChars) {
8240
8229
  if (current) lines.push(current);
8241
8230
  return lines.join("\n");
8242
8231
  }
8243
- function buildBarOption(parsed, palette, isDark, textColor, axisLineColor, splitLineColor, gridOpacity, colors, bg, titleConfig, chartWidth) {
8232
+ function buildBarOption(parsed, palette, isDark, textColor, axisLineColor, splitLineColor, gridOpacity, colors, _bg, titleConfig, chartWidth) {
8244
8233
  const { xLabel, yLabel } = resolveAxisLabels(parsed);
8245
8234
  const isHorizontal = parsed.orientation === "horizontal";
8246
8235
  const labels = parsed.data.map((d) => d.label);
@@ -8567,7 +8556,7 @@ function pieLabelLayout(parsed) {
8567
8556
  if (maxLen > 18) return { outerRadius: 55, fontSize: 13 };
8568
8557
  return { outerRadius: 70, fontSize: 14 };
8569
8558
  }
8570
- function buildPieOption(parsed, palette, isDark, textColor, colors, bg, titleConfig, isDoughnut) {
8559
+ function buildPieOption(parsed, palette, isDark, textColor, colors, _bg, titleConfig, isDoughnut) {
8571
8560
  const HIDE_AXES = { xAxis: { show: false }, yAxis: { show: false } };
8572
8561
  const data = parsed.data.map((d, i) => {
8573
8562
  const stroke2 = d.color ?? colors[i % colors.length];
@@ -8666,7 +8655,7 @@ function buildRadarOption(parsed, palette, isDark, textColor, gridOpacity, title
8666
8655
  ]
8667
8656
  };
8668
8657
  }
8669
- function buildPolarAreaOption(parsed, palette, isDark, textColor, colors, bg, titleConfig) {
8658
+ function buildPolarAreaOption(parsed, palette, isDark, textColor, colors, _bg, titleConfig) {
8670
8659
  const data = parsed.data.map((d, i) => {
8671
8660
  const stroke2 = d.color ?? colors[i % colors.length];
8672
8661
  return {
@@ -8709,7 +8698,7 @@ function buildPolarAreaOption(parsed, palette, isDark, textColor, colors, bg, ti
8709
8698
  ]
8710
8699
  };
8711
8700
  }
8712
- function buildBarStackedOption(parsed, palette, isDark, textColor, axisLineColor, splitLineColor, gridOpacity, colors, bg, titleConfig, chartWidth) {
8701
+ function buildBarStackedOption(parsed, palette, isDark, textColor, axisLineColor, splitLineColor, gridOpacity, colors, _bg, titleConfig, chartWidth) {
8713
8702
  const { xLabel, yLabel } = resolveAxisLabels(parsed);
8714
8703
  const isHorizontal = parsed.orientation === "horizontal";
8715
8704
  const seriesNames = parsed.seriesNames ?? [];
@@ -8849,8 +8838,8 @@ async function renderExtendedChartForExport(content, theme, palette) {
8849
8838
  const titleHeight = option.title && option.title.text ? 40 : 0;
8850
8839
  const legendY = 8 + titleHeight;
8851
8840
  const grid = option.grid;
8852
- const gridLeftPct = grid?.left ? parseFloat(String(grid.left)) : void 0;
8853
- const gridRightPct = grid?.right ? parseFloat(String(grid.right)) : void 0;
8841
+ const gridLeftPct = grid?.["left"] ? parseFloat(String(grid["left"])) : void 0;
8842
+ const gridRightPct = grid?.["right"] ? parseFloat(String(grid["right"])) : void 0;
8854
8843
  const { svg: legendSvgStr } = renderLegendSvg(legendGroups, {
8855
8844
  palette: effectivePalette,
8856
8845
  isDark,
@@ -9200,7 +9189,7 @@ function parseOrg(content, palette) {
9200
9189
  }
9201
9190
  return result;
9202
9191
  }
9203
- function parseNodeLabel(trimmed, _indent, lineNumber, palette, counter, metaAliasMap = /* @__PURE__ */ new Map(), warnFn, nameAliasMap) {
9192
+ function parseNodeLabel(trimmed, _indent, lineNumber, _palette, counter, metaAliasMap = /* @__PURE__ */ new Map(), warnFn, nameAliasMap) {
9204
9193
  const segments = trimmed.split("|").map((s) => s.trim());
9205
9194
  let label = segments[0];
9206
9195
  const asMatch = label.match(/^(.*?)\s+as\s+([A-Za-z][A-Za-z0-9_]{0,11})\s*$/);
@@ -9449,8 +9438,8 @@ function parseKanban(content, palette) {
9449
9438
  columnMetadata,
9450
9439
  parsePipeMetadata(pipeSegments, metaAliasMap)
9451
9440
  );
9452
- if (columnMetadata.wip) {
9453
- const wipVal = parseInt(columnMetadata.wip, 10);
9441
+ if (columnMetadata["wip"]) {
9442
+ const wipVal = parseInt(columnMetadata["wip"], 10);
9454
9443
  if (!isNaN(wipVal)) {
9455
9444
  wipLimit = wipVal;
9456
9445
  }
@@ -9829,7 +9818,7 @@ function parseC4(content, palette) {
9829
9818
  );
9830
9819
  const shape = inferC4Shape(
9831
9820
  nodeName,
9832
- metadata.tech ?? metadata.technology
9821
+ metadata["tech"] ?? metadata["technology"]
9833
9822
  );
9834
9823
  const dNode = {
9835
9824
  name: nodeName,
@@ -9932,11 +9921,11 @@ function parseC4(content, palette) {
9932
9921
  target = targetBody.substring(0, pipeIdx).trim();
9933
9922
  const metaPart = targetBody.substring(pipeIdx + 1).trim();
9934
9923
  const meta = parsePipeMetadata(["", metaPart], metaAliasMap);
9935
- if (meta.tech) {
9936
- technology = meta.tech;
9924
+ if (meta["tech"]) {
9925
+ technology = meta["tech"];
9937
9926
  }
9938
- if (meta.technology) {
9939
- technology = meta.technology;
9927
+ if (meta["technology"]) {
9928
+ technology = meta["technology"];
9940
9929
  }
9941
9930
  }
9942
9931
  const rel = {
@@ -10070,7 +10059,7 @@ function parseC4(content, palette) {
10070
10059
  metaAliasMap,
10071
10060
  () => pushError(lineNumber, MULTIPLE_PIPE_ERROR)
10072
10061
  );
10073
- const shape = explicitShape ?? inferC4Shape(namePart, metadata.tech ?? metadata.technology);
10062
+ const shape = explicitShape ?? inferC4Shape(namePart, metadata["tech"] ?? metadata["technology"]);
10074
10063
  let isADescription;
10075
10064
  if ("description" in metadata) {
10076
10065
  const descVal = metadata["description"].trim();
@@ -10130,7 +10119,7 @@ function parseC4(content, palette) {
10130
10119
  metaAliasMap,
10131
10120
  () => pushError(lineNumber, MULTIPLE_PIPE_ERROR)
10132
10121
  );
10133
- const shape = explicitShape ?? inferC4Shape(namePart, metadata.tech ?? metadata.technology);
10122
+ const shape = explicitShape ?? inferC4Shape(namePart, metadata["tech"] ?? metadata["technology"]);
10134
10123
  let prefixDescription;
10135
10124
  if ("description" in metadata) {
10136
10125
  const descVal = metadata["description"].trim();
@@ -10739,7 +10728,7 @@ function parseSitemap(content, palette) {
10739
10728
  }
10740
10729
  return result;
10741
10730
  }
10742
- function parseNodeLabel2(trimmed, lineNumber, palette, counter, metaAliasMap = /* @__PURE__ */ new Map(), warnFn, _diagnostics, nameAliasMap) {
10731
+ function parseNodeLabel2(trimmed, lineNumber, _palette, counter, metaAliasMap = /* @__PURE__ */ new Map(), warnFn, _diagnostics, nameAliasMap) {
10743
10732
  const segments = trimmed.split("|").map((s) => s.trim());
10744
10733
  let label = segments[0];
10745
10734
  const asMatch = label.match(/^(.*?)\s+as\s+([A-Za-z][A-Za-z0-9_]{0,11})\s*$/);
@@ -11030,11 +11019,11 @@ function parseInfra(content) {
11030
11019
  continue;
11031
11020
  }
11032
11021
  if (trimmed === "animate") {
11033
- result.options.animate = "on";
11022
+ result.options["animate"] = "on";
11034
11023
  continue;
11035
11024
  }
11036
11025
  if (trimmed === "no-animate") {
11037
- result.options.animate = "off";
11026
+ result.options["animate"] = "off";
11038
11027
  continue;
11039
11028
  }
11040
11029
  if (tryParseSharedOption(trimmed, result.options)) {
@@ -11188,8 +11177,8 @@ function parseInfra(content) {
11188
11177
  const pipeMeta = extractPipeMetadata(targetRaw);
11189
11178
  const targetName = pipeMeta.clean || targetRaw;
11190
11179
  warnUnparsedPipeMeta(targetName, lineNumber, warn);
11191
- const split = pipeMeta.tags.split ? parseFloat(pipeMeta.tags.split) : null;
11192
- const fanoutRaw = pipeMeta.tags.fanout ? parseInt(pipeMeta.tags.fanout, 10) : null;
11180
+ const split = pipeMeta.tags["split"] ? parseFloat(pipeMeta.tags["split"]) : null;
11181
+ const fanoutRaw = pipeMeta.tags["fanout"] ? parseInt(pipeMeta.tags["fanout"], 10) : null;
11193
11182
  if (fanoutRaw !== null && fanoutRaw < 1) {
11194
11183
  warn(
11195
11184
  lineNumber,
@@ -11220,8 +11209,8 @@ function parseInfra(content) {
11220
11209
  const pipeMeta = extractPipeMetadata(targetRaw);
11221
11210
  const targetName = pipeMeta.clean || targetRaw;
11222
11211
  warnUnparsedPipeMeta(targetName, lineNumber, warn);
11223
- const split = pipeMeta.tags.split ? parseFloat(pipeMeta.tags.split) : null;
11224
- const fanoutRaw = pipeMeta.tags.fanout ? parseInt(pipeMeta.tags.fanout, 10) : null;
11212
+ const split = pipeMeta.tags["split"] ? parseFloat(pipeMeta.tags["split"]) : null;
11213
+ const fanoutRaw = pipeMeta.tags["fanout"] ? parseInt(pipeMeta.tags["fanout"], 10) : null;
11225
11214
  if (fanoutRaw !== null && fanoutRaw < 1) {
11226
11215
  warn(
11227
11216
  lineNumber,
@@ -11255,8 +11244,8 @@ function parseInfra(content) {
11255
11244
  const pipeMeta = extractPipeMetadata(targetRaw);
11256
11245
  const targetName = pipeMeta.clean || targetRaw;
11257
11246
  warnUnparsedPipeMeta(targetName, lineNumber, warn);
11258
- const split = pipeMeta.tags.split ? parseFloat(pipeMeta.tags.split) : null;
11259
- const fanoutRaw = pipeMeta.tags.fanout ? parseInt(pipeMeta.tags.fanout, 10) : null;
11247
+ const split = pipeMeta.tags["split"] ? parseFloat(pipeMeta.tags["split"]) : null;
11248
+ const fanoutRaw = pipeMeta.tags["fanout"] ? parseInt(pipeMeta.tags["fanout"], 10) : null;
11260
11249
  if (fanoutRaw !== null && fanoutRaw < 1) {
11261
11250
  warn(
11262
11251
  lineNumber,
@@ -11287,8 +11276,8 @@ function parseInfra(content) {
11287
11276
  const pipeMeta = extractPipeMetadata(targetRaw);
11288
11277
  const targetName = pipeMeta.clean || targetRaw;
11289
11278
  warnUnparsedPipeMeta(targetName, lineNumber, warn);
11290
- const split = pipeMeta.tags.split ? parseFloat(pipeMeta.tags.split) : null;
11291
- const fanoutRaw = pipeMeta.tags.fanout ? parseInt(pipeMeta.tags.fanout, 10) : null;
11279
+ const split = pipeMeta.tags["split"] ? parseFloat(pipeMeta.tags["split"]) : null;
11280
+ const fanoutRaw = pipeMeta.tags["fanout"] ? parseInt(pipeMeta.tags["fanout"], 10) : null;
11292
11281
  if (fanoutRaw !== null && fanoutRaw < 1) {
11293
11282
  warn(
11294
11283
  lineNumber,
@@ -11995,15 +11984,15 @@ function parseGantt(content, palette) {
11995
11984
  metaAliasMap,
11996
11985
  () => warn(lineNumber, MULTIPLE_PIPE_ERROR)
11997
11986
  );
11998
- if (meta.lag || meta.lead) {
11999
- const key = meta.lag ? "lag" : "lead";
11987
+ if (meta["lag"] || meta["lead"]) {
11988
+ const key = meta["lag"] ? "lag" : "lead";
12000
11989
  softError(
12001
11990
  lineNumber,
12002
11991
  `"${key}" is no longer supported \u2014 use "offset: ${meta[key]}" instead.${key === "lead" ? ' Negate the value for lead behavior: "offset: -...".' : ""}`
12003
11992
  );
12004
11993
  }
12005
- if (meta.offset) {
12006
- const raw = meta.offset;
11994
+ if (meta["offset"]) {
11995
+ const raw = meta["offset"];
12007
11996
  if (raw.trim().startsWith("+")) {
12008
11997
  warn(
12009
11998
  lineNumber,
@@ -12390,15 +12379,15 @@ function parseGantt(content, palette) {
12390
12379
  metaAliasMap,
12391
12380
  () => warn(lineNumber, MULTIPLE_PIPE_ERROR)
12392
12381
  );
12393
- if (meta.lag || meta.lead) {
12394
- const key = meta.lag ? "lag" : "lead";
12382
+ if (meta["lag"] || meta["lead"]) {
12383
+ const key = meta["lag"] ? "lag" : "lead";
12395
12384
  softError(
12396
12385
  lineNumber,
12397
12386
  `"${key}" is no longer supported \u2014 use "offset: ${meta[key]}" instead.${key === "lead" ? ' Negate the value for lead behavior: "offset: -...".' : ""}`
12398
12387
  );
12399
12388
  }
12400
- if (meta.offset) {
12401
- const raw = meta.offset;
12389
+ if (meta["offset"]) {
12390
+ const raw = meta["offset"];
12402
12391
  if (raw.trim().startsWith("+")) {
12403
12392
  warn(
12404
12393
  lineNumber,
@@ -12469,9 +12458,9 @@ function parseGantt(content, palette) {
12469
12458
  () => warn(ln, MULTIPLE_PIPE_ERROR)
12470
12459
  ) : {};
12471
12460
  let progress = null;
12472
- if (metadata.progress) {
12473
- progress = parseFloat(metadata.progress);
12474
- delete metadata.progress;
12461
+ if (metadata["progress"]) {
12462
+ progress = parseFloat(metadata["progress"]);
12463
+ delete metadata["progress"];
12475
12464
  }
12476
12465
  for (const part of segments.slice(1).join(",").split(",")) {
12477
12466
  const seg = part.trim();
@@ -12480,16 +12469,16 @@ function parseGantt(content, palette) {
12480
12469
  progress = parseInt(progressMatch[1], 10);
12481
12470
  }
12482
12471
  }
12483
- if (metadata.lag || metadata.lead) {
12484
- const key = metadata.lag ? "lag" : "lead";
12472
+ if (metadata["lag"] || metadata["lead"]) {
12473
+ const key = metadata["lag"] ? "lag" : "lead";
12485
12474
  softError(
12486
12475
  ln,
12487
12476
  `"${key}" is no longer supported \u2014 use "offset: ${metadata[key]}" instead.${key === "lead" ? ' Negate the value for lead behavior: "offset: -...".' : ""}`
12488
12477
  );
12489
12478
  }
12490
12479
  let taskOffset;
12491
- if (metadata.offset) {
12492
- const raw = metadata.offset;
12480
+ if (metadata["offset"]) {
12481
+ const raw = metadata["offset"];
12493
12482
  if (raw.trim().startsWith("+")) {
12494
12483
  warn(
12495
12484
  ln,
@@ -12504,7 +12493,7 @@ function parseGantt(content, palette) {
12504
12493
  );
12505
12494
  }
12506
12495
  }
12507
- delete metadata.offset;
12496
+ delete metadata["offset"];
12508
12497
  }
12509
12498
  const groupPath = currentGroupPath();
12510
12499
  const inheritedMeta = {};
@@ -13027,7 +13016,7 @@ function parsePert(content, parseOpts = {}) {
13027
13016
  id,
13028
13017
  name,
13029
13018
  activityIds: [],
13030
- collapsed: meta.collapsed === "true",
13019
+ collapsed: meta["collapsed"] === "true",
13031
13020
  lineNumber,
13032
13021
  ...Object.keys(tags).length > 0 && { tags }
13033
13022
  });
@@ -13289,7 +13278,7 @@ function parsePert(content, parseOpts = {}) {
13289
13278
  name: decl.name,
13290
13279
  ...decl.alias !== void 0 && { alias: decl.alias },
13291
13280
  duration: estimate,
13292
- ...meta.confidence && { confidence: meta.confidence },
13281
+ ...meta["confidence"] && { confidence: meta["confidence"] },
13293
13282
  ...decl.groupHint !== void 0 && { groupId: decl.groupHint },
13294
13283
  lineNumber: decl.lineNumber,
13295
13284
  isMilestone,
@@ -14620,7 +14609,7 @@ function parseMindmap(content, palette) {
14620
14609
  }
14621
14610
  return result;
14622
14611
  }
14623
- function parseNodeLine2(trimmed, lineNumber, palette, counter, aliasMap, warnFn) {
14612
+ function parseNodeLine2(trimmed, lineNumber, _palette, counter, aliasMap, warnFn) {
14624
14613
  const segments = trimmed.split("|").map((s) => s.trim());
14625
14614
  const label = segments[0];
14626
14615
  const metadata = parsePipeMetadata(
@@ -15064,7 +15053,7 @@ function parseWireframe(content) {
15064
15053
  wrapper.isContainer = true;
15065
15054
  wrapper.orientation = "horizontal";
15066
15055
  wrapper.children = children;
15067
- wrapper.metadata._inlineRow = "true";
15056
+ wrapper.metadata["_inlineRow"] = "true";
15068
15057
  pushElement(wrapper);
15069
15058
  }
15070
15059
  for (let i = 0; i < lines.length; i++) {
@@ -15215,7 +15204,7 @@ function parseWireframe(content) {
15215
15204
  wrapper.isContainer = true;
15216
15205
  wrapper.orientation = "horizontal";
15217
15206
  wrapper.children.push(labelEl, fieldEl);
15218
- wrapper.metadata._labelField = "true";
15207
+ wrapper.metadata["_labelField"] = "true";
15219
15208
  pushElement(wrapper);
15220
15209
  }
15221
15210
  } else {
@@ -17036,9 +17025,9 @@ function parseRaci(content, palette) {
17036
17025
  let roleColor;
17037
17026
  if (segments.length > 1) {
17038
17027
  const meta = parsePipeMetadata(segments);
17039
- if (meta.color) {
17028
+ if (meta["color"]) {
17040
17029
  roleColor = resolveColorWithDiagnostic(
17041
- meta.color,
17030
+ meta["color"],
17042
17031
  j + 1,
17043
17032
  result.diagnostics,
17044
17033
  palette
@@ -17105,9 +17094,9 @@ function parseRaci(content, palette) {
17105
17094
  let phaseColor;
17106
17095
  if (phaseMatch[2]) {
17107
17096
  const meta = parsePipeMetadata(["", phaseMatch[2]]);
17108
- if (meta.color) {
17097
+ if (meta["color"]) {
17109
17098
  phaseColor = resolveColorWithDiagnostic(
17110
- meta.color,
17099
+ meta["color"],
17111
17100
  lineNumber,
17112
17101
  result.diagnostics,
17113
17102
  palette
@@ -19116,7 +19105,7 @@ function renderOrg(container, parsed, layout, palette, isDark, onClickItem, expo
19116
19105
  displayNames.set(group.name.toLowerCase(), group.name);
19117
19106
  }
19118
19107
  const rootNodeIds = new Set(parsed.roots.map((r) => r.id));
19119
- const colorOff = parsed.options?.color === "off";
19108
+ const colorOff = parsed.options?.["color"] === "off";
19120
19109
  for (const c of layout.containers) {
19121
19110
  const cG = contentG.append("g").attr("transform", `translate(${c.x}, ${c.y})`).attr("class", "org-container").attr("data-line-number", String(c.lineNumber));
19122
19111
  if (activeTagGroup) {
@@ -22216,7 +22205,7 @@ function renderERDiagram(container, parsed, layout, palette, isDark, onClickItem
22216
22205
  const seriesColors2 = getSeriesColors(palette);
22217
22206
  const semanticRoles = useSemanticColors ? classifyEREntities(parsed.tables, parsed.relationships) : null;
22218
22207
  const semanticActive = semanticRoles !== null && (semanticColorsActive ?? true);
22219
- const useLabels = parsed.options.notation === "labels";
22208
+ const useLabels = parsed.options["notation"] === "labels";
22220
22209
  for (const edge of layout.edges) {
22221
22210
  if (edge.points.length < 2) continue;
22222
22211
  const edgeG = contentG.append("g").attr("class", "er-edge-group").attr("data-line-number", String(edge.lineNumber));
@@ -22431,495 +22420,6 @@ var init_renderer5 = __esm({
22431
22420
  }
22432
22421
  });
22433
22422
 
22434
- // src/boxes-and-lines/layout.ts
22435
- var layout_exports5 = {};
22436
- __export(layout_exports5, {
22437
- layoutBoxesAndLines: () => layoutBoxesAndLines
22438
- });
22439
- function clipToRectBorder2(cx, cy, w, h, tx, ty) {
22440
- const dx = tx - cx;
22441
- const dy = ty - cy;
22442
- if (dx === 0 && dy === 0) return { x: cx, y: cy };
22443
- const hw = w / 2;
22444
- const hh = h / 2;
22445
- const sx = dx !== 0 ? hw / Math.abs(dx) : Infinity;
22446
- const sy = dy !== 0 ? hh / Math.abs(dy) : Infinity;
22447
- const s = Math.min(sx, sy);
22448
- return { x: cx + dx * s, y: cy + dy * s };
22449
- }
22450
- function splitCamelCase(word) {
22451
- const parts = [];
22452
- let start = 0;
22453
- for (let i = 1; i < word.length; i++) {
22454
- const prev = word[i - 1];
22455
- const curr = word[i];
22456
- const next = i + 1 < word.length ? word[i + 1] : "";
22457
- const lowerToUpper = prev >= "a" && prev <= "z" && curr >= "A" && curr <= "Z";
22458
- const upperRunEnd = prev >= "A" && prev <= "Z" && curr >= "A" && curr <= "Z" && next >= "a" && next <= "z";
22459
- if (lowerToUpper || upperRunEnd) {
22460
- parts.push(word.slice(start, i));
22461
- start = i;
22462
- }
22463
- }
22464
- parts.push(word.slice(start));
22465
- return parts.length > 1 ? parts : [word];
22466
- }
22467
- function estimateLabelLines(label, nodeWidth2 = NODE_WIDTH) {
22468
- const rawParts = label.split(/[\s-]+/);
22469
- const words = [];
22470
- for (const part of rawParts) {
22471
- if (!part) continue;
22472
- words.push(...splitCamelCase(part));
22473
- }
22474
- for (let fontSize = 13; fontSize >= 9; fontSize--) {
22475
- const charWidth = fontSize * 0.6;
22476
- const maxChars = Math.floor((nodeWidth2 - 24) / charWidth);
22477
- if (maxChars < 2) continue;
22478
- let lines = 1;
22479
- let current = "";
22480
- for (const word of words) {
22481
- const test = current ? `${current} ${word}` : word;
22482
- if (test.length <= maxChars) {
22483
- current = test;
22484
- } else {
22485
- lines++;
22486
- current = word;
22487
- }
22488
- }
22489
- if (lines <= MAX_LABEL_LINES) return Math.min(lines, MAX_LABEL_LINES);
22490
- }
22491
- return MAX_LABEL_LINES;
22492
- }
22493
- function computeNodeSize(node) {
22494
- if (!node.description || node.description.length === 0) {
22495
- return { width: NODE_WIDTH, height: NODE_HEIGHT };
22496
- }
22497
- const w = DESC_NODE_WIDTH;
22498
- const labelLines = estimateLabelLines(node.label, w);
22499
- const labelHeight = labelLines * 13 * LABEL_LINE_HEIGHT + LABEL_PAD;
22500
- const charsPerLine = Math.floor((w - 24) / (DESC_FONT_SIZE * 0.6));
22501
- let totalRenderedLines = 0;
22502
- for (const line12 of node.description) {
22503
- if (line12.length <= charsPerLine) {
22504
- totalRenderedLines += 1;
22505
- } else {
22506
- const words = line12.split(/\s+/);
22507
- let current = "";
22508
- let lineCount = 0;
22509
- for (const word of words) {
22510
- const fitted = word.length > charsPerLine ? word.slice(0, charsPerLine) : word;
22511
- const test = current ? `${current} ${fitted}` : fitted;
22512
- if (test.length <= charsPerLine) {
22513
- current = test;
22514
- } else {
22515
- if (current) lineCount++;
22516
- current = fitted;
22517
- }
22518
- }
22519
- if (current) lineCount++;
22520
- totalRenderedLines += lineCount;
22521
- }
22522
- }
22523
- totalRenderedLines = Math.min(totalRenderedLines, MAX_DESC_LINES);
22524
- const descriptionHeight = totalRenderedLines * DESC_FONT_SIZE * DESC_LINE_HEIGHT;
22525
- const totalHeight = labelHeight + SEPARATOR_GAP5 + DESC_PADDING + descriptionHeight + DESC_PADDING;
22526
- return { width: w, height: Math.max(NODE_HEIGHT, totalHeight) };
22527
- }
22528
- function layoutBoxesAndLines(parsed, collapseInfo, layoutOptions) {
22529
- const hideDescriptions = layoutOptions?.hideDescriptions ?? false;
22530
- const g = new import_dagre4.default.graphlib.Graph({ compound: true, multigraph: true });
22531
- g.setGraph({
22532
- rankdir: parsed.direction,
22533
- nodesep: NODESEP,
22534
- ranksep: RANKSEP,
22535
- marginx: MARGIN3,
22536
- marginy: MARGIN3
22537
- });
22538
- g.setDefaultEdgeLabel(() => ({}));
22539
- const collapsedGroupLabels = /* @__PURE__ */ new Set();
22540
- if (collapseInfo) {
22541
- const missingGroups = /* @__PURE__ */ new Set();
22542
- for (const og of collapseInfo.originalGroups) {
22543
- if (!parsed.groups.some((g2) => g2.label === og.label)) {
22544
- missingGroups.add(og.label);
22545
- }
22546
- }
22547
- for (const label of missingGroups) {
22548
- const og = collapseInfo.originalGroups.find((g2) => g2.label === label);
22549
- const parentLabel = og?.parentGroup;
22550
- if (!parentLabel || !missingGroups.has(parentLabel)) {
22551
- collapsedGroupLabels.add(label);
22552
- }
22553
- }
22554
- }
22555
- for (const label of collapsedGroupLabels) {
22556
- const gid = `__group_${label}`;
22557
- g.setNode(gid, { label, width: NODE_WIDTH, height: NODE_HEIGHT });
22558
- }
22559
- for (const group of parsed.groups) {
22560
- const gid = `__group_${group.label}`;
22561
- g.setNode(gid, {
22562
- label: group.label,
22563
- paddingLeft: CONTAINER_PAD_X3,
22564
- paddingRight: CONTAINER_PAD_X3,
22565
- paddingTop: CONTAINER_PAD_TOP2,
22566
- paddingBottom: CONTAINER_PAD_BOTTOM3
22567
- });
22568
- }
22569
- const originalGroupByLabel = /* @__PURE__ */ new Map();
22570
- if (collapseInfo) {
22571
- for (const og of collapseInfo.originalGroups) {
22572
- originalGroupByLabel.set(og.label, og);
22573
- }
22574
- }
22575
- for (const label of collapsedGroupLabels) {
22576
- const og = originalGroupByLabel.get(label);
22577
- if (og?.parentGroup && !collapsedGroupLabels.has(og.parentGroup)) {
22578
- const gid = `__group_${label}`;
22579
- const parentGid = `__group_${og.parentGroup}`;
22580
- if (g.hasNode(parentGid)) {
22581
- g.setParent(gid, parentGid);
22582
- }
22583
- }
22584
- }
22585
- const nodeSizes = /* @__PURE__ */ new Map();
22586
- let maxDescHeight = 0;
22587
- for (const node of parsed.nodes) {
22588
- const size = hideDescriptions ? { width: NODE_WIDTH, height: NODE_HEIGHT } : computeNodeSize(node);
22589
- nodeSizes.set(node.label, size);
22590
- if (!hideDescriptions && node.description && node.description.length > 0) {
22591
- maxDescHeight = Math.max(maxDescHeight, size.height);
22592
- }
22593
- }
22594
- if (maxDescHeight > 0) {
22595
- for (const node of parsed.nodes) {
22596
- if (node.description && node.description.length > 0) {
22597
- const size = nodeSizes.get(node.label);
22598
- nodeSizes.set(node.label, { width: size.width, height: maxDescHeight });
22599
- }
22600
- }
22601
- }
22602
- for (const node of parsed.nodes) {
22603
- const size = nodeSizes.get(node.label);
22604
- g.setNode(node.label, {
22605
- label: node.label,
22606
- width: size.width,
22607
- height: size.height
22608
- });
22609
- }
22610
- for (const group of parsed.groups) {
22611
- if (group.parentGroup) {
22612
- const childGid = `__group_${group.label}`;
22613
- const parentGid = `__group_${group.parentGroup}`;
22614
- if (g.hasNode(childGid) && g.hasNode(parentGid)) {
22615
- g.setParent(childGid, parentGid);
22616
- }
22617
- }
22618
- }
22619
- const groupLabelSet = new Set(parsed.groups.map((gr) => gr.label));
22620
- for (const group of parsed.groups) {
22621
- const gid = `__group_${group.label}`;
22622
- for (const child of group.children) {
22623
- if (groupLabelSet.has(child)) continue;
22624
- if (g.hasNode(child)) {
22625
- g.setParent(child, gid);
22626
- }
22627
- }
22628
- }
22629
- const expandedGroupIds = /* @__PURE__ */ new Set();
22630
- for (const group of parsed.groups) {
22631
- expandedGroupIds.add(`__group_${group.label}`);
22632
- }
22633
- const groupFirstChild = /* @__PURE__ */ new Map();
22634
- for (const group of parsed.groups) {
22635
- const gid = `__group_${group.label}`;
22636
- const firstChild = group.children.find(
22637
- (c) => !groupLabelSet.has(c) && g.hasNode(c)
22638
- );
22639
- if (firstChild) {
22640
- groupFirstChild.set(gid, firstChild);
22641
- }
22642
- }
22643
- const deferredEdgeIndices = [];
22644
- let proxyIdx = 0;
22645
- for (let i = 0; i < parsed.edges.length; i++) {
22646
- const edge = parsed.edges[i];
22647
- const src = edge.source;
22648
- const tgt = edge.target;
22649
- if (!g.hasNode(src) || !g.hasNode(tgt)) continue;
22650
- if (expandedGroupIds.has(src) || expandedGroupIds.has(tgt)) {
22651
- deferredEdgeIndices.push(i);
22652
- const proxySrc = expandedGroupIds.has(src) ? groupFirstChild.get(src) : src;
22653
- const proxyTgt = expandedGroupIds.has(tgt) ? groupFirstChild.get(tgt) : tgt;
22654
- if (proxySrc && proxyTgt && proxySrc !== proxyTgt) {
22655
- g.setEdge(
22656
- proxySrc,
22657
- proxyTgt,
22658
- { label: "", minlen: 1 },
22659
- `proxy${proxyIdx++}`
22660
- );
22661
- }
22662
- continue;
22663
- }
22664
- g.setEdge(src, tgt, { label: edge.label ?? "", minlen: 1 }, `e${i}`);
22665
- }
22666
- import_dagre4.default.layout(g);
22667
- const layoutNodes = [];
22668
- for (const node of parsed.nodes) {
22669
- const dagreNode = g.node(node.label);
22670
- if (!dagreNode) continue;
22671
- layoutNodes.push({
22672
- label: node.label,
22673
- x: dagreNode.x,
22674
- y: dagreNode.y,
22675
- width: dagreNode.width,
22676
- height: dagreNode.height
22677
- });
22678
- }
22679
- const layoutGroups = [];
22680
- for (const group of parsed.groups) {
22681
- const gid = `__group_${group.label}`;
22682
- const dagreNode = g.node(gid);
22683
- if (!dagreNode) continue;
22684
- layoutGroups.push({
22685
- label: group.label,
22686
- lineNumber: group.lineNumber,
22687
- x: dagreNode.x,
22688
- y: dagreNode.y,
22689
- width: dagreNode.width,
22690
- height: dagreNode.height,
22691
- collapsed: false
22692
- });
22693
- }
22694
- for (const label of collapsedGroupLabels) {
22695
- const gid = `__group_${label}`;
22696
- const dagreNode = g.node(gid);
22697
- if (!dagreNode) continue;
22698
- const og = collapseInfo?.originalGroups.find((g2) => g2.label === label);
22699
- layoutGroups.push({
22700
- label,
22701
- lineNumber: og?.lineNumber ?? 0,
22702
- x: dagreNode.x,
22703
- y: dagreNode.y,
22704
- width: dagreNode.width,
22705
- height: dagreNode.height,
22706
- collapsed: true,
22707
- childCount: collapseInfo?.collapsedChildCounts.get(label) ?? 0
22708
- });
22709
- }
22710
- const groupAlignShifts = /* @__PURE__ */ new Map();
22711
- {
22712
- const groupEdges = [];
22713
- for (const edge of parsed.edges) {
22714
- if (edge.source.startsWith("__group_") && edge.target.startsWith("__group_")) {
22715
- groupEdges.push(edge);
22716
- }
22717
- }
22718
- if (groupEdges.length > 0) {
22719
- const groupParent = /* @__PURE__ */ new Map();
22720
- const find = (x) => {
22721
- while (groupParent.has(x) && groupParent.get(x) !== x) {
22722
- groupParent.set(x, groupParent.get(groupParent.get(x)));
22723
- x = groupParent.get(x);
22724
- }
22725
- return x;
22726
- };
22727
- const union = (a, b) => {
22728
- const ra = find(a), rb = find(b);
22729
- if (ra !== rb) groupParent.set(ra, rb);
22730
- };
22731
- for (const edge of groupEdges) {
22732
- if (!groupParent.has(edge.source))
22733
- groupParent.set(edge.source, edge.source);
22734
- if (!groupParent.has(edge.target))
22735
- groupParent.set(edge.target, edge.target);
22736
- union(edge.source, edge.target);
22737
- }
22738
- const components = /* @__PURE__ */ new Map();
22739
- for (const lg of layoutGroups) {
22740
- const gid = `__group_${lg.label}`;
22741
- if (!groupParent.has(gid)) continue;
22742
- const root = find(gid);
22743
- if (!components.has(root)) components.set(root, []);
22744
- components.get(root).push(lg);
22745
- }
22746
- const axis = parsed.direction === "TB" ? "x" : "y";
22747
- for (const groups of components.values()) {
22748
- if (groups.length < 2) continue;
22749
- const dim = axis === "x" ? "width" : "height";
22750
- let widest = groups[0];
22751
- for (const g2 of groups) {
22752
- if (g2[dim] > widest[dim]) widest = g2;
22753
- }
22754
- const targetCenter = widest[axis];
22755
- for (const grp of groups) {
22756
- const dx = targetCenter - grp[axis];
22757
- if (dx === 0) continue;
22758
- grp[axis] += dx;
22759
- groupAlignShifts.set(`__group_${grp.label}`, dx);
22760
- const parsedGroup = parsed.groups.find(
22761
- (pg) => pg.label === grp.label
22762
- );
22763
- if (parsedGroup) {
22764
- for (const childLabel of parsedGroup.children) {
22765
- const childNode = layoutNodes.find((n) => n.label === childLabel);
22766
- if (childNode) childNode[axis] += dx;
22767
- }
22768
- }
22769
- }
22770
- }
22771
- }
22772
- }
22773
- const edgeYOffsets = new Array(parsed.edges.length).fill(0);
22774
- const edgeParallelCounts = new Array(parsed.edges.length).fill(1);
22775
- const parallelGroups = /* @__PURE__ */ new Map();
22776
- for (let i = 0; i < parsed.edges.length; i++) {
22777
- const edge = parsed.edges[i];
22778
- const [a, b] = edge.source < edge.target ? [edge.source, edge.target] : [edge.target, edge.source];
22779
- const key = `${a}\0${b}`;
22780
- if (!parallelGroups.has(key)) parallelGroups.set(key, []);
22781
- parallelGroups.get(key).push(i);
22782
- }
22783
- for (const group of parallelGroups.values()) {
22784
- const capped = group.slice(0, MAX_PARALLEL_EDGES);
22785
- for (const idx of group.slice(MAX_PARALLEL_EDGES)) {
22786
- edgeParallelCounts[idx] = 0;
22787
- }
22788
- if (capped.length < 2) continue;
22789
- const effectiveSpacing = PARALLEL_SPACING;
22790
- for (let j = 0; j < capped.length; j++) {
22791
- edgeYOffsets[capped[j]] = (j - (capped.length - 1) / 2) * effectiveSpacing;
22792
- edgeParallelCounts[capped[j]] = capped.length;
22793
- }
22794
- }
22795
- const deferredSet = new Set(deferredEdgeIndices);
22796
- const layoutEdges = [];
22797
- for (let i = 0; i < parsed.edges.length; i++) {
22798
- const edge = parsed.edges[i];
22799
- if (edgeParallelCounts[i] === 0) continue;
22800
- let points;
22801
- if (deferredSet.has(i)) {
22802
- const srcLayout = layoutGroups.find(
22803
- (lg) => `__group_${lg.label}` === edge.source
22804
- );
22805
- const tgtLayout = layoutGroups.find(
22806
- (lg) => `__group_${lg.label}` === edge.target
22807
- );
22808
- if (!srcLayout || !tgtLayout) {
22809
- const srcNode = g.node(edge.source);
22810
- const tgtNode = g.node(edge.target);
22811
- if (!srcNode || !tgtNode) continue;
22812
- const srcPt = clipToRectBorder2(
22813
- srcNode.x,
22814
- srcNode.y,
22815
- srcNode.width,
22816
- srcNode.height,
22817
- tgtNode.x,
22818
- tgtNode.y
22819
- );
22820
- const tgtPt = clipToRectBorder2(
22821
- tgtNode.x,
22822
- tgtNode.y,
22823
- tgtNode.width,
22824
- tgtNode.height,
22825
- srcNode.x,
22826
- srcNode.y
22827
- );
22828
- const midX = (srcPt.x + tgtPt.x) / 2;
22829
- const midY = (srcPt.y + tgtPt.y) / 2;
22830
- points = [srcPt, { x: midX, y: midY }, tgtPt];
22831
- } else if (parsed.direction === "TB") {
22832
- const cx = (srcLayout.x + tgtLayout.x) / 2;
22833
- const srcPt = { x: cx, y: srcLayout.y + srcLayout.height / 2 };
22834
- const tgtPt = { x: cx, y: tgtLayout.y - tgtLayout.height / 2 };
22835
- const midY = (srcPt.y + tgtPt.y) / 2;
22836
- points = [srcPt, { x: cx, y: midY }, tgtPt];
22837
- } else {
22838
- const cy = (srcLayout.y + tgtLayout.y) / 2;
22839
- const srcPt = { x: srcLayout.x + srcLayout.width / 2, y: cy };
22840
- const tgtPt = { x: tgtLayout.x - tgtLayout.width / 2, y: cy };
22841
- const midX = (srcPt.x + tgtPt.x) / 2;
22842
- points = [srcPt, { x: midX, y: cy }, tgtPt];
22843
- }
22844
- } else {
22845
- const dagreEdge = g.edge(edge.source, edge.target, `e${i}`);
22846
- points = dagreEdge?.points ?? [];
22847
- const srcShift = groupAlignShifts.get(edge.source) ?? 0;
22848
- const tgtShift = groupAlignShifts.get(edge.target) ?? 0;
22849
- if (srcShift !== 0 || tgtShift !== 0) {
22850
- const avgShift = (srcShift + tgtShift) / 2;
22851
- const prop = parsed.direction === "TB" ? "x" : "y";
22852
- points = points.map((p) => ({ ...p, [prop]: p[prop] + avgShift }));
22853
- }
22854
- }
22855
- let labelX;
22856
- let labelY;
22857
- if (edge.label && points.length >= 2) {
22858
- const mid = Math.floor(points.length / 2);
22859
- labelX = points[mid].x;
22860
- labelY = points[mid].y - 10;
22861
- }
22862
- layoutEdges.push({
22863
- source: edge.source,
22864
- target: edge.target,
22865
- label: edge.label,
22866
- bidirectional: edge.bidirectional,
22867
- lineNumber: edge.lineNumber,
22868
- points,
22869
- labelX,
22870
- labelY,
22871
- yOffset: edgeYOffsets[i],
22872
- parallelCount: edgeParallelCounts[i],
22873
- metadata: edge.metadata,
22874
- deferred: deferredSet.has(i) || void 0
22875
- });
22876
- }
22877
- let maxX = 0;
22878
- let maxY = 0;
22879
- for (const node of layoutNodes) {
22880
- maxX = Math.max(maxX, node.x + node.width / 2);
22881
- maxY = Math.max(maxY, node.y + node.height / 2);
22882
- }
22883
- for (const group of layoutGroups) {
22884
- maxX = Math.max(maxX, group.x + group.width / 2);
22885
- maxY = Math.max(maxY, group.y + group.height / 2);
22886
- }
22887
- return {
22888
- nodes: layoutNodes,
22889
- edges: layoutEdges,
22890
- groups: layoutGroups,
22891
- width: maxX + MARGIN3,
22892
- height: maxY + MARGIN3
22893
- };
22894
- }
22895
- var import_dagre4, NODESEP, RANKSEP, MARGIN3, CONTAINER_PAD_X3, CONTAINER_PAD_TOP2, CONTAINER_PAD_BOTTOM3, MAX_PARALLEL_EDGES, PARALLEL_SPACING, PHI, NODE_HEIGHT, NODE_WIDTH, DESC_NODE_WIDTH, DESC_FONT_SIZE, DESC_LINE_HEIGHT, DESC_PADDING, SEPARATOR_GAP5, MAX_DESC_LINES, MAX_LABEL_LINES, LABEL_LINE_HEIGHT, LABEL_PAD;
22896
- var init_layout5 = __esm({
22897
- "src/boxes-and-lines/layout.ts"() {
22898
- "use strict";
22899
- import_dagre4 = __toESM(require("@dagrejs/dagre"), 1);
22900
- NODESEP = 60;
22901
- RANKSEP = 100;
22902
- MARGIN3 = 40;
22903
- CONTAINER_PAD_X3 = 30;
22904
- CONTAINER_PAD_TOP2 = 40;
22905
- CONTAINER_PAD_BOTTOM3 = 24;
22906
- MAX_PARALLEL_EDGES = 5;
22907
- PARALLEL_SPACING = 22;
22908
- PHI = 1.618;
22909
- NODE_HEIGHT = 60;
22910
- NODE_WIDTH = Math.round(NODE_HEIGHT * PHI);
22911
- DESC_NODE_WIDTH = 140;
22912
- DESC_FONT_SIZE = 10;
22913
- DESC_LINE_HEIGHT = 1.4;
22914
- DESC_PADDING = 8;
22915
- SEPARATOR_GAP5 = 4;
22916
- MAX_DESC_LINES = 6;
22917
- MAX_LABEL_LINES = 3;
22918
- LABEL_LINE_HEIGHT = 1.3;
22919
- LABEL_PAD = 12;
22920
- }
22921
- });
22922
-
22923
22423
  // src/utils/wrapped-desc.ts
22924
22424
  function wrapDescriptionLines(lines, charsPerLine, lengthFn = (s) => s.length) {
22925
22425
  const result = [];
@@ -22969,7 +22469,7 @@ __export(renderer_exports6, {
22969
22469
  renderBoxesAndLines: () => renderBoxesAndLines,
22970
22470
  renderBoxesAndLinesForExport: () => renderBoxesAndLinesForExport
22971
22471
  });
22972
- function splitCamelCase2(word) {
22472
+ function splitCamelCase(word) {
22973
22473
  const parts = [];
22974
22474
  let start = 0;
22975
22475
  for (let i = 1; i < word.length; i++) {
@@ -22992,7 +22492,7 @@ function fitLabelToHeader(label, nodeWidth2, maxLines) {
22992
22492
  const words = [];
22993
22493
  for (const part of rawParts) {
22994
22494
  if (!part || /^\s+$/.test(part) || part === "-") continue;
22995
- words.push(...splitCamelCase2(part));
22495
+ words.push(...splitCamelCase(part));
22996
22496
  }
22997
22497
  for (let fontSize = NODE_FONT_SIZE; fontSize >= MIN_NODE_FONT_SIZE; fontSize--) {
22998
22498
  const charWidth2 = fontSize * CHAR_WIDTH_RATIO2;
@@ -23368,12 +22868,12 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
23368
22868
  }
23369
22869
  const sepY = -ln.height / 2 + headerH;
23370
22870
  nodeG.append("line").attr("x1", -ln.width / 2).attr("y1", sepY).attr("x2", ln.width / 2).attr("y2", sepY).attr("stroke", colors.stroke).attr("stroke-opacity", 0.3).attr("stroke-width", 1);
23371
- const descStartY = sepY + 4 + DESC_FONT_SIZE2;
22871
+ const descStartY = sepY + 4 + DESC_FONT_SIZE;
23372
22872
  const maxTextWidth = ln.width - NODE_TEXT_PADDING * 2;
23373
22873
  const charsPerLine = Math.floor(
23374
- maxTextWidth / (DESC_FONT_SIZE2 * CHAR_WIDTH_RATIO2)
22874
+ maxTextWidth / (DESC_FONT_SIZE * CHAR_WIDTH_RATIO2)
23375
22875
  );
23376
- const descLineH = DESC_FONT_SIZE2 * DESC_LINE_HEIGHT2;
22876
+ const descLineH = DESC_FONT_SIZE * DESC_LINE_HEIGHT;
23377
22877
  const displayLen = (text) => text.replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/\*\*(.+?)\*\*/g, "$1").replace(/\*(.+?)\*/g, "$1").replace(/`(.+?)`/g, "$1").replace(/https?:\/\/\S+/g, (u) => u.slice(0, 20)).length;
23378
22878
  const normalizedLines = [];
23379
22879
  for (const descLine of desc) {
@@ -23389,8 +22889,8 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
23389
22889
  charsPerLine,
23390
22890
  displayLen
23391
22891
  );
23392
- const truncated = wrappedLinesShared.length > MAX_DESC_LINES2;
23393
- const visibleLines = truncated ? wrappedLinesShared.slice(0, MAX_DESC_LINES2) : wrappedLinesShared;
22892
+ const truncated = wrappedLinesShared.length > MAX_DESC_LINES;
22893
+ const visibleLines = truncated ? wrappedLinesShared.slice(0, MAX_DESC_LINES) : wrappedLinesShared;
23394
22894
  const BULLET_GLYPH_X = -ln.width / 2 + 6;
23395
22895
  const BULLET_BODY_X = BULLET_GLYPH_X + 10;
23396
22896
  for (let li = 0; li < visibleLines.length; li++) {
@@ -23401,11 +22901,11 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
23401
22901
  }
23402
22902
  const y2 = descStartY + li * descLineH;
23403
22903
  if (line12.kind === "bullet-first") {
23404
- nodeG.append("text").attr("x", BULLET_GLYPH_X).attr("y", y2).attr("text-anchor", "start").attr("dominant-baseline", "central").attr("font-size", DESC_FONT_SIZE2).attr("fill", palette.textMuted).text("\u2022");
22904
+ nodeG.append("text").attr("x", BULLET_GLYPH_X).attr("y", y2).attr("text-anchor", "start").attr("dominant-baseline", "central").attr("font-size", DESC_FONT_SIZE).attr("fill", palette.textMuted).text("\u2022");
23405
22905
  }
23406
22906
  const isBullet = line12.kind === "bullet-first" || line12.kind === "bullet-cont";
23407
- const textEl = nodeG.append("text").attr("x", isBullet ? BULLET_BODY_X : 0).attr("y", y2).attr("text-anchor", isBullet ? "start" : "middle").attr("dominant-baseline", "central").attr("font-size", DESC_FONT_SIZE2).attr("fill", palette.textMuted);
23408
- renderInlineText(textEl, lineText, palette, DESC_FONT_SIZE2);
22907
+ const textEl = nodeG.append("text").attr("x", isBullet ? BULLET_BODY_X : 0).attr("y", y2).attr("text-anchor", isBullet ? "start" : "middle").attr("dominant-baseline", "central").attr("font-size", DESC_FONT_SIZE).attr("fill", palette.textMuted);
22908
+ renderInlineText(textEl, lineText, palette, DESC_FONT_SIZE);
23409
22909
  }
23410
22910
  if (truncated) {
23411
22911
  const fullText = desc.join(" ");
@@ -23483,7 +22983,7 @@ function renderBoxesAndLinesForExport(container, parsed, layout, palette, isDark
23483
22983
  hiddenTagValues: options?.hiddenTagValues
23484
22984
  });
23485
22985
  }
23486
- var d3Selection6, d3Shape4, DIAGRAM_PADDING6, NODE_FONT_SIZE, MIN_NODE_FONT_SIZE, EDGE_LABEL_FONT_SIZE4, EDGE_STROKE_WIDTH5, NODE_STROKE_WIDTH5, NODE_RX, COLLAPSE_BAR_HEIGHT3, ARROWHEAD_W2, ARROWHEAD_H2, DESC_FONT_SIZE2, DESC_LINE_HEIGHT2, MAX_DESC_LINES2, CHAR_WIDTH_RATIO2, NODE_TEXT_PADDING, GROUP_RX, GROUP_LABEL_FONT_SIZE, GROUP_LABEL_ZONE, lineGeneratorLR, lineGeneratorTB;
22986
+ var d3Selection6, d3Shape4, DIAGRAM_PADDING6, NODE_FONT_SIZE, MIN_NODE_FONT_SIZE, EDGE_LABEL_FONT_SIZE4, EDGE_STROKE_WIDTH5, NODE_STROKE_WIDTH5, NODE_RX, COLLAPSE_BAR_HEIGHT3, ARROWHEAD_W2, ARROWHEAD_H2, DESC_FONT_SIZE, DESC_LINE_HEIGHT, MAX_DESC_LINES, CHAR_WIDTH_RATIO2, NODE_TEXT_PADDING, GROUP_RX, GROUP_LABEL_FONT_SIZE, GROUP_LABEL_ZONE, lineGeneratorLR, lineGeneratorTB;
23487
22987
  var init_renderer6 = __esm({
23488
22988
  "src/boxes-and-lines/renderer.ts"() {
23489
22989
  "use strict";
@@ -23507,9 +23007,9 @@ var init_renderer6 = __esm({
23507
23007
  COLLAPSE_BAR_HEIGHT3 = 4;
23508
23008
  ARROWHEAD_W2 = 5;
23509
23009
  ARROWHEAD_H2 = 4;
23510
- DESC_FONT_SIZE2 = 10;
23511
- DESC_LINE_HEIGHT2 = 1.4;
23512
- MAX_DESC_LINES2 = 6;
23010
+ DESC_FONT_SIZE = 10;
23011
+ DESC_LINE_HEIGHT = 1.4;
23012
+ MAX_DESC_LINES = 6;
23513
23013
  CHAR_WIDTH_RATIO2 = 0.6;
23514
23014
  NODE_TEXT_PADDING = 12;
23515
23015
  GROUP_RX = 8;
@@ -23520,6 +23020,523 @@ var init_renderer6 = __esm({
23520
23020
  }
23521
23021
  });
23522
23022
 
23023
+ // src/boxes-and-lines/layout.ts
23024
+ var layout_exports5 = {};
23025
+ __export(layout_exports5, {
23026
+ layoutBoxesAndLines: () => layoutBoxesAndLines
23027
+ });
23028
+ function splitCamelCase2(word) {
23029
+ const parts = [];
23030
+ let start = 0;
23031
+ for (let i = 1; i < word.length; i++) {
23032
+ const prev = word[i - 1];
23033
+ const curr = word[i];
23034
+ const next = i + 1 < word.length ? word[i + 1] : "";
23035
+ const lowerToUpper = prev >= "a" && prev <= "z" && curr >= "A" && curr <= "Z";
23036
+ const upperRunEnd = prev >= "A" && prev <= "Z" && curr >= "A" && curr <= "Z" && next >= "a" && next <= "z";
23037
+ if (lowerToUpper || upperRunEnd) {
23038
+ parts.push(word.slice(start, i));
23039
+ start = i;
23040
+ }
23041
+ }
23042
+ parts.push(word.slice(start));
23043
+ return parts.length > 1 ? parts : [word];
23044
+ }
23045
+ function estimateLabelLines(label, nodeWidth2 = NODE_WIDTH) {
23046
+ const rawParts = label.split(/[\s-]+/);
23047
+ const words = [];
23048
+ for (const part of rawParts) {
23049
+ if (!part) continue;
23050
+ words.push(...splitCamelCase2(part));
23051
+ }
23052
+ for (let fontSize = 13; fontSize >= 9; fontSize--) {
23053
+ const charWidth = fontSize * 0.6;
23054
+ const maxChars = Math.floor((nodeWidth2 - 24) / charWidth);
23055
+ if (maxChars < 2) continue;
23056
+ let lines = 1;
23057
+ let current = "";
23058
+ for (const word of words) {
23059
+ const test = current ? `${current} ${word}` : word;
23060
+ if (test.length <= maxChars) {
23061
+ current = test;
23062
+ } else {
23063
+ lines++;
23064
+ current = word;
23065
+ }
23066
+ }
23067
+ if (lines <= MAX_LABEL_LINES) return Math.min(lines, MAX_LABEL_LINES);
23068
+ }
23069
+ return MAX_LABEL_LINES;
23070
+ }
23071
+ function computeNodeSize(node) {
23072
+ if (!node.description || node.description.length === 0) {
23073
+ return { width: NODE_WIDTH, height: NODE_HEIGHT };
23074
+ }
23075
+ const w = DESC_NODE_WIDTH;
23076
+ const labelLines = estimateLabelLines(node.label, w);
23077
+ const labelHeight = labelLines * 13 * LABEL_LINE_HEIGHT + LABEL_PAD;
23078
+ const charsPerLine = Math.floor((w - 24) / (DESC_FONT_SIZE2 * 0.6));
23079
+ let totalRenderedLines = 0;
23080
+ for (const line12 of node.description) {
23081
+ if (line12.length <= charsPerLine) {
23082
+ totalRenderedLines += 1;
23083
+ } else {
23084
+ const words = line12.split(/\s+/);
23085
+ let current = "";
23086
+ let lineCount = 0;
23087
+ for (const word of words) {
23088
+ const fitted = word.length > charsPerLine ? word.slice(0, charsPerLine) : word;
23089
+ const test = current ? `${current} ${fitted}` : fitted;
23090
+ if (test.length <= charsPerLine) {
23091
+ current = test;
23092
+ } else {
23093
+ if (current) lineCount++;
23094
+ current = fitted;
23095
+ }
23096
+ }
23097
+ if (current) lineCount++;
23098
+ totalRenderedLines += lineCount;
23099
+ }
23100
+ }
23101
+ totalRenderedLines = Math.min(totalRenderedLines, MAX_DESC_LINES2);
23102
+ const descriptionHeight = totalRenderedLines * DESC_FONT_SIZE2 * DESC_LINE_HEIGHT2;
23103
+ const totalHeight = labelHeight + SEPARATOR_GAP5 + DESC_PADDING + descriptionHeight + DESC_PADDING;
23104
+ return { width: w, height: Math.max(NODE_HEIGHT, totalHeight) };
23105
+ }
23106
+ function getElk() {
23107
+ if (!elkInstance) elkInstance = new import_elk_bundled.default();
23108
+ return elkInstance;
23109
+ }
23110
+ function baseOptions() {
23111
+ return {
23112
+ "elk.algorithm": "layered",
23113
+ // INCLUDE_CHILDREN lets ELK route edges across container boundaries.
23114
+ "elk.hierarchyHandling": "INCLUDE_CHILDREN",
23115
+ "elk.edgeRouting": "ORTHOGONAL",
23116
+ "elk.layered.unnecessaryBendpoints": "true",
23117
+ // Let edges leave from top/bottom of nodes (not just the flow-direction
23118
+ // sides) when it reduces crossings.
23119
+ "elk.layered.allowNonFlowPortsToSwitchSides": "true"
23120
+ };
23121
+ }
23122
+ function bkBaseline() {
23123
+ return {
23124
+ ...baseOptions(),
23125
+ "elk.layered.nodePlacement.strategy": "BRANDES_KOEPF",
23126
+ "elk.layered.nodePlacement.bk.fixedAlignment": "BALANCED",
23127
+ "elk.layered.nodePlacement.bk.edgeStraightening": "IMPROVE_STRAIGHTNESS",
23128
+ "elk.layered.compaction.connectedComponents": "true",
23129
+ "elk.layered.spacing.nodeNodeBetweenLayers": "90",
23130
+ "elk.spacing.nodeNode": "55",
23131
+ "elk.spacing.edgeNode": "55",
23132
+ "elk.spacing.edgeEdge": "18"
23133
+ };
23134
+ }
23135
+ function getVariants() {
23136
+ const bk = bkBaseline();
23137
+ return [
23138
+ {
23139
+ name: "bk-baseline",
23140
+ options: {
23141
+ ...bk,
23142
+ "elk.layered.crossingMinimization.greedySwitch.type": "ONE_SIDED"
23143
+ }
23144
+ },
23145
+ {
23146
+ name: "bk-aggressive",
23147
+ options: {
23148
+ ...bk,
23149
+ "elk.layered.crossingMinimization.greedySwitch.type": "TWO_SIDED",
23150
+ "elk.layered.thoroughness": "50"
23151
+ }
23152
+ },
23153
+ {
23154
+ name: "bk-wide",
23155
+ options: {
23156
+ ...bk,
23157
+ "elk.layered.crossingMinimization.greedySwitch.type": "TWO_SIDED",
23158
+ "elk.layered.thoroughness": "50",
23159
+ "elk.spacing.nodeNode": "70",
23160
+ "elk.spacing.edgeNode": "75",
23161
+ "elk.spacing.edgeEdge": "22",
23162
+ "elk.layered.spacing.nodeNodeBetweenLayers": "120"
23163
+ }
23164
+ },
23165
+ {
23166
+ name: "longest-path",
23167
+ options: {
23168
+ ...bk,
23169
+ "elk.layered.layering.strategy": "LONGEST_PATH",
23170
+ "elk.layered.crossingMinimization.greedySwitch.type": "TWO_SIDED",
23171
+ "elk.layered.thoroughness": "50"
23172
+ }
23173
+ },
23174
+ {
23175
+ name: "bounded-width",
23176
+ options: {
23177
+ ...bk,
23178
+ "elk.layered.layering.strategy": "COFFMAN_GRAHAM",
23179
+ "elk.layered.layering.coffmanGraham.layerBound": "3",
23180
+ "elk.layered.crossingMinimization.greedySwitch.type": "TWO_SIDED",
23181
+ "elk.layered.thoroughness": "50"
23182
+ }
23183
+ }
23184
+ ];
23185
+ }
23186
+ function countCrossings(edges) {
23187
+ let count = 0;
23188
+ for (let i = 0; i < edges.length; i++) {
23189
+ const a = edges[i].points;
23190
+ if (a.length < 2) continue;
23191
+ for (let j = i + 1; j < edges.length; j++) {
23192
+ const b = edges[j].points;
23193
+ if (b.length < 2) continue;
23194
+ if (edges[i].source === edges[j].source) continue;
23195
+ if (edges[i].source === edges[j].target) continue;
23196
+ if (edges[i].target === edges[j].source) continue;
23197
+ if (edges[i].target === edges[j].target) continue;
23198
+ for (let ai = 0; ai < a.length - 1; ai++) {
23199
+ for (let bi = 0; bi < b.length - 1; bi++) {
23200
+ if (segmentsCross(a[ai], a[ai + 1], b[bi], b[bi + 1])) count++;
23201
+ }
23202
+ }
23203
+ }
23204
+ }
23205
+ return count;
23206
+ }
23207
+ function segmentsCross(p1, p2, p3, p4) {
23208
+ const d1x = p2.x - p1.x;
23209
+ const d1y = p2.y - p1.y;
23210
+ const d2x = p4.x - p3.x;
23211
+ const d2y = p4.y - p3.y;
23212
+ const denom = d1x * d2y - d1y * d2x;
23213
+ if (Math.abs(denom) < 1e-9) return false;
23214
+ const t = ((p3.x - p1.x) * d2y - (p3.y - p1.y) * d2x) / denom;
23215
+ const s = ((p3.x - p1.x) * d1y - (p3.y - p1.y) * d1x) / denom;
23216
+ const EPS = 1e-3;
23217
+ return t > EPS && t < 1 - EPS && s > EPS && s < 1 - EPS;
23218
+ }
23219
+ function countTotalBends(edges) {
23220
+ let bends = 0;
23221
+ for (const e of edges) bends += Math.max(0, e.points.length - 2);
23222
+ return bends;
23223
+ }
23224
+ function scoreLayout(layout) {
23225
+ return {
23226
+ crossings: countCrossings(layout.edges),
23227
+ bends: countTotalBends(layout.edges),
23228
+ area: layout.width * layout.height
23229
+ };
23230
+ }
23231
+ function cmpScore(a, b) {
23232
+ const aBucket = a.crossings <= CROSSINGS_FORGIVENESS ? 0 : a.crossings;
23233
+ const bBucket = b.crossings <= CROSSINGS_FORGIVENESS ? 0 : b.crossings;
23234
+ if (aBucket !== bBucket) return aBucket - bBucket;
23235
+ if (a.area !== b.area) return a.area - b.area;
23236
+ return a.bends - b.bends;
23237
+ }
23238
+ async function layoutBoxesAndLines(parsed, collapseInfo, layoutOptions) {
23239
+ const hideDescriptions = layoutOptions?.hideDescriptions ?? false;
23240
+ const direction = parsed.direction === "TB" ? "DOWN" : "RIGHT";
23241
+ const collapsedGroupLabels = /* @__PURE__ */ new Set();
23242
+ if (collapseInfo) {
23243
+ const missingGroups = /* @__PURE__ */ new Set();
23244
+ for (const og of collapseInfo.originalGroups) {
23245
+ if (!parsed.groups.some((g) => g.label === og.label)) {
23246
+ missingGroups.add(og.label);
23247
+ }
23248
+ }
23249
+ for (const label of missingGroups) {
23250
+ const og = collapseInfo.originalGroups.find((g) => g.label === label);
23251
+ const parentLabel = og?.parentGroup;
23252
+ if (!parentLabel || !missingGroups.has(parentLabel)) {
23253
+ collapsedGroupLabels.add(label);
23254
+ }
23255
+ }
23256
+ }
23257
+ const nodeSizes = /* @__PURE__ */ new Map();
23258
+ let maxDescHeight = 0;
23259
+ for (const node of parsed.nodes) {
23260
+ const size = hideDescriptions ? { width: NODE_WIDTH, height: NODE_HEIGHT } : computeNodeSize(node);
23261
+ nodeSizes.set(node.label, size);
23262
+ if (!hideDescriptions && node.description && node.description.length > 0) {
23263
+ maxDescHeight = Math.max(maxDescHeight, size.height);
23264
+ }
23265
+ }
23266
+ if (maxDescHeight > 0) {
23267
+ for (const node of parsed.nodes) {
23268
+ if (node.description && node.description.length > 0) {
23269
+ const size = nodeSizes.get(node.label);
23270
+ nodeSizes.set(node.label, { width: size.width, height: maxDescHeight });
23271
+ }
23272
+ }
23273
+ }
23274
+ const expandedGroupSet = new Set(parsed.groups.map((g) => g.label));
23275
+ const gid = (label) => `__group_${label}`;
23276
+ function buildGraph() {
23277
+ const nodeById = /* @__PURE__ */ new Map();
23278
+ const parentOf = /* @__PURE__ */ new Map();
23279
+ for (const node of parsed.nodes) {
23280
+ const size = nodeSizes.get(node.label);
23281
+ nodeById.set(node.label, {
23282
+ id: node.label,
23283
+ width: size.width,
23284
+ height: size.height,
23285
+ labels: [{ text: node.label }]
23286
+ });
23287
+ }
23288
+ for (const group of parsed.groups) {
23289
+ nodeById.set(gid(group.label), {
23290
+ id: gid(group.label),
23291
+ labels: [{ text: group.label }],
23292
+ layoutOptions: {
23293
+ "elk.padding": `[top=${CONTAINER_PAD_TOP2},left=${CONTAINER_PAD_X3},bottom=${CONTAINER_PAD_BOTTOM3},right=${CONTAINER_PAD_X3}]`,
23294
+ // Suggest square-ish containers — has limited effect with
23295
+ // INCLUDE_CHILDREN but doesn't hurt.
23296
+ "elk.aspectRatio": "1.4"
23297
+ },
23298
+ children: [],
23299
+ edges: []
23300
+ });
23301
+ }
23302
+ for (const label of collapsedGroupLabels) {
23303
+ nodeById.set(gid(label), {
23304
+ id: gid(label),
23305
+ width: NODE_WIDTH,
23306
+ height: NODE_HEIGHT,
23307
+ labels: [{ text: label }]
23308
+ });
23309
+ }
23310
+ for (const group of parsed.groups) {
23311
+ if (group.parentGroup && nodeById.has(gid(group.parentGroup))) {
23312
+ parentOf.set(gid(group.label), gid(group.parentGroup));
23313
+ }
23314
+ }
23315
+ if (collapseInfo) {
23316
+ for (const label of collapsedGroupLabels) {
23317
+ const og = collapseInfo.originalGroups.find((g) => g.label === label);
23318
+ if (og?.parentGroup && !collapsedGroupLabels.has(og.parentGroup) && nodeById.has(gid(og.parentGroup))) {
23319
+ parentOf.set(gid(label), gid(og.parentGroup));
23320
+ }
23321
+ }
23322
+ }
23323
+ for (const group of parsed.groups) {
23324
+ for (const child of group.children) {
23325
+ if (expandedGroupSet.has(child)) continue;
23326
+ if (nodeById.has(child)) {
23327
+ parentOf.set(child, gid(group.label));
23328
+ }
23329
+ }
23330
+ }
23331
+ const roots = [];
23332
+ for (const [id, node] of nodeById) {
23333
+ const parentId = parentOf.get(id);
23334
+ if (parentId) {
23335
+ const parent = nodeById.get(parentId);
23336
+ parent.children = parent.children ?? [];
23337
+ parent.children.push(node);
23338
+ } else {
23339
+ roots.push(node);
23340
+ }
23341
+ }
23342
+ const rootEdges = [];
23343
+ for (let i = 0; i < parsed.edges.length; i++) {
23344
+ const edge = parsed.edges[i];
23345
+ if (!nodeById.has(edge.source) || !nodeById.has(edge.target)) continue;
23346
+ rootEdges.push({
23347
+ id: `e${i}`,
23348
+ sources: [edge.source],
23349
+ targets: [edge.target]
23350
+ });
23351
+ }
23352
+ return { roots, rootEdges };
23353
+ }
23354
+ async function runVariant(variant) {
23355
+ const { roots, rootEdges } = buildGraph();
23356
+ const elkRoot = {
23357
+ id: "root",
23358
+ layoutOptions: {
23359
+ ...variant.options,
23360
+ "elk.direction": direction,
23361
+ "elk.padding": `[top=${MARGIN3},left=${MARGIN3},bottom=${MARGIN3},right=${MARGIN3}]`
23362
+ },
23363
+ children: roots,
23364
+ edges: rootEdges
23365
+ };
23366
+ const result = await getElk().layout(elkRoot);
23367
+ return extractLayout(result);
23368
+ }
23369
+ function extractLayout(result) {
23370
+ const layoutNodes = [];
23371
+ const layoutGroups = [];
23372
+ const allEdges = [];
23373
+ const containerAbs = /* @__PURE__ */ new Map();
23374
+ function walk(n, offsetX, offsetY, isRoot) {
23375
+ const nx = (n.x ?? 0) + offsetX;
23376
+ const ny = (n.y ?? 0) + offsetY;
23377
+ const nw = n.width ?? 0;
23378
+ const nh = n.height ?? 0;
23379
+ if (isRoot) {
23380
+ containerAbs.set("root", { x: nx, y: ny });
23381
+ } else {
23382
+ const isGroup = n.id.startsWith("__group_");
23383
+ if (isGroup) {
23384
+ const label = n.id.slice("__group_".length);
23385
+ const collapsed = collapsedGroupLabels.has(label);
23386
+ const og = collapseInfo?.originalGroups.find(
23387
+ (g) => g.label === label
23388
+ );
23389
+ const pg = parsed.groups.find((g) => g.label === label);
23390
+ layoutGroups.push({
23391
+ label,
23392
+ lineNumber: pg?.lineNumber ?? og?.lineNumber ?? 0,
23393
+ x: nx + nw / 2,
23394
+ y: ny + nh / 2,
23395
+ width: nw,
23396
+ height: nh,
23397
+ collapsed,
23398
+ childCount: collapsed ? collapseInfo?.collapsedChildCounts.get(label) ?? 0 : void 0
23399
+ });
23400
+ if (!collapsed) containerAbs.set(n.id, { x: nx, y: ny });
23401
+ } else {
23402
+ layoutNodes.push({
23403
+ label: n.id,
23404
+ x: nx + nw / 2,
23405
+ y: ny + nh / 2,
23406
+ width: nw,
23407
+ height: nh
23408
+ });
23409
+ }
23410
+ }
23411
+ if (n.edges) for (const e of n.edges) allEdges.push(e);
23412
+ if (n.children) for (const c of n.children) walk(c, nx, ny, false);
23413
+ }
23414
+ walk(result, 0, 0, true);
23415
+ const edgeYOffsets = new Array(parsed.edges.length).fill(0);
23416
+ const edgeParallelCounts = new Array(parsed.edges.length).fill(1);
23417
+ const parallelGroups = /* @__PURE__ */ new Map();
23418
+ for (let i = 0; i < parsed.edges.length; i++) {
23419
+ const edge = parsed.edges[i];
23420
+ const [a, b] = edge.source < edge.target ? [edge.source, edge.target] : [edge.target, edge.source];
23421
+ const key = `${a}\0${b}`;
23422
+ if (!parallelGroups.has(key)) parallelGroups.set(key, []);
23423
+ parallelGroups.get(key).push(i);
23424
+ }
23425
+ for (const group of parallelGroups.values()) {
23426
+ const capped = group.slice(0, MAX_PARALLEL_EDGES);
23427
+ for (const idx of group.slice(MAX_PARALLEL_EDGES)) {
23428
+ edgeParallelCounts[idx] = 0;
23429
+ }
23430
+ if (capped.length < 2) continue;
23431
+ for (let j = 0; j < capped.length; j++) {
23432
+ edgeYOffsets[capped[j]] = (j - (capped.length - 1) / 2) * PARALLEL_SPACING;
23433
+ edgeParallelCounts[capped[j]] = capped.length;
23434
+ }
23435
+ }
23436
+ const edgeById = /* @__PURE__ */ new Map();
23437
+ for (const e of allEdges) edgeById.set(e.id, e);
23438
+ const layoutEdges = [];
23439
+ for (let i = 0; i < parsed.edges.length; i++) {
23440
+ const edge = parsed.edges[i];
23441
+ if (edgeParallelCounts[i] === 0) continue;
23442
+ const elkEdge = edgeById.get(`e${i}`);
23443
+ if (!elkEdge || !elkEdge.sections || elkEdge.sections.length === 0)
23444
+ continue;
23445
+ const container = elkEdge.container ?? "root";
23446
+ const off = containerAbs.get(container) ?? { x: 0, y: 0 };
23447
+ const s = elkEdge.sections[0];
23448
+ const points = [
23449
+ { x: s.startPoint.x + off.x, y: s.startPoint.y + off.y },
23450
+ ...(s.bendPoints ?? []).map((p) => ({
23451
+ x: p.x + off.x,
23452
+ y: p.y + off.y
23453
+ })),
23454
+ { x: s.endPoint.x + off.x, y: s.endPoint.y + off.y }
23455
+ ];
23456
+ let labelX;
23457
+ let labelY;
23458
+ if (edge.label && points.length >= 2) {
23459
+ const mid = Math.floor(points.length / 2);
23460
+ labelX = points[mid].x;
23461
+ labelY = points[mid].y - 10;
23462
+ }
23463
+ layoutEdges.push({
23464
+ source: edge.source,
23465
+ target: edge.target,
23466
+ label: edge.label,
23467
+ bidirectional: edge.bidirectional,
23468
+ lineNumber: edge.lineNumber,
23469
+ points,
23470
+ labelX,
23471
+ labelY,
23472
+ yOffset: edgeYOffsets[i],
23473
+ parallelCount: edgeParallelCounts[i],
23474
+ metadata: edge.metadata,
23475
+ deferred: true
23476
+ });
23477
+ }
23478
+ let maxX = 0;
23479
+ let maxY = 0;
23480
+ for (const node of layoutNodes) {
23481
+ maxX = Math.max(maxX, node.x + node.width / 2);
23482
+ maxY = Math.max(maxY, node.y + node.height / 2);
23483
+ }
23484
+ for (const group of layoutGroups) {
23485
+ maxX = Math.max(maxX, group.x + group.width / 2);
23486
+ maxY = Math.max(maxY, group.y + group.height / 2);
23487
+ }
23488
+ return {
23489
+ nodes: layoutNodes,
23490
+ edges: layoutEdges,
23491
+ groups: layoutGroups,
23492
+ width: maxX + MARGIN3,
23493
+ height: maxY + MARGIN3
23494
+ };
23495
+ }
23496
+ const N = parsed.nodes.length + parsed.groups.length;
23497
+ const E = parsed.edges.length;
23498
+ const trivial = N < 8 && E < 10;
23499
+ const variants = trivial ? [getVariants()[1]] : getVariants();
23500
+ const results = await Promise.all(variants.map((v) => runVariant(v)));
23501
+ let best = results[0];
23502
+ let bestScore = scoreLayout(best);
23503
+ for (let i = 1; i < results.length; i++) {
23504
+ const s = scoreLayout(results[i]);
23505
+ if (cmpScore(s, bestScore) < 0) {
23506
+ best = results[i];
23507
+ bestScore = s;
23508
+ }
23509
+ }
23510
+ return best;
23511
+ }
23512
+ var import_elk_bundled, MARGIN3, CONTAINER_PAD_X3, CONTAINER_PAD_TOP2, CONTAINER_PAD_BOTTOM3, MAX_PARALLEL_EDGES, PARALLEL_SPACING, PHI, NODE_HEIGHT, NODE_WIDTH, DESC_NODE_WIDTH, DESC_FONT_SIZE2, DESC_LINE_HEIGHT2, DESC_PADDING, SEPARATOR_GAP5, MAX_DESC_LINES2, MAX_LABEL_LINES, LABEL_LINE_HEIGHT, LABEL_PAD, elkInstance, CROSSINGS_FORGIVENESS;
23513
+ var init_layout5 = __esm({
23514
+ "src/boxes-and-lines/layout.ts"() {
23515
+ "use strict";
23516
+ import_elk_bundled = __toESM(require("elkjs/lib/elk.bundled.js"), 1);
23517
+ MARGIN3 = 40;
23518
+ CONTAINER_PAD_X3 = 30;
23519
+ CONTAINER_PAD_TOP2 = 40;
23520
+ CONTAINER_PAD_BOTTOM3 = 24;
23521
+ MAX_PARALLEL_EDGES = 5;
23522
+ PARALLEL_SPACING = 22;
23523
+ PHI = 1.618;
23524
+ NODE_HEIGHT = 60;
23525
+ NODE_WIDTH = Math.round(NODE_HEIGHT * PHI);
23526
+ DESC_NODE_WIDTH = 140;
23527
+ DESC_FONT_SIZE2 = 10;
23528
+ DESC_LINE_HEIGHT2 = 1.4;
23529
+ DESC_PADDING = 8;
23530
+ SEPARATOR_GAP5 = 4;
23531
+ MAX_DESC_LINES2 = 6;
23532
+ MAX_LABEL_LINES = 3;
23533
+ LABEL_LINE_HEIGHT = 1.3;
23534
+ LABEL_PAD = 12;
23535
+ elkInstance = null;
23536
+ CROSSINGS_FORGIVENESS = 1;
23537
+ }
23538
+ });
23539
+
23523
23540
  // src/mindmap/text-wrap.ts
23524
23541
  function tokenize(text) {
23525
23542
  const tokens = [];
@@ -23658,7 +23675,7 @@ var layout_exports6 = {};
23658
23675
  __export(layout_exports6, {
23659
23676
  layoutMindmap: () => layoutMindmap
23660
23677
  });
23661
- function layoutMindmap(parsed, palette, options) {
23678
+ function layoutMindmap(parsed, _palette, options) {
23662
23679
  const roots = parsed.roots;
23663
23680
  if (roots.length === 0) {
23664
23681
  return { nodes: [], edges: [], width: 0, height: 0 };
@@ -24554,7 +24571,7 @@ function layoutElement(el, x, y, width) {
24554
24571
  node.height = getElementHeight(el);
24555
24572
  return node;
24556
24573
  }
24557
- const isInlineRow = el.metadata._inlineRow === "true" || el.metadata._labelField === "true";
24574
+ const isInlineRow = el.metadata["_inlineRow"] === "true" || el.metadata["_labelField"] === "true";
24558
24575
  const padTop = isInlineRow ? 0 : GROUP_PADDING_TOP;
24559
24576
  const padBottom = isInlineRow ? 0 : GROUP_PADDING_BOTTOM;
24560
24577
  const padX = isInlineRow ? 0 : GROUP_PADDING_X;
@@ -24603,7 +24620,7 @@ function allocateEqualWidths(children, totalWidth) {
24603
24620
  }
24604
24621
  function getElementHeight(el) {
24605
24622
  if (el.type === "heading") {
24606
- return el.headingLevel === 2 ? ELEMENT_HEIGHTS.subheading ?? 36 : ELEMENT_HEIGHTS.heading ?? 48;
24623
+ return el.headingLevel === 2 ? ELEMENT_HEIGHTS["subheading"] ?? 36 : ELEMENT_HEIGHTS["heading"] ?? 48;
24607
24624
  }
24608
24625
  if (el.type === "textInput" && el.fieldVariant === "textarea") {
24609
24626
  return 80;
@@ -24617,16 +24634,16 @@ function getElementHeight(el) {
24617
24634
  if (el.type === "image") {
24618
24635
  if (el.imageHint === "round") return 80;
24619
24636
  if (el.imageHint === "wide") return 80;
24620
- return ELEMENT_HEIGHTS.image ?? 120;
24637
+ return ELEMENT_HEIGHTS["image"] ?? 120;
24621
24638
  }
24622
- if (el.metadata._labelField === "true") {
24639
+ if (el.metadata["_labelField"] === "true") {
24623
24640
  return 36;
24624
24641
  }
24625
24642
  return ELEMENT_HEIGHTS[el.type] ?? 24;
24626
24643
  }
24627
24644
  function getSpacingAfter(el) {
24628
24645
  if (el.type === "heading" && el.headingLevel === 2) {
24629
- return SPACING_AFTER.subheading ?? 12;
24646
+ return SPACING_AFTER["subheading"] ?? 12;
24630
24647
  }
24631
24648
  return SPACING_AFTER[el.type] ?? 8;
24632
24649
  }
@@ -24634,7 +24651,7 @@ function computeFieldAlignX(children) {
24634
24651
  let maxLabelWidth = 0;
24635
24652
  let labelFieldCount = 0;
24636
24653
  for (const child of children) {
24637
- if (child.metadata._labelField === "true" && child.children.length >= 2) {
24654
+ if (child.metadata["_labelField"] === "true" && child.children.length >= 2) {
24638
24655
  const labelEl = child.children[0];
24639
24656
  const labelWidth = labelEl.label.length * CHAR_WIDTH5;
24640
24657
  maxLabelWidth = Math.max(maxLabelWidth, labelWidth);
@@ -24845,7 +24862,7 @@ function renderNode(parent, node, ctx, depth) {
24845
24862
  function renderGroup(g, node, ctx, depth) {
24846
24863
  const { palette, isTransparent } = ctx;
24847
24864
  const el = node.element;
24848
- if (el.metadata._inlineRow === "true" || el.metadata._labelField === "true") {
24865
+ if (el.metadata["_inlineRow"] === "true" || el.metadata["_labelField"] === "true") {
24849
24866
  for (const child of node.children) {
24850
24867
  renderNode(g, child, ctx, depth);
24851
24868
  }
@@ -24973,7 +24990,7 @@ function renderDivider(g, node, ctx) {
24973
24990
  function renderText(g, node, ctx) {
24974
24991
  const { palette } = ctx;
24975
24992
  const el = node.element;
24976
- if (el.metadata._labelField === "true" && el.children.length >= 2) {
24993
+ if (el.metadata["_labelField"] === "true" && el.children.length >= 2) {
24977
24994
  for (const child of node.children) {
24978
24995
  renderNode(g, child, ctx, 0);
24979
24996
  }
@@ -25708,7 +25725,7 @@ function layoutC4Context(parsed, activeTagGroup) {
25708
25725
  }
25709
25726
  const contextRels = rollUpContextRelationships(parsed);
25710
25727
  const spacing = computeAdaptiveSpacing(contextRels);
25711
- const g = new import_dagre5.default.graphlib.Graph();
25728
+ const g = new import_dagre4.default.graphlib.Graph();
25712
25729
  g.setGraph({
25713
25730
  rankdir: "TB",
25714
25731
  nodesep: spacing.nodesep,
@@ -25729,7 +25746,7 @@ function layoutC4Context(parsed, activeTagGroup) {
25729
25746
  g.setEdge(rel.sourceName, rel.targetName, { label: rel.label ?? "" });
25730
25747
  }
25731
25748
  }
25732
- import_dagre5.default.layout(g);
25749
+ import_dagre4.default.layout(g);
25733
25750
  reduceCrossings(
25734
25751
  g,
25735
25752
  validRels.map((r) => ({ source: r.sourceName, target: r.targetName }))
@@ -25901,7 +25918,7 @@ function layoutC4Containers(parsed, systemName, activeTagGroup) {
25901
25918
  }
25902
25919
  }
25903
25920
  const hasGroups = elementToGroup.size > 0;
25904
- const g = hasGroups ? new import_dagre5.default.graphlib.Graph({ compound: true }) : new import_dagre5.default.graphlib.Graph();
25921
+ const g = hasGroups ? new import_dagre4.default.graphlib.Graph({ compound: true }) : new import_dagre4.default.graphlib.Graph();
25905
25922
  g.setDefaultEdgeLabel(() => ({}));
25906
25923
  if (hasGroups) {
25907
25924
  const seenGroups = /* @__PURE__ */ new Set();
@@ -25979,7 +25996,7 @@ function layoutC4Containers(parsed, systemName, activeTagGroup) {
25979
25996
  g.setEdge(rel.sourceName, rel.targetName, { label: rel.label ?? "" });
25980
25997
  }
25981
25998
  }
25982
- import_dagre5.default.layout(g);
25999
+ import_dagre4.default.layout(g);
25983
26000
  const nodeGroupMap = hasGroups ? new Map([...elementToGroup.entries()].map(([k, v]) => [k, v.name])) : void 0;
25984
26001
  reduceCrossings(
25985
26002
  g,
@@ -26305,7 +26322,7 @@ function layoutC4Components(parsed, systemName, containerName, activeTagGroup) {
26305
26322
  }
26306
26323
  }
26307
26324
  const hasGroups = elementToGroup.size > 0;
26308
- const g = hasGroups ? new import_dagre5.default.graphlib.Graph({ compound: true }) : new import_dagre5.default.graphlib.Graph();
26325
+ const g = hasGroups ? new import_dagre4.default.graphlib.Graph({ compound: true }) : new import_dagre4.default.graphlib.Graph();
26309
26326
  g.setDefaultEdgeLabel(() => ({}));
26310
26327
  if (hasGroups) {
26311
26328
  const seenGroups = /* @__PURE__ */ new Set();
@@ -26389,7 +26406,7 @@ function layoutC4Components(parsed, systemName, containerName, activeTagGroup) {
26389
26406
  g.setEdge(rel.sourceName, rel.targetName, { label: rel.label ?? "" });
26390
26407
  }
26391
26408
  }
26392
- import_dagre5.default.layout(g);
26409
+ import_dagre4.default.layout(g);
26393
26410
  const nodeGroupMap = hasGroups ? new Map([...elementToGroup.entries()].map(([k, v]) => [k, v.name])) : void 0;
26394
26411
  reduceCrossings(
26395
26412
  g,
@@ -26678,7 +26695,7 @@ function layoutC4Deployment(parsed, activeTagGroup) {
26678
26695
  for (const r of refEntries) {
26679
26696
  nameToElement.set(r.element.name, r.element);
26680
26697
  }
26681
- const g = new import_dagre5.default.graphlib.Graph({ compound: true });
26698
+ const g = new import_dagre4.default.graphlib.Graph({ compound: true });
26682
26699
  g.setDefaultEdgeLabel(() => ({}));
26683
26700
  for (const [infraId] of infraIds) {
26684
26701
  g.setNode(infraId, {});
@@ -26722,7 +26739,7 @@ function layoutC4Deployment(parsed, activeTagGroup) {
26722
26739
  g.setEdge(rel.sourceName, rel.targetName, { label: rel.label ?? "" });
26723
26740
  }
26724
26741
  }
26725
- import_dagre5.default.layout(g);
26742
+ import_dagre4.default.layout(g);
26726
26743
  const nodeInfraMap = /* @__PURE__ */ new Map();
26727
26744
  for (const r of refEntries) nodeInfraMap.set(r.element.name, r.infraId);
26728
26745
  reduceCrossings(
@@ -26900,11 +26917,11 @@ function layoutC4Deployment(parsed, activeTagGroup) {
26900
26917
  height: totalHeight
26901
26918
  };
26902
26919
  }
26903
- var import_dagre5, gNode, gEdge, CHAR_WIDTH6, MIN_NODE_WIDTH, MAX_NODE_WIDTH, TYPE_LABEL_HEIGHT, DIVIDER_GAP, NAME_HEIGHT, DESC_LINE_HEIGHT5, DESC_CHAR_WIDTH, CARD_V_PAD3, CARD_H_PAD3, META_LINE_HEIGHT5, META_CHAR_WIDTH, MARGIN5, BOUNDARY_PAD, GROUP_BOUNDARY_PAD, LEGEND_HEIGHT4, LEGEND_PILL_PAD4, LEGEND_DOT_R4, LEGEND_ENTRY_DOT_GAP4, LEGEND_ENTRY_TRAIL4, LEGEND_CAPSULE_PAD4, EDGE_NODE_COLLISION_WEIGHT, META_EXCLUDE_KEYS;
26920
+ var import_dagre4, gNode, gEdge, CHAR_WIDTH6, MIN_NODE_WIDTH, MAX_NODE_WIDTH, TYPE_LABEL_HEIGHT, DIVIDER_GAP, NAME_HEIGHT, DESC_LINE_HEIGHT5, DESC_CHAR_WIDTH, CARD_V_PAD3, CARD_H_PAD3, META_LINE_HEIGHT5, META_CHAR_WIDTH, MARGIN5, BOUNDARY_PAD, GROUP_BOUNDARY_PAD, LEGEND_HEIGHT4, LEGEND_PILL_PAD4, LEGEND_DOT_R4, LEGEND_ENTRY_DOT_GAP4, LEGEND_ENTRY_TRAIL4, LEGEND_CAPSULE_PAD4, EDGE_NODE_COLLISION_WEIGHT, META_EXCLUDE_KEYS;
26904
26921
  var init_layout8 = __esm({
26905
26922
  "src/c4/layout.ts"() {
26906
26923
  "use strict";
26907
- import_dagre5 = __toESM(require("@dagrejs/dagre"), 1);
26924
+ import_dagre4 = __toESM(require("@dagrejs/dagre"), 1);
26908
26925
  init_legend_constants();
26909
26926
  gNode = (g, name) => g.node(name);
26910
26927
  gEdge = (g, v, w) => g.edge(v, w);
@@ -27987,7 +28004,7 @@ function layoutGraph(graph, options) {
27987
28004
  if (allNodes.length === 0) {
27988
28005
  return { nodes: [], edges: [], groups: [], width: 0, height: 0 };
27989
28006
  }
27990
- const g = new import_dagre6.default.graphlib.Graph({ compound: true });
28007
+ const g = new import_dagre5.default.graphlib.Graph({ compound: true });
27991
28008
  g.setGraph({
27992
28009
  rankdir: graph.direction,
27993
28010
  nodesep: 50,
@@ -28023,7 +28040,7 @@ function layoutGraph(graph, options) {
28023
28040
  label: edge.label ?? ""
28024
28041
  });
28025
28042
  }
28026
- import_dagre6.default.layout(g);
28043
+ import_dagre5.default.layout(g);
28027
28044
  const collapsedGroupIds = collapsedChildCounts ? new Set(collapsedChildCounts.keys()) : /* @__PURE__ */ new Set();
28028
28045
  const layoutNodes = allNodes.map((node) => {
28029
28046
  const pos = g.node(node.id);
@@ -28140,11 +28157,11 @@ function layoutGraph(graph, options) {
28140
28157
  height: totalHeight
28141
28158
  };
28142
28159
  }
28143
- var import_dagre6, GROUP_PADDING;
28160
+ var import_dagre5, GROUP_PADDING;
28144
28161
  var init_layout9 = __esm({
28145
28162
  "src/graph/layout.ts"() {
28146
28163
  "use strict";
28147
- import_dagre6 = __toESM(require("@dagrejs/dagre"), 1);
28164
+ import_dagre5 = __toESM(require("@dagrejs/dagre"), 1);
28148
28165
  GROUP_PADDING = 20;
28149
28166
  }
28150
28167
  });
@@ -28456,7 +28473,7 @@ function renderFlowchart(container, graph, layout, palette, isDark, onClickItem,
28456
28473
  endTerminalIds.add(node.id);
28457
28474
  }
28458
28475
  }
28459
- const colorOff = graph.options?.color === "off";
28476
+ const colorOff = graph.options?.["color"] === "off";
28460
28477
  const solid = graph.options?.["solid-fill"] === "on";
28461
28478
  for (const node of layout.nodes) {
28462
28479
  const nodeG = contentG.append("g").attr("transform", `translate(${node.x}, ${node.y})`).attr("class", "fc-node").attr("data-line-number", String(node.lineNumber)).attr("data-node-id", node.id);
@@ -29689,7 +29706,7 @@ function layoutInfra(computed, expandedNodeIds, collapsedNodes) {
29689
29706
  };
29690
29707
  }
29691
29708
  const isLR = computed.direction !== "TB";
29692
- const g = new import_dagre7.default.graphlib.Graph();
29709
+ const g = new import_dagre6.default.graphlib.Graph();
29693
29710
  g.setGraph({
29694
29711
  rankdir: computed.direction === "TB" ? "TB" : "LR",
29695
29712
  nodesep: isLR ? 70 : 60,
@@ -29740,7 +29757,7 @@ function layoutInfra(computed, expandedNodeIds, collapsedNodes) {
29740
29757
  g.setEdge(edge.sourceId, edge.targetId, { label: edge.label });
29741
29758
  }
29742
29759
  }
29743
- import_dagre7.default.layout(g);
29760
+ import_dagre6.default.layout(g);
29744
29761
  const layoutNodes = computed.nodes.map((node) => {
29745
29762
  const pos = g.node(node.id);
29746
29763
  return {
@@ -29902,11 +29919,11 @@ function layoutInfra(computed, expandedNodeIds, collapsedNodes) {
29902
29919
  height: totalHeight
29903
29920
  };
29904
29921
  }
29905
- var import_dagre7, MIN_NODE_WIDTH2, NODE_HEADER_HEIGHT, META_LINE_HEIGHT7, NODE_SEPARATOR_GAP, NODE_PAD_BOTTOM, ROLE_DOT_ROW, COLLAPSE_BAR_HEIGHT5, CHAR_WIDTH7, META_CHAR_WIDTH3, PADDING_X3, GROUP_PADDING2, GROUP_HEADER_HEIGHT, EDGE_MARGIN, DISPLAY_KEYS, DISPLAY_NAMES, GROUP_GAP;
29922
+ var import_dagre6, MIN_NODE_WIDTH2, NODE_HEADER_HEIGHT, META_LINE_HEIGHT7, NODE_SEPARATOR_GAP, NODE_PAD_BOTTOM, ROLE_DOT_ROW, COLLAPSE_BAR_HEIGHT5, CHAR_WIDTH7, META_CHAR_WIDTH3, PADDING_X3, GROUP_PADDING2, GROUP_HEADER_HEIGHT, EDGE_MARGIN, DISPLAY_KEYS, DISPLAY_NAMES, GROUP_GAP;
29906
29923
  var init_layout10 = __esm({
29907
29924
  "src/infra/layout.ts"() {
29908
29925
  "use strict";
29909
- import_dagre7 = __toESM(require("@dagrejs/dagre"), 1);
29926
+ import_dagre6 = __toESM(require("@dagrejs/dagre"), 1);
29910
29927
  MIN_NODE_WIDTH2 = 140;
29911
29928
  NODE_HEADER_HEIGHT = 28;
29912
29929
  META_LINE_HEIGHT7 = 14;
@@ -30648,7 +30665,7 @@ function renderGroups(svg, groups, palette, _isDark) {
30648
30665
  }
30649
30666
  }
30650
30667
  }
30651
- function renderEdgePaths(svg, edges, nodes, groups, palette, isDark, animate, direction, speedMultiplier = 1) {
30668
+ function renderEdgePaths(svg, edges, nodes, groups, palette, _isDark, animate, direction, speedMultiplier = 1) {
30652
30669
  const nodeMap = new Map(nodes.map((n) => [n.id, n]));
30653
30670
  const maxRps = Math.max(...edges.map((e) => e.computedRps), 1);
30654
30671
  const { srcPts, tgtPts } = computePortPts(edges, nodeMap, direction);
@@ -30689,7 +30706,7 @@ function renderEdgePaths(svg, edges, nodes, groups, palette, isDark, animate, di
30689
30706
  }
30690
30707
  }
30691
30708
  }
30692
- function renderEdgeLabels(svg, edges, nodes, groups, palette, isDark, animate, direction) {
30709
+ function renderEdgeLabels(svg, edges, nodes, groups, palette, _isDark, animate, direction) {
30693
30710
  const nodeMap = new Map(nodes.map((n) => [n.id, n]));
30694
30711
  const { srcPts, tgtPts } = computePortPts(edges, nodeMap, direction);
30695
30712
  for (const edge of edges) {
@@ -31430,7 +31447,7 @@ function sampleBetaPert(o, m, p, rng) {
31430
31447
  const beta = 1 + 4 * (p - m) / range;
31431
31448
  return o + sampleBeta(alpha, beta, rng) * range;
31432
31449
  }
31433
- function simulate(resolved, expanded, predecessors, successors, topo, terminals, poisoned, opts) {
31450
+ function simulate(resolved, expanded, _predecessors, _successors, topo, terminals, poisoned, opts) {
31434
31451
  const rng = mulberry32(opts.seed);
31435
31452
  const expById = /* @__PURE__ */ new Map();
31436
31453
  for (const e of expanded) expById.set(e.id, e);
@@ -32550,7 +32567,7 @@ function relayoutPert(resolved, overrides, collapsedGroupIds = /* @__PURE__ */ n
32550
32567
  }
32551
32568
  }
32552
32569
  const dagreId = (id) => memberToGroup.get(id) ?? id;
32553
- const g = new import_dagre8.default.graphlib.Graph();
32570
+ const g = new import_dagre7.default.graphlib.Graph();
32554
32571
  g.setGraph({
32555
32572
  rankdir: resolved.options.direction,
32556
32573
  nodesep: 50,
@@ -32589,7 +32606,7 @@ function relayoutPert(resolved, overrides, collapsedGroupIds = /* @__PURE__ */ n
32589
32606
  seenEdges.add(k);
32590
32607
  g.setEdge(src, tgt, {});
32591
32608
  }
32592
- import_dagre8.default.layout(g);
32609
+ import_dagre7.default.layout(g);
32593
32610
  const swimApplied = applySwimLanes(
32594
32611
  g,
32595
32612
  resolved,
@@ -32709,7 +32726,7 @@ function relayoutPert(resolved, overrides, collapsedGroupIds = /* @__PURE__ */ n
32709
32726
  height: totalH + DIAGRAM_PADDING10
32710
32727
  };
32711
32728
  }
32712
- function applySwimLanes(g, resolved, memberToGroup, collapsedGroupIds) {
32729
+ function applySwimLanes(g, resolved, _memberToGroup, collapsedGroupIds) {
32713
32730
  const expanded = resolved.groups.filter(
32714
32731
  (rg) => !collapsedGroupIds.has(rg.group.id)
32715
32732
  );
@@ -32935,7 +32952,7 @@ function reduceCrossings2(g, direction) {
32935
32952
  buckets.get(key).push(id);
32936
32953
  }
32937
32954
  const edges = g.edges().map((e) => ({ v: e.v, w: e.w }));
32938
- const countCrossings = () => {
32955
+ const countCrossings2 = () => {
32939
32956
  let total = 0;
32940
32957
  for (let i = 0; i < edges.length; i++) {
32941
32958
  const a = edges[i];
@@ -32948,13 +32965,13 @@ function reduceCrossings2(g, direction) {
32948
32965
  const b1 = g.node(b.v);
32949
32966
  const b2 = g.node(b.w);
32950
32967
  if (!b1 || !b2) continue;
32951
- if (segmentsCross(a1, a2, b1, b2)) total++;
32968
+ if (segmentsCross2(a1, a2, b1, b2)) total++;
32952
32969
  }
32953
32970
  }
32954
32971
  return total;
32955
32972
  };
32956
32973
  const MAX_ITER = 8;
32957
- let baseline = countCrossings();
32974
+ let baseline = countCrossings2();
32958
32975
  if (baseline === 0) return;
32959
32976
  for (let iter = 0; iter < MAX_ITER; iter++) {
32960
32977
  let improved = false;
@@ -32972,7 +32989,7 @@ function reduceCrossings2(g, direction) {
32972
32989
  const bv = bn[slotAxis];
32973
32990
  an[slotAxis] = bv;
32974
32991
  bn[slotAxis] = av;
32975
- const after = countCrossings();
32992
+ const after = countCrossings2();
32976
32993
  if (after < baseline) {
32977
32994
  baseline = after;
32978
32995
  improved = true;
@@ -32993,7 +33010,7 @@ function reduceCrossings2(g, direction) {
32993
33010
  data.points = smoothEdge(src, tgt, direction);
32994
33011
  }
32995
33012
  }
32996
- function segmentsCross(a1, a2, b1, b2) {
33013
+ function segmentsCross2(a1, a2, b1, b2) {
32997
33014
  const ccw = (p, q, r) => (q.x - p.x) * (r.y - p.y) - (q.y - p.y) * (r.x - p.x);
32998
33015
  const d1 = ccw(b1, b2, a1);
32999
33016
  const d2 = ccw(b1, b2, a2);
@@ -33001,11 +33018,11 @@ function segmentsCross(a1, a2, b1, b2) {
33001
33018
  const d4 = ccw(a1, a2, b2);
33002
33019
  return (d1 > 0 && d2 < 0 || d1 < 0 && d2 > 0) && (d32 > 0 && d4 < 0 || d32 < 0 && d4 > 0);
33003
33020
  }
33004
- var import_dagre8, DEFAULT_NODE_HEIGHT, MILESTONE_NODE_HEIGHT, COLLAPSED_GROUP_HEIGHT, DIAGRAM_PADDING10, GROUP_PADDING3, GROUP_TOP_PADDING, SWIMLANE_SLOT_SEP, SWIMLANE_GAP, NODE_CELL_FONT_SIZE, NODE_NAME_FONT_SIZE, CELL_CHAR_WIDTH_RATIO, CELL_PAD_X, NAME_PAD_X, NAME_PIN_WIDTH, MIN_CELL_WIDTH, MIN_NODE_WIDTH3, MAX_NODE_WIDTH2, MIN_MILESTONE_WIDTH, MAX_MILESTONE_WIDTH;
33021
+ var import_dagre7, DEFAULT_NODE_HEIGHT, MILESTONE_NODE_HEIGHT, COLLAPSED_GROUP_HEIGHT, DIAGRAM_PADDING10, GROUP_PADDING3, GROUP_TOP_PADDING, SWIMLANE_SLOT_SEP, SWIMLANE_GAP, NODE_CELL_FONT_SIZE, NODE_NAME_FONT_SIZE, CELL_CHAR_WIDTH_RATIO, CELL_PAD_X, NAME_PAD_X, NAME_PIN_WIDTH, MIN_CELL_WIDTH, MIN_NODE_WIDTH3, MAX_NODE_WIDTH2, MIN_MILESTONE_WIDTH, MAX_MILESTONE_WIDTH;
33005
33022
  var init_layout11 = __esm({
33006
33023
  "src/pert/layout.ts"() {
33007
33024
  "use strict";
33008
- import_dagre8 = __toESM(require("@dagrejs/dagre"), 1);
33025
+ import_dagre7 = __toESM(require("@dagrejs/dagre"), 1);
33009
33026
  init_internal();
33010
33027
  DEFAULT_NODE_HEIGHT = 90;
33011
33028
  MILESTONE_NODE_HEIGHT = DEFAULT_NODE_HEIGHT;
@@ -35002,12 +35019,6 @@ function calculateSchedule(parsed) {
35002
35019
  const warn = (line12, message) => {
35003
35020
  diagnostics.push(makeDgmoError(line12, message, "warning"));
35004
35021
  };
35005
- const _fail = (line12, message) => {
35006
- const diag = makeDgmoError(line12, message);
35007
- diagnostics.push(diag);
35008
- result.error = formatDgmoError(diag);
35009
- return result;
35010
- };
35011
35022
  const holidaySet = buildHolidaySet(parsed.holidays);
35012
35023
  let projectStart;
35013
35024
  if (parsed.options.start) {
@@ -35032,7 +35043,6 @@ function calculateSchedule(parsed) {
35032
35043
  }
35033
35044
  buildImplicitDeps(parsed.nodes, taskMap);
35034
35045
  for (const task of allTasks2) {
35035
- const _node = taskMap.get(task.id);
35036
35046
  for (const dep of task.dependencies) {
35037
35047
  const resolved = resolveTaskName(dep.targetName, allTasks2);
35038
35048
  if (isResolverError(resolved)) {
@@ -36571,7 +36581,7 @@ function buildControlsToggles(hasCriticalPath, criticalPathActive, hasDependenci
36571
36581
  }
36572
36582
  return toggles;
36573
36583
  }
36574
- function renderTagLegend(svg, chartG, tagGroups, activeGroupName, chartLeftMargin, chartInnerWidth, legendY, palette, isDark, hasCriticalPath, criticalPathActive, optionLineNumbers, onToggle, onToggleControlsExpand, currentSwimlaneGroup, onSwimlaneChange, legendViewMode, resolvedTasks, controlsExpanded = false, hasDependencies = false, dependenciesActive = false, onControlsToggle) {
36584
+ function renderTagLegend(svg, chartG, tagGroups, activeGroupName, chartLeftMargin, chartInnerWidth, legendY, palette, isDark, hasCriticalPath, criticalPathActive, _optionLineNumbers, onToggle, onToggleControlsExpand, currentSwimlaneGroup, onSwimlaneChange, legendViewMode, resolvedTasks, controlsExpanded = false, hasDependencies = false, dependenciesActive = false, onControlsToggle) {
36575
36585
  let visibleGroups;
36576
36586
  if (activeGroupName) {
36577
36587
  const activeGroup = tagGroups.filter(
@@ -37534,7 +37544,7 @@ function resolveTaskColor(rt, activeTagGroup, resolved, seriesColors2, palette)
37534
37544
  }
37535
37545
  return palette.accent || seriesColors2[0] || "#4a90d9";
37536
37546
  }
37537
- function renderTimeScaleHorizontal(g, scale, innerWidth, innerHeight, textColor) {
37547
+ function renderTimeScaleHorizontal(g, scale, _innerWidth, innerHeight, textColor) {
37538
37548
  const [domainMin, domainMax] = scale.domain();
37539
37549
  const ticks = computeTimeTicks(domainMin, domainMax, scale);
37540
37550
  if (ticks.length < 2) return;
@@ -37781,7 +37791,7 @@ function renderState(container, graph, layout, palette, isDark, onClickItem, exp
37781
37791
  for (const group of layout.groups) {
37782
37792
  if (group.collapsed) collapsedGroupIds.add(group.id);
37783
37793
  }
37784
- const colorOff = graph.options?.color === "off";
37794
+ const colorOff = graph.options?.["color"] === "off";
37785
37795
  const solid = graph.options?.["solid-fill"] === "on";
37786
37796
  for (const node of layout.nodes) {
37787
37797
  const isCollapsedGroup = collapsedGroupIds.has(node.id);
@@ -38181,7 +38191,7 @@ function renderQuadrantFocus(container, parsed, quadrantPosition, palette, isDar
38181
38191
  }
38182
38192
  }
38183
38193
  }
38184
- function renderQuarterCircle(svg, parsed, quadrant, qColor, palette, isDark, width, height, mutedColor, tooltip, rootContainer, onClickItem) {
38194
+ function renderQuarterCircle(svg, parsed, quadrant, qColor, palette, isDark, width, height, mutedColor, _tooltip, rootContainer, onClickItem) {
38185
38195
  const padding = 8;
38186
38196
  const size = Math.min(width - padding, height - padding);
38187
38197
  const maxRadius = size * 0.95;
@@ -39051,7 +39061,7 @@ function estimateListingHeight(parsed) {
39051
39061
  );
39052
39062
  return LISTING_LINE_HEIGHT * (maxBlipsInQuadrant + 1) + LISTING_LINE_HEIGHT + LISTING_TOP_MARGIN;
39053
39063
  }
39054
- function createBlipPopover(container, palette, isDark) {
39064
+ function createBlipPopover(container, _palette, isDark) {
39055
39065
  container.style.position = "relative";
39056
39066
  const existing = container.querySelector(
39057
39067
  "[data-blip-popover]"
@@ -40919,7 +40929,7 @@ function computeEdgeLabelPosition(midAngle, radius, cx, cy, lineCount, maxCharLe
40919
40929
  labelAngle: best.labelAngle
40920
40930
  };
40921
40931
  }
40922
- function fitToCanvas(nodes, edges, parsed, cx, cy, radius, width, height, _isClockwise) {
40932
+ function fitToCanvas(nodes, edges, parsed, _cx, _cy, radius, width, height, _isClockwise) {
40923
40933
  const PADDING3 = 30;
40924
40934
  let contentMinX = Infinity, contentMaxX = -Infinity;
40925
40935
  let contentMinY = Infinity, contentMaxY = -Infinity;
@@ -42428,7 +42438,7 @@ function renderPhaseBar(svg, phase, x, y, width, palette, collapsed, autoColor,
42428
42438
  });
42429
42439
  }
42430
42440
  }
42431
- function renderTaskRow(svg, task, parsed, x, y, labelW, roleX, roleColW, palette, surfaceBg, solid, taskDiagnostics, hasAnyDiagnostic, rowContent, onClickLine, _onMarkerDragStart) {
42441
+ function renderTaskRow(svg, task, parsed, x, y, labelW, roleX, roleColW, palette, surfaceBg, solid, taskDiagnostics, _hasAnyDiagnostic, rowContent, onClickLine, _onMarkerDragStart) {
42432
42442
  const rowG = svg.append("g").attr("class", "raci-task-row").attr("data-task-id", task.id).attr("data-line-number", String(task.lineNumber));
42433
42443
  const labelX = x + 8;
42434
42444
  const labelMaxW = labelW - 16;
@@ -43234,7 +43244,6 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
43234
43244
  const messages = collapsed ? collapsed.messages : parsed.messages;
43235
43245
  const elements = collapsed ? collapsed.elements : parsed.elements;
43236
43246
  const groups = collapsed ? collapsed.groups : parsed.groups;
43237
- const collapsedGroupIds = collapsed?.collapsedGroupIds ?? /* @__PURE__ */ new Map();
43238
43247
  const collapsedSections = options?.collapsedSections;
43239
43248
  const sourceParticipants = collapsed ? collapsed.participants : parsed.participants;
43240
43249
  const participants = applyPositionOverrides(
@@ -43262,7 +43271,7 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
43262
43271
  return Math.min(NOTE_MAX_W, laneMax);
43263
43272
  };
43264
43273
  const charsForWidth = (maxW) => Math.floor((maxW - NOTE_PAD_H * 2 - NOTE_FOLD) / NOTE_CHAR_W);
43265
- const activationsOff = parsedOptions.activations?.toLowerCase() === "off";
43274
+ const activationsOff = parsedOptions["activations"]?.toLowerCase() === "off";
43266
43275
  const activeTagGroup = resolveActiveTagGroup(
43267
43276
  parsed.tagGroups,
43268
43277
  parsedOptions["active-tag"],
@@ -46214,7 +46223,7 @@ function renderTimelineGroupLegend(g, groups, groupColorMap, textColor, palette,
46214
46223
  legendX += pillW + GAP;
46215
46224
  }
46216
46225
  }
46217
- function renderTimeline(container, parsed, palette, isDark, onClickItem, exportDims, activeTagGroup, swimlaneTagGroup, onTagStateChange, viewMode) {
46226
+ function setupTimeline(container, parsed, palette, isDark, exportDims, activeTagGroup, swimlaneTagGroup) {
46218
46227
  d3Selection22.select(container).selectAll(":not([data-d3-tooltip])").remove();
46219
46228
  const solid = parsed.solidFill === true;
46220
46229
  const {
@@ -46223,19 +46232,17 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
46223
46232
  timelineEras,
46224
46233
  timelineMarkers,
46225
46234
  timelineSort,
46226
- timelineScale,
46227
- timelineSwimlanes,
46228
46235
  orientation
46229
46236
  } = parsed;
46230
- const title = parsed.noTitle ? null : parsed.title;
46231
- if (timelineEvents.length === 0) return;
46232
- if (swimlaneTagGroup == null && timelineSort === "tag" && parsed.timelineDefaultSwimlaneTG) {
46233
- swimlaneTagGroup = parsed.timelineDefaultSwimlaneTG;
46237
+ if (timelineEvents.length === 0) return null;
46238
+ let resolvedSwimlaneTG = swimlaneTagGroup ?? null;
46239
+ if (resolvedSwimlaneTG == null && timelineSort === "tag" && parsed.timelineDefaultSwimlaneTG) {
46240
+ resolvedSwimlaneTG = parsed.timelineDefaultSwimlaneTG;
46234
46241
  }
46235
46242
  const tooltip = createTooltip2(container, palette, isDark);
46236
46243
  const width = exportDims?.width ?? container.clientWidth;
46237
46244
  const height = exportDims?.height ?? container.clientHeight;
46238
- if (width <= 0 || height <= 0) return;
46245
+ if (width <= 0 || height <= 0) return null;
46239
46246
  const isVertical = orientation === "vertical";
46240
46247
  const textColor = palette.text;
46241
46248
  const mutedColor = palette.border;
@@ -46247,8 +46254,8 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
46247
46254
  groupColorMap.set(grp.name, grp.color ?? colors[i % colors.length]);
46248
46255
  });
46249
46256
  let tagLanes = null;
46250
- if (swimlaneTagGroup) {
46251
- const tagKey = swimlaneTagGroup.toLowerCase();
46257
+ if (resolvedSwimlaneTG) {
46258
+ const tagKey = resolvedSwimlaneTG.toLowerCase();
46252
46259
  const tagGroup = parsed.timelineTagGroups.find(
46253
46260
  (g) => g.name.toLowerCase() === tagKey
46254
46261
  );
@@ -46279,7 +46286,7 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
46279
46286
  }
46280
46287
  }
46281
46288
  }
46282
- const effectiveColorTG = activeTagGroup ?? swimlaneTagGroup ?? null;
46289
+ const effectiveColorTG = activeTagGroup ?? resolvedSwimlaneTG ?? null;
46283
46290
  function eventColor(ev) {
46284
46291
  if (effectiveColorTG) {
46285
46292
  const tagColor = resolveTagColor(
@@ -46335,6 +46342,30 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
46335
46342
  }
46336
46343
  }
46337
46344
  const datePadding = (maxDate - minDate) * 0.05 || 0.5;
46345
+ const tagLegendReserve = parsed.timelineTagGroups.length > 0 ? 36 : 0;
46346
+ return {
46347
+ width,
46348
+ height,
46349
+ isVertical,
46350
+ tooltip,
46351
+ solid,
46352
+ textColor,
46353
+ mutedColor,
46354
+ bgColor,
46355
+ bg,
46356
+ swimlaneTagGroup: resolvedSwimlaneTG,
46357
+ groupColorMap,
46358
+ tagLanes,
46359
+ eventColor,
46360
+ minDate,
46361
+ maxDate,
46362
+ datePadding,
46363
+ earliestStartDateStr,
46364
+ latestEndDateStr,
46365
+ tagLegendReserve
46366
+ };
46367
+ }
46368
+ function makeTimelineHoverHelpers() {
46338
46369
  const FADE_OPACITY3 = 0.1;
46339
46370
  function fadeToGroup(g, groupName) {
46340
46371
  g.selectAll(".tl-event").each(function() {
@@ -46434,337 +46465,683 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
46434
46465
  evG.attr(`data-tag-${key}`, value.toLowerCase());
46435
46466
  }
46436
46467
  }
46437
- const tagLegendReserve = parsed.timelineTagGroups.length > 0 ? 36 : 0;
46438
- if (isVertical) {
46439
- const useGroupedVertical = tagLanes != null || timelineSort === "group" && timelineGroups.length > 0;
46440
- if (useGroupedVertical) {
46441
- let laneNames;
46442
- let laneEventsByName;
46443
- if (tagLanes) {
46444
- laneNames = tagLanes.map((l) => l.name);
46445
- laneEventsByName = new Map(tagLanes.map((l) => [l.name, l.events]));
46446
- } else {
46447
- const groupNames = timelineGroups.map((gr) => gr.name);
46448
- const ungroupedEvents = timelineEvents.filter(
46449
- (ev) => ev.group === null || !groupNames.includes(ev.group)
46450
- );
46451
- laneNames = ungroupedEvents.length > 0 ? [...groupNames, "(Other)"] : groupNames;
46452
- laneEventsByName = new Map(
46453
- laneNames.map((name) => [
46454
- name,
46455
- timelineEvents.filter(
46456
- (ev) => name === "(Other)" ? ev.group === null || !groupNames.includes(ev.group) : ev.group === name
46457
- )
46458
- ])
46459
- );
46468
+ return {
46469
+ FADE_OPACITY: FADE_OPACITY3,
46470
+ fadeToGroup,
46471
+ fadeToEra,
46472
+ fadeToMarker,
46473
+ fadeReset,
46474
+ fadeToTagValue,
46475
+ setTagAttrs
46476
+ };
46477
+ }
46478
+ function renderTimelineTagLegendOverlay(container, parsed, palette, isDark, setup, hovers, onClickItem, exportDims, swimlaneTagGroup, activeTagGroup, onTagStateChange, viewMode) {
46479
+ if (parsed.timelineTagGroups.length === 0) return;
46480
+ const { width, textColor, groupColorMap, solid } = setup;
46481
+ const { FADE_OPACITY: FADE_OPACITY3, fadeReset, fadeToTagValue } = hovers;
46482
+ const title = parsed.noTitle ? null : parsed.title;
46483
+ const { timelineEvents } = parsed;
46484
+ const LG_HEIGHT = LEGEND_HEIGHT;
46485
+ const LG_PILL_PAD = LEGEND_PILL_PAD;
46486
+ const LG_PILL_FONT_SIZE = LEGEND_PILL_FONT_SIZE;
46487
+ const LG_CAPSULE_PAD = LEGEND_CAPSULE_PAD;
46488
+ const LG_DOT_R = LEGEND_DOT_R;
46489
+ const LG_ENTRY_FONT_SIZE = LEGEND_ENTRY_FONT_SIZE;
46490
+ const LG_ENTRY_DOT_GAP = LEGEND_ENTRY_DOT_GAP;
46491
+ const LG_ENTRY_TRAIL = LEGEND_ENTRY_TRAIL;
46492
+ const LG_ICON_W = 20;
46493
+ const mainSvg = d3Selection22.select(container).select("svg");
46494
+ const mainG = mainSvg.select("g");
46495
+ if (!mainSvg.empty() && !mainG.empty()) {
46496
+ let drawSwimlaneIcon4 = function(parent, x, y, isSwimActive) {
46497
+ const iconG = parent.append("g").attr("class", "tl-swimlane-icon").attr("transform", `translate(${x}, ${y})`).style("cursor", "pointer");
46498
+ const barColor = isSwimActive ? palette.primary : palette.textMuted;
46499
+ const barOpacity = isSwimActive ? 1 : 0.35;
46500
+ const bars = [
46501
+ { y: 0, w: 8 },
46502
+ { y: 4, w: 12 },
46503
+ { y: 8, w: 6 }
46504
+ ];
46505
+ for (const bar of bars) {
46506
+ iconG.append("rect").attr("x", 0).attr("y", bar.y).attr("width", bar.w).attr("height", 2).attr("rx", 1).attr("fill", barColor).attr("opacity", barOpacity);
46460
46507
  }
46461
- const laneCount = laneNames.length;
46462
- const scaleMargin = timelineScale ? 40 : 0;
46463
- const markerMargin = timelineMarkers.length > 0 ? 30 : 0;
46464
- const margin = {
46465
- top: 104 + markerMargin + tagLegendReserve,
46466
- right: 40 + scaleMargin,
46467
- bottom: 40,
46468
- left: 60 + scaleMargin
46469
- };
46470
- const innerWidth = width - margin.left - margin.right;
46471
- const innerHeight = height - margin.top - margin.bottom;
46472
- const laneWidth = innerWidth / laneCount;
46473
- const yScale = d3Scale2.scaleLinear().domain([minDate - datePadding, maxDate + datePadding]).range([0, innerHeight]);
46474
- const svg = d3Selection22.select(container).append("svg").attr("viewBox", `0 0 ${width} ${height}`).attr("width", exportDims ? width : "100%").attr("preserveAspectRatio", "xMidYMin meet").style("background", bgColor);
46475
- const g = svg.append("g").attr("transform", `translate(${margin.left},${margin.top})`);
46476
- renderChartTitle(
46477
- svg,
46478
- title,
46479
- parsed.titleLineNumber,
46480
- width,
46481
- textColor,
46482
- onClickItem
46483
- );
46484
- renderEras(
46485
- g,
46486
- timelineEras,
46487
- yScale,
46488
- true,
46489
- innerWidth,
46490
- innerHeight,
46491
- (s, e) => fadeToEra(g, s, e),
46492
- () => fadeReset(g),
46493
- timelineScale,
46494
- tooltip,
46495
- palette
46496
- );
46497
- renderMarkers(
46498
- g,
46499
- timelineMarkers,
46500
- yScale,
46501
- true,
46502
- innerWidth,
46503
- innerHeight,
46504
- (d) => fadeToMarker(g, d),
46505
- () => fadeReset(g),
46506
- timelineScale,
46507
- tooltip,
46508
- palette
46508
+ return iconG;
46509
+ }, relayout2 = function() {
46510
+ renderTimeline(
46511
+ container,
46512
+ parsed,
46513
+ palette,
46514
+ isDark,
46515
+ onClickItem,
46516
+ exportDims,
46517
+ currentActiveGroup,
46518
+ currentSwimlaneGroup,
46519
+ onTagStateChange,
46520
+ viewMode
46509
46521
  );
46510
- if (timelineScale) {
46511
- renderTimeScale(
46512
- g,
46513
- yScale,
46514
- true,
46515
- innerWidth,
46516
- innerHeight,
46517
- textColor,
46518
- minDate,
46519
- maxDate,
46520
- formatBoundaryLabel(earliestStartDateStr, latestEndDateStr),
46521
- formatBoundaryLabel(latestEndDateStr, earliestStartDateStr)
46522
+ }, drawLegend2 = function() {
46523
+ mainSvg.selectAll(".tl-tag-legend-group").remove();
46524
+ mainSvg.selectAll(".tl-tag-legend-container").remove();
46525
+ const effectiveColorKey = (currentActiveGroup ?? currentSwimlaneGroup)?.toLowerCase() ?? null;
46526
+ const visibleGroups = viewMode ? legendGroups.filter(
46527
+ (lg) => effectiveColorKey != null && lg.group.name.toLowerCase() === effectiveColorKey
46528
+ ) : legendGroups;
46529
+ if (visibleGroups.length === 0) return;
46530
+ const legendContainer = mainSvg.append("g").attr("class", "tl-tag-legend-container");
46531
+ if (currentActiveGroup) {
46532
+ legendContainer.attr(
46533
+ "data-legend-active",
46534
+ currentActiveGroup.toLowerCase()
46522
46535
  );
46523
46536
  }
46524
- if (timelineSwimlanes || tagLanes) {
46525
- laneNames.forEach((laneName, laneIdx) => {
46526
- const laneX = laneIdx * laneWidth;
46527
- const fillColor = laneIdx % 2 === 0 ? textColor : "transparent";
46528
- g.append("rect").attr("class", "tl-swimlane").attr("data-group", laneName).attr("x", laneX).attr("y", 0).attr("width", laneWidth).attr("height", innerHeight).attr("fill", fillColor).attr("opacity", 0.06);
46529
- });
46530
- }
46531
- laneNames.forEach((laneName, laneIdx) => {
46532
- const laneX = laneIdx * laneWidth;
46533
- const laneColor = groupColorMap.get(laneName) ?? textColor;
46534
- const laneCenter = laneX + laneWidth / 2;
46535
- const headerG = g.append("g").attr("class", "tl-lane-header").attr("data-group", laneName).style("cursor", "pointer").on("mouseenter", () => fadeToGroup(g, laneName)).on("mouseleave", () => fadeReset(g));
46536
- headerG.append("text").attr("x", laneCenter).attr("y", -15).attr("text-anchor", "middle").attr("fill", laneColor).attr("font-size", "12px").attr("font-weight", "600").text(laneName);
46537
- g.append("line").attr("x1", laneCenter).attr("y1", 0).attr("x2", laneCenter).attr("y2", innerHeight).attr("stroke", mutedColor).attr("stroke-width", 1).attr("stroke-dasharray", "4,4");
46538
- const laneEvents = laneEventsByName.get(laneName) ?? [];
46539
- for (const ev of laneEvents) {
46540
- const y = yScale(parseTimelineDate(ev.date));
46541
- const evG = g.append("g").attr("class", "tl-event").attr("data-group", laneName).attr("data-line-number", String(ev.lineNumber)).attr("data-date", String(parseTimelineDate(ev.date))).attr(
46542
- "data-end-date",
46543
- ev.endDate ? String(parseTimelineDate(ev.endDate)) : null
46544
- ).style("cursor", "pointer").on("mouseenter", function(event) {
46545
- fadeToGroup(g, laneName);
46546
- showTooltip(tooltip, buildEventTooltipHtml(ev), event);
46547
- }).on("mouseleave", function() {
46548
- fadeReset(g);
46549
- hideTooltip(tooltip);
46550
- }).on("mousemove", function(event) {
46551
- showTooltip(tooltip, buildEventTooltipHtml(ev), event);
46552
- }).on("click", () => {
46553
- if (onClickItem && ev.lineNumber) onClickItem(ev.lineNumber);
46554
- });
46555
- setTagAttrs(evG, ev);
46556
- const evColor = eventColor(ev);
46557
- if (ev.endDate) {
46558
- const y2 = yScale(parseTimelineDate(ev.endDate));
46559
- const rectH = Math.max(y2 - y, 4);
46560
- let fill2 = shapeFill(palette, evColor, isDark, { solid });
46561
- let stroke2 = evColor;
46562
- if (ev.uncertain) {
46563
- const gradientId = `uncertain-vg-${ev.lineNumber}`;
46564
- const strokeGradientId = `uncertain-vg-s-${ev.lineNumber}`;
46565
- const defs = svg.select("defs").node() || svg.append("defs").node();
46566
- const defsEl = d3Selection22.select(defs);
46567
- defsEl.append("linearGradient").attr("id", gradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "0%").attr("y2", "100%").selectAll("stop").data([
46568
- { offset: "0%", opacity: 1 },
46569
- { offset: "80%", opacity: 1 },
46570
- { offset: "100%", opacity: 0 }
46571
- ]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", mix(laneColor, bg, 30)).attr("stop-opacity", (d) => d.opacity);
46572
- defsEl.append("linearGradient").attr("id", strokeGradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "0%").attr("y2", "100%").selectAll("stop").data([
46573
- { offset: "0%", opacity: 1 },
46574
- { offset: "80%", opacity: 1 },
46575
- { offset: "100%", opacity: 0 }
46576
- ]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", evColor).attr("stop-opacity", (d) => d.opacity);
46577
- fill2 = `url(#${gradientId})`;
46578
- stroke2 = `url(#${strokeGradientId})`;
46579
- }
46580
- evG.append("rect").attr("x", laneCenter - 6).attr("y", y).attr("width", 12).attr("height", rectH).attr("rx", 4).attr("fill", fill2).attr("stroke", stroke2).attr("stroke-width", 2);
46581
- evG.append("text").attr("x", laneCenter + 14).attr("y", y + rectH / 2).attr("dy", "0.35em").attr("fill", textColor).attr("font-size", "10px").text(ev.label);
46537
+ const iconAddon = viewMode ? 0 : LG_ICON_W;
46538
+ const centralGroups = visibleGroups.map((lg) => ({
46539
+ name: lg.group.name,
46540
+ entries: lg.group.entries.map((e) => ({
46541
+ value: e.value,
46542
+ color: e.color
46543
+ }))
46544
+ }));
46545
+ const centralActive = viewMode ? effectiveColorKey : currentActiveGroup;
46546
+ const centralConfig = {
46547
+ groups: centralGroups,
46548
+ position: { placement: "top-center", titleRelation: "below-title" },
46549
+ mode: "fixed",
46550
+ capsulePillAddonWidth: iconAddon
46551
+ };
46552
+ const centralState = { activeGroup: centralActive };
46553
+ const centralCallbacks = viewMode ? {} : {
46554
+ onGroupToggle: (groupName) => {
46555
+ currentActiveGroup = currentActiveGroup === groupName.toLowerCase() ? null : groupName.toLowerCase();
46556
+ drawLegend2();
46557
+ recolorEvents2();
46558
+ onTagStateChange?.(currentActiveGroup, currentSwimlaneGroup);
46559
+ },
46560
+ onEntryHover: (groupName, entryValue) => {
46561
+ const tagKey = groupName.toLowerCase();
46562
+ if (entryValue) {
46563
+ const tagVal = entryValue.toLowerCase();
46564
+ fadeToTagValue(mainG, tagKey, tagVal);
46565
+ mainSvg.selectAll("[data-legend-entry]").each(function() {
46566
+ const el = d3Selection22.select(this);
46567
+ const ev = el.attr("data-legend-entry");
46568
+ const eg = el.attr("data-tag-group") ?? el.node()?.closest?.("[data-tag-group]")?.getAttribute("data-tag-group");
46569
+ el.attr(
46570
+ "opacity",
46571
+ eg === tagKey && ev === tagVal ? 1 : FADE_OPACITY3
46572
+ );
46573
+ });
46582
46574
  } else {
46583
- evG.append("circle").attr("cx", laneCenter).attr("cy", y).attr("r", 4).attr("fill", shapeFill(palette, evColor, isDark, { solid })).attr("stroke", evColor).attr("stroke-width", 2);
46584
- evG.append("text").attr("x", laneCenter + 10).attr("y", y).attr("dy", "0.35em").attr("fill", textColor).attr("font-size", "10px").text(ev.label);
46575
+ fadeReset(mainG);
46576
+ mainSvg.selectAll("[data-legend-entry]").attr("opacity", 1);
46577
+ }
46578
+ },
46579
+ onGroupRendered: (groupName, groupEl, isActive) => {
46580
+ const groupKey = groupName.toLowerCase();
46581
+ groupEl.attr("data-tag-group", groupKey);
46582
+ if (isActive && !viewMode) {
46583
+ const isSwimActive = currentSwimlaneGroup != null && currentSwimlaneGroup.toLowerCase() === groupKey;
46584
+ const pillWidth3 = measureLegendText(groupName, LG_PILL_FONT_SIZE) + LG_PILL_PAD;
46585
+ const pillXOff = LG_CAPSULE_PAD;
46586
+ const iconX = pillXOff + pillWidth3 + 5;
46587
+ const iconY = (LG_HEIGHT - 10) / 2;
46588
+ const iconEl = drawSwimlaneIcon4(
46589
+ groupEl,
46590
+ iconX,
46591
+ iconY,
46592
+ isSwimActive
46593
+ );
46594
+ iconEl.attr("data-swimlane-toggle", groupKey).on("click", (event) => {
46595
+ event.stopPropagation();
46596
+ currentSwimlaneGroup = currentSwimlaneGroup === groupKey ? null : groupKey;
46597
+ onTagStateChange?.(
46598
+ currentActiveGroup,
46599
+ currentSwimlaneGroup
46600
+ );
46601
+ relayout2();
46602
+ });
46585
46603
  }
46586
46604
  }
46587
- });
46588
- } else {
46589
- const scaleMargin = timelineScale ? 40 : 0;
46590
- const markerMargin = timelineMarkers.length > 0 ? 30 : 0;
46591
- const margin = {
46592
- top: 104 + markerMargin + tagLegendReserve,
46593
- right: 200,
46594
- bottom: 40,
46595
- left: 60 + scaleMargin
46596
46605
  };
46597
- const innerWidth = width - margin.left - margin.right;
46598
- const innerHeight = height - margin.top - margin.bottom;
46599
- const axisX = 20;
46600
- const yScale = d3Scale2.scaleLinear().domain([minDate - datePadding, maxDate + datePadding]).range([0, innerHeight]);
46601
- const sorted = timelineEvents.slice().sort((a, b) => parseTimelineDate(a.date) - parseTimelineDate(b.date));
46602
- const svg = d3Selection22.select(container).append("svg").attr("viewBox", `0 0 ${width} ${height}`).attr("width", exportDims ? width : "100%").attr("preserveAspectRatio", "xMidYMin meet").style("background", bgColor);
46603
- const g = svg.append("g").attr("transform", `translate(${margin.left},${margin.top})`);
46604
- renderChartTitle(
46605
- svg,
46606
- title,
46607
- parsed.titleLineNumber,
46608
- width,
46609
- textColor,
46610
- onClickItem
46611
- );
46612
- renderEras(
46613
- g,
46614
- timelineEras,
46615
- yScale,
46616
- true,
46617
- innerWidth,
46618
- innerHeight,
46619
- (s, e) => fadeToEra(g, s, e),
46620
- () => fadeReset(g),
46621
- timelineScale,
46622
- tooltip,
46623
- palette
46624
- );
46625
- renderMarkers(
46626
- g,
46627
- timelineMarkers,
46628
- yScale,
46629
- true,
46630
- innerWidth,
46631
- innerHeight,
46632
- (d) => fadeToMarker(g, d),
46633
- () => fadeReset(g),
46634
- timelineScale,
46635
- tooltip,
46636
- palette
46606
+ const legendInnerG = legendContainer.append("g").attr("transform", `translate(0, ${legendY})`);
46607
+ renderLegendD3(
46608
+ legendInnerG,
46609
+ centralConfig,
46610
+ centralState,
46611
+ palette,
46612
+ isDark,
46613
+ centralCallbacks,
46614
+ width
46637
46615
  );
46616
+ }, recolorEvents2 = function() {
46617
+ const colorTG = currentActiveGroup ?? swimlaneTagGroup ?? null;
46618
+ mainG.selectAll(".tl-event").each(function() {
46619
+ const el = d3Selection22.select(this);
46620
+ const lineNum = el.attr("data-line-number");
46621
+ const ev = lineNum ? eventByLine.get(lineNum) : void 0;
46622
+ if (!ev) return;
46623
+ let color;
46624
+ if (colorTG) {
46625
+ const tagColor = resolveTagColor(
46626
+ ev.metadata,
46627
+ parsed.timelineTagGroups,
46628
+ colorTG
46629
+ );
46630
+ color = tagColor ?? (ev.group && groupColorMap.has(ev.group) ? groupColorMap.get(ev.group) : textColor);
46631
+ } else {
46632
+ color = ev.group && groupColorMap.has(ev.group) ? groupColorMap.get(ev.group) : textColor;
46633
+ }
46634
+ el.selectAll("rect").attr("fill", shapeFill(palette, color, isDark, { solid })).attr("stroke", color);
46635
+ el.selectAll("circle:not(.tl-event-point-outline)").attr("fill", shapeFill(palette, color, isDark, { solid })).attr("stroke", color);
46636
+ });
46637
+ };
46638
+ var drawSwimlaneIcon3 = drawSwimlaneIcon4, relayout = relayout2, drawLegend = drawLegend2, recolorEvents = recolorEvents2;
46639
+ const legendY = title ? 50 : 10;
46640
+ const legendGroups = parsed.timelineTagGroups.map((g) => {
46641
+ const pillW = measureLegendText(g.name, LG_PILL_FONT_SIZE) + LG_PILL_PAD;
46642
+ const iconSpace = viewMode ? 8 : LG_ICON_W + 4;
46643
+ let entryX = LG_CAPSULE_PAD + pillW + iconSpace;
46644
+ for (const entry of g.entries) {
46645
+ const textX = entryX + LG_DOT_R * 2 + LG_ENTRY_DOT_GAP;
46646
+ entryX = textX + measureLegendText(entry.value, LG_ENTRY_FONT_SIZE) + LG_ENTRY_TRAIL;
46647
+ }
46648
+ return {
46649
+ group: g,
46650
+ minifiedWidth: pillW,
46651
+ expandedWidth: entryX + LG_CAPSULE_PAD
46652
+ };
46653
+ });
46654
+ let currentActiveGroup = activeTagGroup ?? null;
46655
+ let currentSwimlaneGroup = swimlaneTagGroup ?? null;
46656
+ const eventByLine = /* @__PURE__ */ new Map();
46657
+ for (const ev of timelineEvents) {
46658
+ eventByLine.set(String(ev.lineNumber), ev);
46659
+ }
46660
+ drawLegend2();
46661
+ }
46662
+ }
46663
+ function renderTimelineHorizontalTimeSort(container, parsed, palette, isDark, setup, hovers, onClickItem, _exportDims, _swimlaneTagGroup, _activeTagGroup, _onTagStateChange, _viewMode) {
46664
+ const {
46665
+ width,
46666
+ height,
46667
+ tooltip,
46668
+ solid,
46669
+ textColor,
46670
+ bgColor,
46671
+ bg,
46672
+ groupColorMap,
46673
+ eventColor,
46674
+ minDate,
46675
+ maxDate,
46676
+ datePadding,
46677
+ earliestStartDateStr,
46678
+ latestEndDateStr,
46679
+ tagLegendReserve
46680
+ } = setup;
46681
+ const { fadeToGroup, fadeToEra, fadeToMarker, fadeReset, setTagAttrs } = hovers;
46682
+ const {
46683
+ timelineEvents,
46684
+ timelineGroups,
46685
+ timelineEras,
46686
+ timelineMarkers,
46687
+ timelineScale
46688
+ } = parsed;
46689
+ const title = parsed.noTitle ? null : parsed.title;
46690
+ const BAR_H2 = 22;
46691
+ const sorted = timelineEvents.slice().sort((a, b) => parseTimelineDate(a.date) - parseTimelineDate(b.date));
46692
+ const scaleMargin = timelineScale ? 24 : 0;
46693
+ const ERA_ROW_H = 22;
46694
+ const MARKER_ROW_H = 22;
46695
+ const eraReserve = timelineEras.length > 0 ? ERA_ROW_H : 0;
46696
+ const markerReserve = timelineMarkers.length > 0 ? MARKER_ROW_H : 0;
46697
+ const topScaleH = timelineScale ? 40 : 0;
46698
+ const margin = {
46699
+ top: 104 + topScaleH + eraReserve + markerReserve + tagLegendReserve,
46700
+ right: 40,
46701
+ bottom: 40 + scaleMargin,
46702
+ left: 60
46703
+ };
46704
+ const markerLabelY = markerReserve ? -(topScaleH + MARKER_ROW_H / 2) : 0;
46705
+ const eraLabelY = eraReserve ? -(topScaleH + markerReserve + ERA_ROW_H / 2) : 0;
46706
+ const innerWidth = width - margin.left - margin.right;
46707
+ const innerHeight = height - margin.top - margin.bottom;
46708
+ const rowH = Math.min(28, innerHeight / sorted.length);
46709
+ const xScale = d3Scale2.scaleLinear().domain([minDate - datePadding, maxDate + datePadding]).range([0, innerWidth]);
46710
+ const svg = d3Selection22.select(container).append("svg").attr("width", width).attr("height", height).style("background", bgColor);
46711
+ const g = svg.append("g").attr("transform", `translate(${margin.left},${margin.top})`);
46712
+ renderChartTitle(
46713
+ svg,
46714
+ title,
46715
+ parsed.titleLineNumber,
46716
+ width,
46717
+ textColor,
46718
+ onClickItem
46719
+ );
46720
+ renderEras(
46721
+ g,
46722
+ timelineEras,
46723
+ xScale,
46724
+ false,
46725
+ innerWidth,
46726
+ innerHeight,
46727
+ (s, e) => fadeToEra(g, s, e),
46728
+ () => fadeReset(g),
46729
+ timelineScale,
46730
+ tooltip,
46731
+ palette,
46732
+ eraReserve ? eraLabelY : void 0
46733
+ );
46734
+ renderMarkers(
46735
+ g,
46736
+ timelineMarkers,
46737
+ xScale,
46738
+ false,
46739
+ innerWidth,
46740
+ innerHeight,
46741
+ (d) => fadeToMarker(g, d),
46742
+ () => fadeReset(g),
46743
+ timelineScale,
46744
+ tooltip,
46745
+ palette,
46746
+ markerReserve ? markerLabelY : void 0
46747
+ );
46748
+ if (timelineScale) {
46749
+ renderTimeScale(
46750
+ g,
46751
+ xScale,
46752
+ false,
46753
+ innerWidth,
46754
+ innerHeight,
46755
+ textColor,
46756
+ minDate,
46757
+ maxDate,
46758
+ formatBoundaryLabel(earliestStartDateStr, latestEndDateStr),
46759
+ formatBoundaryLabel(latestEndDateStr, earliestStartDateStr)
46760
+ );
46761
+ }
46762
+ if (timelineGroups.length > 0) {
46763
+ const legendY = timelineScale ? -75 : -55;
46764
+ renderTimelineGroupLegend(
46765
+ g,
46766
+ timelineGroups,
46767
+ groupColorMap,
46768
+ textColor,
46769
+ palette,
46770
+ isDark,
46771
+ legendY,
46772
+ (name) => fadeToGroup(g, name),
46773
+ () => fadeReset(g)
46774
+ );
46775
+ }
46776
+ sorted.forEach((ev, i) => {
46777
+ const y = i * rowH + rowH / 2;
46778
+ const x = xScale(parseTimelineDate(ev.date));
46779
+ const color = eventColor(ev);
46780
+ const evG = g.append("g").attr("class", "tl-event").attr("data-group", ev.group || "").attr("data-line-number", String(ev.lineNumber)).attr("data-date", String(parseTimelineDate(ev.date))).attr(
46781
+ "data-end-date",
46782
+ ev.endDate ? String(parseTimelineDate(ev.endDate)) : null
46783
+ ).style("cursor", "pointer").on("mouseenter", function(event) {
46784
+ if (ev.group && timelineGroups.length > 0) fadeToGroup(g, ev.group);
46638
46785
  if (timelineScale) {
46639
- renderTimeScale(
46786
+ showEventDatesOnScale(
46640
46787
  g,
46641
- yScale,
46642
- true,
46643
- innerWidth,
46788
+ xScale,
46789
+ ev.date,
46790
+ ev.endDate,
46644
46791
  innerHeight,
46645
- textColor,
46646
- minDate,
46647
- maxDate,
46648
- formatBoundaryLabel(earliestStartDateStr, latestEndDateStr),
46649
- formatBoundaryLabel(latestEndDateStr, earliestStartDateStr)
46792
+ color
46650
46793
  );
46794
+ } else {
46795
+ showTooltip(tooltip, buildEventTooltipHtml(ev), event);
46651
46796
  }
46652
- if (timelineGroups.length > 0) {
46653
- renderTimelineGroupLegend(
46654
- g,
46655
- timelineGroups,
46656
- groupColorMap,
46657
- textColor,
46658
- palette,
46659
- isDark,
46660
- -55,
46661
- (name) => fadeToGroup(g, name),
46662
- () => fadeReset(g)
46663
- );
46797
+ }).on("mouseleave", function() {
46798
+ fadeReset(g);
46799
+ if (timelineScale) {
46800
+ hideEventDatesOnScale(g);
46801
+ } else {
46802
+ hideTooltip(tooltip);
46664
46803
  }
46665
- g.append("line").attr("x1", axisX).attr("y1", 0).attr("x2", axisX).attr("y2", innerHeight).attr("stroke", mutedColor).attr("stroke-width", 1).attr("stroke-dasharray", "4,4");
46666
- for (const ev of sorted) {
46667
- const y = yScale(parseTimelineDate(ev.date));
46668
- const color = eventColor(ev);
46669
- const evG = g.append("g").attr("class", "tl-event").attr("data-group", ev.group || "").attr("data-line-number", String(ev.lineNumber)).attr("data-date", String(parseTimelineDate(ev.date))).attr(
46670
- "data-end-date",
46671
- ev.endDate ? String(parseTimelineDate(ev.endDate)) : null
46672
- ).style("cursor", "pointer").on("mouseenter", function(event) {
46673
- if (ev.group && timelineGroups.length > 0) fadeToGroup(g, ev.group);
46804
+ }).on("mousemove", function(event) {
46805
+ if (!timelineScale) {
46806
+ showTooltip(tooltip, buildEventTooltipHtml(ev), event);
46807
+ }
46808
+ }).on("click", () => {
46809
+ if (onClickItem && ev.lineNumber) onClickItem(ev.lineNumber);
46810
+ });
46811
+ setTagAttrs(evG, ev);
46812
+ if (ev.endDate) {
46813
+ const x2 = xScale(parseTimelineDate(ev.endDate));
46814
+ const rectW = Math.max(x2 - x, 4);
46815
+ const estLabelWidth = ev.label.length * 7 + 16;
46816
+ const labelFitsInside = rectW >= estLabelWidth;
46817
+ let fill2 = shapeFill(palette, color, isDark, { solid });
46818
+ let stroke2 = color;
46819
+ if (ev.uncertain) {
46820
+ const gradientId = `uncertain-ts-${ev.lineNumber}`;
46821
+ const strokeGradientId = `uncertain-ts-s-${ev.lineNumber}`;
46822
+ const defs = svg.select("defs").node() || svg.append("defs").node();
46823
+ const defsEl = d3Selection22.select(defs);
46824
+ defsEl.append("linearGradient").attr("id", gradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "100%").attr("y2", "0%").selectAll("stop").data([
46825
+ { offset: "0%", opacity: 1 },
46826
+ { offset: "80%", opacity: 1 },
46827
+ { offset: "100%", opacity: 0 }
46828
+ ]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", mix(color, bg, 30)).attr("stop-opacity", (d) => d.opacity);
46829
+ defsEl.append("linearGradient").attr("id", strokeGradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "100%").attr("y2", "0%").selectAll("stop").data([
46830
+ { offset: "0%", opacity: 1 },
46831
+ { offset: "80%", opacity: 1 },
46832
+ { offset: "100%", opacity: 0 }
46833
+ ]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", color).attr("stop-opacity", (d) => d.opacity);
46834
+ fill2 = `url(#${gradientId})`;
46835
+ stroke2 = `url(#${strokeGradientId})`;
46836
+ }
46837
+ evG.append("rect").attr("x", x).attr("y", y - BAR_H2 / 2).attr("width", rectW).attr("height", BAR_H2).attr("rx", 4).attr("fill", fill2).attr("stroke", stroke2).attr("stroke-width", 2);
46838
+ if (labelFitsInside) {
46839
+ evG.append("text").attr("x", x + 8).attr("y", y).attr("dy", "0.35em").attr("text-anchor", "start").attr("fill", textColor).attr("font-size", "13px").text(ev.label);
46840
+ } else {
46841
+ const wouldFlipLeft = x + rectW > innerWidth * 0.6;
46842
+ const labelFitsLeft = x - 6 - estLabelWidth > 0;
46843
+ const flipLeft = wouldFlipLeft && labelFitsLeft;
46844
+ evG.append("text").attr("x", flipLeft ? x - 6 : x + rectW + 6).attr("y", y).attr("dy", "0.35em").attr("text-anchor", flipLeft ? "end" : "start").attr("fill", textColor).attr("font-size", "13px").text(ev.label);
46845
+ }
46846
+ } else {
46847
+ const estLabelWidth = ev.label.length * 7;
46848
+ const wouldFlipLeft = x > innerWidth * 0.6;
46849
+ const labelFitsLeft = x - 10 - estLabelWidth > 0;
46850
+ const flipLeft = wouldFlipLeft && labelFitsLeft;
46851
+ evG.append("circle").attr("cx", x).attr("cy", y).attr("r", 5).attr("fill", shapeFill(palette, color, isDark, { solid })).attr("stroke", color).attr("stroke-width", 2);
46852
+ evG.append("text").attr("x", flipLeft ? x - 10 : x + 10).attr("y", y).attr("dy", "0.35em").attr("text-anchor", flipLeft ? "end" : "start").attr("fill", textColor).attr("font-size", "12px").text(ev.label);
46853
+ }
46854
+ });
46855
+ }
46856
+ function renderTimelineHorizontalGrouped(container, parsed, palette, isDark, setup, hovers, onClickItem, _exportDims, _swimlaneTagGroup, _activeTagGroup, _onTagStateChange, _viewMode) {
46857
+ const {
46858
+ width,
46859
+ height,
46860
+ tooltip,
46861
+ solid,
46862
+ textColor,
46863
+ bgColor,
46864
+ bg,
46865
+ groupColorMap,
46866
+ tagLanes,
46867
+ eventColor,
46868
+ minDate,
46869
+ maxDate,
46870
+ datePadding,
46871
+ earliestStartDateStr,
46872
+ latestEndDateStr,
46873
+ tagLegendReserve
46874
+ } = setup;
46875
+ const { fadeToGroup, fadeToEra, fadeToMarker, fadeReset, setTagAttrs } = hovers;
46876
+ const {
46877
+ timelineEvents,
46878
+ timelineGroups,
46879
+ timelineEras,
46880
+ timelineMarkers,
46881
+ timelineScale,
46882
+ timelineSwimlanes
46883
+ } = parsed;
46884
+ const title = parsed.noTitle ? null : parsed.title;
46885
+ const BAR_H2 = 22;
46886
+ const GROUP_GAP3 = 12;
46887
+ let lanes;
46888
+ if (tagLanes) {
46889
+ lanes = tagLanes;
46890
+ } else {
46891
+ const groupNames = timelineGroups.map((gr) => gr.name);
46892
+ const ungroupedEvents = timelineEvents.filter(
46893
+ (ev) => ev.group === null || !groupNames.includes(ev.group)
46894
+ );
46895
+ const laneNames = ungroupedEvents.length > 0 ? [...groupNames, "(Other)"] : groupNames;
46896
+ lanes = laneNames.map((name) => ({
46897
+ name,
46898
+ events: timelineEvents.filter(
46899
+ (ev) => name === "(Other)" ? ev.group === null || !groupNames.includes(ev.group) : ev.group === name
46900
+ )
46901
+ }));
46902
+ }
46903
+ const totalEventRows = lanes.reduce((s, l) => s + l.events.length, 0);
46904
+ const scaleMargin = timelineScale ? 24 : 0;
46905
+ const ERA_ROW_H = 22;
46906
+ const MARKER_ROW_H = 22;
46907
+ const eraReserve = timelineEras.length > 0 ? ERA_ROW_H : 0;
46908
+ const markerReserve = timelineMarkers.length > 0 ? MARKER_ROW_H : 0;
46909
+ const topScaleH = timelineScale ? 40 : 0;
46910
+ const maxGroupNameLen = Math.max(...lanes.map((l) => l.name.length));
46911
+ const dynamicLeftMargin = Math.max(120, maxGroupNameLen * 7 + 30);
46912
+ const baseTopMargin = title ? 50 : 20;
46913
+ const margin = {
46914
+ top: baseTopMargin + topScaleH + eraReserve + markerReserve + tagLegendReserve,
46915
+ right: 40,
46916
+ bottom: 40 + scaleMargin,
46917
+ left: dynamicLeftMargin
46918
+ };
46919
+ const markerLabelY = markerReserve ? -(topScaleH + MARKER_ROW_H / 2) : 0;
46920
+ const eraLabelY = eraReserve ? -(topScaleH + markerReserve + ERA_ROW_H / 2) : 0;
46921
+ const innerWidth = width - margin.left - margin.right;
46922
+ const innerHeight = height - margin.top - margin.bottom;
46923
+ const totalGaps = (lanes.length - 1) * GROUP_GAP3;
46924
+ const rowH = Math.min(28, (innerHeight - totalGaps) / totalEventRows);
46925
+ const xScale = d3Scale2.scaleLinear().domain([minDate - datePadding, maxDate + datePadding]).range([0, innerWidth]);
46926
+ const svg = d3Selection22.select(container).append("svg").attr("width", width).attr("height", height).style("background", bgColor);
46927
+ const g = svg.append("g").attr("transform", `translate(${margin.left},${margin.top})`);
46928
+ renderChartTitle(
46929
+ svg,
46930
+ title,
46931
+ parsed.titleLineNumber,
46932
+ width,
46933
+ textColor,
46934
+ onClickItem
46935
+ );
46936
+ renderEras(
46937
+ g,
46938
+ timelineEras,
46939
+ xScale,
46940
+ false,
46941
+ innerWidth,
46942
+ innerHeight,
46943
+ (s, e) => fadeToEra(g, s, e),
46944
+ () => fadeReset(g),
46945
+ timelineScale,
46946
+ tooltip,
46947
+ palette,
46948
+ eraReserve ? eraLabelY : void 0
46949
+ );
46950
+ renderMarkers(
46951
+ g,
46952
+ timelineMarkers,
46953
+ xScale,
46954
+ false,
46955
+ innerWidth,
46956
+ innerHeight,
46957
+ (d) => fadeToMarker(g, d),
46958
+ () => fadeReset(g),
46959
+ timelineScale,
46960
+ tooltip,
46961
+ palette,
46962
+ markerReserve ? markerLabelY : void 0
46963
+ );
46964
+ if (timelineScale) {
46965
+ renderTimeScale(
46966
+ g,
46967
+ xScale,
46968
+ false,
46969
+ innerWidth,
46970
+ innerHeight,
46971
+ textColor,
46972
+ minDate,
46973
+ maxDate,
46974
+ formatBoundaryLabel(earliestStartDateStr, latestEndDateStr),
46975
+ formatBoundaryLabel(latestEndDateStr, earliestStartDateStr)
46976
+ );
46977
+ }
46978
+ let curY = 0;
46979
+ if (timelineSwimlanes || tagLanes) {
46980
+ let swimY = 0;
46981
+ lanes.forEach((lane, idx) => {
46982
+ const laneSpan = lane.events.length * rowH;
46983
+ const fillColor = idx % 2 === 0 ? textColor : "transparent";
46984
+ g.append("rect").attr("class", "tl-swimlane").attr("data-group", lane.name).attr("x", -margin.left).attr("y", swimY).attr("width", innerWidth + margin.left).attr("height", laneSpan + (idx < lanes.length - 1 ? GROUP_GAP3 : 0)).attr("fill", fillColor).attr("opacity", 0.06);
46985
+ swimY += laneSpan + GROUP_GAP3;
46986
+ });
46987
+ }
46988
+ for (const lane of lanes) {
46989
+ const laneColor = groupColorMap.get(lane.name) ?? textColor;
46990
+ const laneSpan = lane.events.length * rowH;
46991
+ const group = timelineGroups.find((grp) => grp.name === lane.name);
46992
+ const headerG = g.append("g").attr("class", "tl-lane-header").attr("data-group", lane.name).style("cursor", "pointer").on("mouseenter", () => fadeToGroup(g, lane.name)).on("mouseleave", () => fadeReset(g)).on("click", () => {
46993
+ if (onClickItem && group?.lineNumber) onClickItem(group.lineNumber);
46994
+ });
46995
+ headerG.append("text").attr("x", -margin.left + 10).attr("y", curY + laneSpan / 2).attr("dy", "0.35em").attr("text-anchor", "start").attr("fill", laneColor).attr("font-size", "12px").attr("font-weight", "600").text(lane.name);
46996
+ lane.events.forEach((ev, i) => {
46997
+ const y = curY + i * rowH + rowH / 2;
46998
+ const x = xScale(parseTimelineDate(ev.date));
46999
+ const evG = g.append("g").attr("class", "tl-event").attr("data-group", lane.name).attr("data-line-number", String(ev.lineNumber)).attr("data-date", String(parseTimelineDate(ev.date))).attr(
47000
+ "data-end-date",
47001
+ ev.endDate ? String(parseTimelineDate(ev.endDate)) : null
47002
+ ).style("cursor", "pointer").on("mouseenter", function(event) {
47003
+ fadeToGroup(g, lane.name);
47004
+ if (timelineScale) {
47005
+ showEventDatesOnScale(
47006
+ g,
47007
+ xScale,
47008
+ ev.date,
47009
+ ev.endDate,
47010
+ innerHeight,
47011
+ laneColor
47012
+ );
47013
+ } else {
46674
47014
  showTooltip(tooltip, buildEventTooltipHtml(ev), event);
46675
- }).on("mouseleave", function() {
46676
- fadeReset(g);
47015
+ }
47016
+ }).on("mouseleave", function() {
47017
+ fadeReset(g);
47018
+ if (timelineScale) {
47019
+ hideEventDatesOnScale(g);
47020
+ } else {
46677
47021
  hideTooltip(tooltip);
46678
- }).on("mousemove", function(event) {
47022
+ }
47023
+ }).on("mousemove", function(event) {
47024
+ if (!timelineScale) {
46679
47025
  showTooltip(tooltip, buildEventTooltipHtml(ev), event);
46680
- }).on("click", () => {
46681
- if (onClickItem && ev.lineNumber) onClickItem(ev.lineNumber);
46682
- });
46683
- setTagAttrs(evG, ev);
46684
- if (ev.endDate) {
46685
- const y2 = yScale(parseTimelineDate(ev.endDate));
46686
- const rectH = Math.max(y2 - y, 4);
46687
- let fill2 = shapeFill(palette, color, isDark, { solid });
46688
- let stroke2 = color;
46689
- if (ev.uncertain) {
46690
- const gradientId = `uncertain-v-${ev.lineNumber}`;
46691
- const strokeGradientId = `uncertain-v-s-${ev.lineNumber}`;
46692
- const defs = svg.select("defs").node() || svg.append("defs").node();
46693
- const defsEl = d3Selection22.select(defs);
46694
- defsEl.append("linearGradient").attr("id", gradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "0%").attr("y2", "100%").selectAll("stop").data([
46695
- { offset: "0%", opacity: 1 },
46696
- { offset: "80%", opacity: 1 },
46697
- { offset: "100%", opacity: 0 }
46698
- ]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", mix(color, bg, 30)).attr("stop-opacity", (d) => d.opacity);
46699
- defsEl.append("linearGradient").attr("id", strokeGradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "0%").attr("y2", "100%").selectAll("stop").data([
46700
- { offset: "0%", opacity: 1 },
46701
- { offset: "80%", opacity: 1 },
46702
- { offset: "100%", opacity: 0 }
46703
- ]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", color).attr("stop-opacity", (d) => d.opacity);
46704
- fill2 = `url(#${gradientId})`;
46705
- stroke2 = `url(#${strokeGradientId})`;
46706
- }
46707
- evG.append("rect").attr("x", axisX - 6).attr("y", y).attr("width", 12).attr("height", rectH).attr("rx", 4).attr("fill", fill2).attr("stroke", stroke2).attr("stroke-width", 2);
46708
- evG.append("text").attr("x", axisX + 16).attr("y", y + rectH / 2).attr("dy", "0.35em").attr("fill", textColor).attr("font-size", "11px").text(ev.label);
47026
+ }
47027
+ }).on("click", () => {
47028
+ if (onClickItem && ev.lineNumber) onClickItem(ev.lineNumber);
47029
+ });
47030
+ setTagAttrs(evG, ev);
47031
+ const evColor = eventColor(ev);
47032
+ if (ev.endDate) {
47033
+ const x2 = xScale(parseTimelineDate(ev.endDate));
47034
+ const rectW = Math.max(x2 - x, 4);
47035
+ const estLabelWidth = ev.label.length * 7 + 16;
47036
+ const labelFitsInside = rectW >= estLabelWidth;
47037
+ let fill2 = shapeFill(palette, evColor, isDark, { solid });
47038
+ let stroke2 = evColor;
47039
+ if (ev.uncertain) {
47040
+ const gradientId = `uncertain-${ev.lineNumber}`;
47041
+ const strokeGradientId = `uncertain-s-${ev.lineNumber}`;
47042
+ const defs = svg.select("defs").node() || svg.append("defs").node();
47043
+ const defsEl = d3Selection22.select(defs);
47044
+ defsEl.append("linearGradient").attr("id", gradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "100%").attr("y2", "0%").selectAll("stop").data([
47045
+ { offset: "0%", opacity: 1 },
47046
+ { offset: "80%", opacity: 1 },
47047
+ { offset: "100%", opacity: 0 }
47048
+ ]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", mix(evColor, bg, 30)).attr("stop-opacity", (d) => d.opacity);
47049
+ defsEl.append("linearGradient").attr("id", strokeGradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "100%").attr("y2", "0%").selectAll("stop").data([
47050
+ { offset: "0%", opacity: 1 },
47051
+ { offset: "80%", opacity: 1 },
47052
+ { offset: "100%", opacity: 0 }
47053
+ ]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", evColor).attr("stop-opacity", (d) => d.opacity);
47054
+ fill2 = `url(#${gradientId})`;
47055
+ stroke2 = `url(#${strokeGradientId})`;
47056
+ }
47057
+ evG.append("rect").attr("x", x).attr("y", y - BAR_H2 / 2).attr("width", rectW).attr("height", BAR_H2).attr("rx", 4).attr("fill", fill2).attr("stroke", stroke2).attr("stroke-width", 2);
47058
+ if (labelFitsInside) {
47059
+ evG.append("text").attr("x", x + 8).attr("y", y).attr("dy", "0.35em").attr("text-anchor", "start").attr("fill", textColor).attr("font-size", "13px").text(ev.label);
46709
47060
  } else {
46710
- evG.append("circle").attr("cx", axisX).attr("cy", y).attr("r", 4).attr("fill", shapeFill(palette, color, isDark, { solid })).attr("stroke", color).attr("stroke-width", 2);
46711
- evG.append("text").attr("x", axisX + 16).attr("y", y).attr("dy", "0.35em").attr("fill", textColor).attr("font-size", "11px").text(ev.label);
47061
+ const wouldFlipLeft = x + rectW > innerWidth * 0.6;
47062
+ const labelFitsLeft = x - 6 - estLabelWidth > 0;
47063
+ const flipLeft = wouldFlipLeft && labelFitsLeft;
47064
+ evG.append("text").attr("x", flipLeft ? x - 6 : x + rectW + 6).attr("y", y).attr("dy", "0.35em").attr("text-anchor", flipLeft ? "end" : "start").attr("fill", textColor).attr("font-size", "13px").text(ev.label);
46712
47065
  }
46713
- evG.append("text").attr("x", axisX - 14).attr(
46714
- "y",
46715
- ev.endDate ? yScale(parseTimelineDate(ev.date)) + Math.max(
46716
- yScale(parseTimelineDate(ev.endDate)) - yScale(parseTimelineDate(ev.date)),
46717
- 4
46718
- ) / 2 : y
46719
- ).attr("dy", "0.35em").attr("text-anchor", "end").attr("fill", mutedColor).attr("font-size", "10px").text(ev.date + (ev.endDate ? `\u2192${ev.endDate}` : ""));
47066
+ } else {
47067
+ const estLabelWidth = ev.label.length * 7;
47068
+ const wouldFlipLeft = x > innerWidth * 0.6;
47069
+ const labelFitsLeft = x - 10 - estLabelWidth > 0;
47070
+ const flipLeft = wouldFlipLeft && labelFitsLeft;
47071
+ evG.append("circle").attr("cx", x).attr("cy", y).attr("r", 5).attr("fill", shapeFill(palette, evColor, isDark, { solid })).attr("stroke", evColor).attr("stroke-width", 2);
47072
+ evG.append("text").attr("x", flipLeft ? x - 10 : x + 10).attr("y", y).attr("dy", "0.35em").attr("text-anchor", flipLeft ? "end" : "start").attr("fill", textColor).attr("font-size", "12px").text(ev.label);
46720
47073
  }
46721
- }
46722
- return;
47074
+ });
47075
+ curY += laneSpan + GROUP_GAP3;
46723
47076
  }
46724
- const BAR_H2 = 22;
46725
- const GROUP_GAP3 = 12;
46726
- const useGroupedHorizontal = tagLanes != null || timelineSort === "group" && timelineGroups.length > 0;
46727
- if (useGroupedHorizontal) {
46728
- let lanes;
47077
+ }
47078
+ function renderTimelineVertical(container, parsed, palette, isDark, setup, hovers, onClickItem, exportDims, _swimlaneTagGroup, _activeTagGroup, _onTagStateChange, _viewMode) {
47079
+ const {
47080
+ width,
47081
+ height,
47082
+ tooltip,
47083
+ solid,
47084
+ textColor,
47085
+ mutedColor,
47086
+ bgColor,
47087
+ bg,
47088
+ groupColorMap,
47089
+ tagLanes,
47090
+ eventColor,
47091
+ minDate,
47092
+ maxDate,
47093
+ datePadding,
47094
+ earliestStartDateStr,
47095
+ latestEndDateStr,
47096
+ tagLegendReserve
47097
+ } = setup;
47098
+ const { fadeToGroup, fadeToEra, fadeToMarker, fadeReset, setTagAttrs } = hovers;
47099
+ const {
47100
+ timelineEvents,
47101
+ timelineGroups,
47102
+ timelineEras,
47103
+ timelineMarkers,
47104
+ timelineSort,
47105
+ timelineScale,
47106
+ timelineSwimlanes
47107
+ } = parsed;
47108
+ const title = parsed.noTitle ? null : parsed.title;
47109
+ const useGroupedVertical = tagLanes != null || timelineSort === "group" && timelineGroups.length > 0;
47110
+ if (useGroupedVertical) {
47111
+ let laneNames;
47112
+ let laneEventsByName;
46729
47113
  if (tagLanes) {
46730
- lanes = tagLanes;
47114
+ laneNames = tagLanes.map((l) => l.name);
47115
+ laneEventsByName = new Map(tagLanes.map((l) => [l.name, l.events]));
46731
47116
  } else {
46732
47117
  const groupNames = timelineGroups.map((gr) => gr.name);
46733
47118
  const ungroupedEvents = timelineEvents.filter(
46734
47119
  (ev) => ev.group === null || !groupNames.includes(ev.group)
46735
47120
  );
46736
- const laneNames = ungroupedEvents.length > 0 ? [...groupNames, "(Other)"] : groupNames;
46737
- lanes = laneNames.map((name) => ({
46738
- name,
46739
- events: timelineEvents.filter(
46740
- (ev) => name === "(Other)" ? ev.group === null || !groupNames.includes(ev.group) : ev.group === name
46741
- )
46742
- }));
47121
+ laneNames = ungroupedEvents.length > 0 ? [...groupNames, "(Other)"] : groupNames;
47122
+ laneEventsByName = new Map(
47123
+ laneNames.map((name) => [
47124
+ name,
47125
+ timelineEvents.filter(
47126
+ (ev) => name === "(Other)" ? ev.group === null || !groupNames.includes(ev.group) : ev.group === name
47127
+ )
47128
+ ])
47129
+ );
46743
47130
  }
46744
- const totalEventRows = lanes.reduce((s, l) => s + l.events.length, 0);
46745
- const scaleMargin = timelineScale ? 24 : 0;
46746
- const ERA_ROW_H = 22;
46747
- const MARKER_ROW_H = 22;
46748
- const eraReserve = timelineEras.length > 0 ? ERA_ROW_H : 0;
46749
- const markerReserve = timelineMarkers.length > 0 ? MARKER_ROW_H : 0;
46750
- const topScaleH = timelineScale ? 40 : 0;
46751
- const maxGroupNameLen = Math.max(...lanes.map((l) => l.name.length));
46752
- const dynamicLeftMargin = Math.max(120, maxGroupNameLen * 7 + 30);
46753
- const baseTopMargin = title ? 50 : 20;
47131
+ const laneCount = laneNames.length;
47132
+ const scaleMargin = timelineScale ? 40 : 0;
47133
+ const markerMargin = timelineMarkers.length > 0 ? 30 : 0;
46754
47134
  const margin = {
46755
- top: baseTopMargin + topScaleH + eraReserve + markerReserve + tagLegendReserve,
46756
- right: 40,
46757
- bottom: 40 + scaleMargin,
46758
- left: dynamicLeftMargin
47135
+ top: 104 + markerMargin + tagLegendReserve,
47136
+ right: 40 + scaleMargin,
47137
+ bottom: 40,
47138
+ left: 60 + scaleMargin
46759
47139
  };
46760
- const markerLabelY = markerReserve ? -(topScaleH + MARKER_ROW_H / 2) : 0;
46761
- const eraLabelY = eraReserve ? -(topScaleH + markerReserve + ERA_ROW_H / 2) : 0;
46762
47140
  const innerWidth = width - margin.left - margin.right;
46763
47141
  const innerHeight = height - margin.top - margin.bottom;
46764
- const totalGaps = (lanes.length - 1) * GROUP_GAP3;
46765
- const rowH = Math.min(28, (innerHeight - totalGaps) / totalEventRows);
46766
- const xScale = d3Scale2.scaleLinear().domain([minDate - datePadding, maxDate + datePadding]).range([0, innerWidth]);
46767
- const svg = d3Selection22.select(container).append("svg").attr("width", width).attr("height", height).style("background", bgColor);
47142
+ const laneWidth = innerWidth / laneCount;
47143
+ const yScale = d3Scale2.scaleLinear().domain([minDate - datePadding, maxDate + datePadding]).range([0, innerHeight]);
47144
+ const svg = d3Selection22.select(container).append("svg").attr("viewBox", `0 0 ${width} ${height}`).attr("width", exportDims ? width : "100%").attr("preserveAspectRatio", "xMidYMin meet").style("background", bgColor);
46768
47145
  const g = svg.append("g").attr("transform", `translate(${margin.left},${margin.top})`);
46769
47146
  renderChartTitle(
46770
47147
  svg,
@@ -46777,36 +47154,34 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
46777
47154
  renderEras(
46778
47155
  g,
46779
47156
  timelineEras,
46780
- xScale,
46781
- false,
47157
+ yScale,
47158
+ true,
46782
47159
  innerWidth,
46783
47160
  innerHeight,
46784
47161
  (s, e) => fadeToEra(g, s, e),
46785
47162
  () => fadeReset(g),
46786
47163
  timelineScale,
46787
47164
  tooltip,
46788
- palette,
46789
- eraReserve ? eraLabelY : void 0
47165
+ palette
46790
47166
  );
46791
47167
  renderMarkers(
46792
47168
  g,
46793
47169
  timelineMarkers,
46794
- xScale,
46795
- false,
47170
+ yScale,
47171
+ true,
46796
47172
  innerWidth,
46797
47173
  innerHeight,
46798
47174
  (d) => fadeToMarker(g, d),
46799
47175
  () => fadeReset(g),
46800
47176
  timelineScale,
46801
47177
  tooltip,
46802
- palette,
46803
- markerReserve ? markerLabelY : void 0
47178
+ palette
46804
47179
  );
46805
47180
  if (timelineScale) {
46806
47181
  renderTimeScale(
46807
47182
  g,
46808
- xScale,
46809
- false,
47183
+ yScale,
47184
+ true,
46810
47185
  innerWidth,
46811
47186
  innerHeight,
46812
47187
  textColor,
@@ -46816,78 +47191,55 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
46816
47191
  formatBoundaryLabel(latestEndDateStr, earliestStartDateStr)
46817
47192
  );
46818
47193
  }
46819
- let curY = 0;
46820
47194
  if (timelineSwimlanes || tagLanes) {
46821
- let swimY = 0;
46822
- lanes.forEach((lane, idx) => {
46823
- const laneSpan = lane.events.length * rowH;
46824
- const fillColor = idx % 2 === 0 ? textColor : "transparent";
46825
- g.append("rect").attr("class", "tl-swimlane").attr("data-group", lane.name).attr("x", -margin.left).attr("y", swimY).attr("width", innerWidth + margin.left).attr("height", laneSpan + (idx < lanes.length - 1 ? GROUP_GAP3 : 0)).attr("fill", fillColor).attr("opacity", 0.06);
46826
- swimY += laneSpan + GROUP_GAP3;
47195
+ laneNames.forEach((laneName, laneIdx) => {
47196
+ const laneX = laneIdx * laneWidth;
47197
+ const fillColor = laneIdx % 2 === 0 ? textColor : "transparent";
47198
+ g.append("rect").attr("class", "tl-swimlane").attr("data-group", laneName).attr("x", laneX).attr("y", 0).attr("width", laneWidth).attr("height", innerHeight).attr("fill", fillColor).attr("opacity", 0.06);
46827
47199
  });
46828
47200
  }
46829
- for (const lane of lanes) {
46830
- const laneColor = groupColorMap.get(lane.name) ?? textColor;
46831
- const laneSpan = lane.events.length * rowH;
46832
- const group = timelineGroups.find((grp) => grp.name === lane.name);
46833
- const headerG = g.append("g").attr("class", "tl-lane-header").attr("data-group", lane.name).style("cursor", "pointer").on("mouseenter", () => fadeToGroup(g, lane.name)).on("mouseleave", () => fadeReset(g)).on("click", () => {
46834
- if (onClickItem && group?.lineNumber) onClickItem(group.lineNumber);
46835
- });
46836
- headerG.append("text").attr("x", -margin.left + 10).attr("y", curY + laneSpan / 2).attr("dy", "0.35em").attr("text-anchor", "start").attr("fill", laneColor).attr("font-size", "12px").attr("font-weight", "600").text(lane.name);
46837
- lane.events.forEach((ev, i) => {
46838
- const y = curY + i * rowH + rowH / 2;
46839
- const x = xScale(parseTimelineDate(ev.date));
46840
- const evG = g.append("g").attr("class", "tl-event").attr("data-group", lane.name).attr("data-line-number", String(ev.lineNumber)).attr("data-date", String(parseTimelineDate(ev.date))).attr(
47201
+ laneNames.forEach((laneName, laneIdx) => {
47202
+ const laneX = laneIdx * laneWidth;
47203
+ const laneColor = groupColorMap.get(laneName) ?? textColor;
47204
+ const laneCenter = laneX + laneWidth / 2;
47205
+ const headerG = g.append("g").attr("class", "tl-lane-header").attr("data-group", laneName).style("cursor", "pointer").on("mouseenter", () => fadeToGroup(g, laneName)).on("mouseleave", () => fadeReset(g));
47206
+ headerG.append("text").attr("x", laneCenter).attr("y", -15).attr("text-anchor", "middle").attr("fill", laneColor).attr("font-size", "12px").attr("font-weight", "600").text(laneName);
47207
+ g.append("line").attr("x1", laneCenter).attr("y1", 0).attr("x2", laneCenter).attr("y2", innerHeight).attr("stroke", mutedColor).attr("stroke-width", 1).attr("stroke-dasharray", "4,4");
47208
+ const laneEvents = laneEventsByName.get(laneName) ?? [];
47209
+ for (const ev of laneEvents) {
47210
+ const y = yScale(parseTimelineDate(ev.date));
47211
+ const evG = g.append("g").attr("class", "tl-event").attr("data-group", laneName).attr("data-line-number", String(ev.lineNumber)).attr("data-date", String(parseTimelineDate(ev.date))).attr(
46841
47212
  "data-end-date",
46842
47213
  ev.endDate ? String(parseTimelineDate(ev.endDate)) : null
46843
47214
  ).style("cursor", "pointer").on("mouseenter", function(event) {
46844
- fadeToGroup(g, lane.name);
46845
- if (timelineScale) {
46846
- showEventDatesOnScale(
46847
- g,
46848
- xScale,
46849
- ev.date,
46850
- ev.endDate,
46851
- innerHeight,
46852
- laneColor
46853
- );
46854
- } else {
46855
- showTooltip(tooltip, buildEventTooltipHtml(ev), event);
46856
- }
47215
+ fadeToGroup(g, laneName);
47216
+ showTooltip(tooltip, buildEventTooltipHtml(ev), event);
46857
47217
  }).on("mouseleave", function() {
46858
47218
  fadeReset(g);
46859
- if (timelineScale) {
46860
- hideEventDatesOnScale(g);
46861
- } else {
46862
- hideTooltip(tooltip);
46863
- }
47219
+ hideTooltip(tooltip);
46864
47220
  }).on("mousemove", function(event) {
46865
- if (!timelineScale) {
46866
- showTooltip(tooltip, buildEventTooltipHtml(ev), event);
46867
- }
47221
+ showTooltip(tooltip, buildEventTooltipHtml(ev), event);
46868
47222
  }).on("click", () => {
46869
47223
  if (onClickItem && ev.lineNumber) onClickItem(ev.lineNumber);
46870
47224
  });
46871
47225
  setTagAttrs(evG, ev);
46872
47226
  const evColor = eventColor(ev);
46873
47227
  if (ev.endDate) {
46874
- const x2 = xScale(parseTimelineDate(ev.endDate));
46875
- const rectW = Math.max(x2 - x, 4);
46876
- const estLabelWidth = ev.label.length * 7 + 16;
46877
- const labelFitsInside = rectW >= estLabelWidth;
47228
+ const y2 = yScale(parseTimelineDate(ev.endDate));
47229
+ const rectH = Math.max(y2 - y, 4);
46878
47230
  let fill2 = shapeFill(palette, evColor, isDark, { solid });
46879
47231
  let stroke2 = evColor;
46880
47232
  if (ev.uncertain) {
46881
- const gradientId = `uncertain-${ev.lineNumber}`;
46882
- const strokeGradientId = `uncertain-s-${ev.lineNumber}`;
47233
+ const gradientId = `uncertain-vg-${ev.lineNumber}`;
47234
+ const strokeGradientId = `uncertain-vg-s-${ev.lineNumber}`;
46883
47235
  const defs = svg.select("defs").node() || svg.append("defs").node();
46884
47236
  const defsEl = d3Selection22.select(defs);
46885
- defsEl.append("linearGradient").attr("id", gradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "100%").attr("y2", "0%").selectAll("stop").data([
47237
+ defsEl.append("linearGradient").attr("id", gradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "0%").attr("y2", "100%").selectAll("stop").data([
46886
47238
  { offset: "0%", opacity: 1 },
46887
47239
  { offset: "80%", opacity: 1 },
46888
47240
  { offset: "100%", opacity: 0 }
46889
- ]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", mix(evColor, bg, 30)).attr("stop-opacity", (d) => d.opacity);
46890
- defsEl.append("linearGradient").attr("id", strokeGradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "100%").attr("y2", "0%").selectAll("stop").data([
47241
+ ]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", mix(laneColor, bg, 30)).attr("stop-opacity", (d) => d.opacity);
47242
+ defsEl.append("linearGradient").attr("id", strokeGradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "0%").attr("y2", "100%").selectAll("stop").data([
46891
47243
  { offset: "0%", opacity: 1 },
46892
47244
  { offset: "80%", opacity: 1 },
46893
47245
  { offset: "100%", opacity: 0 }
@@ -46895,47 +47247,29 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
46895
47247
  fill2 = `url(#${gradientId})`;
46896
47248
  stroke2 = `url(#${strokeGradientId})`;
46897
47249
  }
46898
- evG.append("rect").attr("x", x).attr("y", y - BAR_H2 / 2).attr("width", rectW).attr("height", BAR_H2).attr("rx", 4).attr("fill", fill2).attr("stroke", stroke2).attr("stroke-width", 2);
46899
- if (labelFitsInside) {
46900
- evG.append("text").attr("x", x + 8).attr("y", y).attr("dy", "0.35em").attr("text-anchor", "start").attr("fill", textColor).attr("font-size", "13px").text(ev.label);
46901
- } else {
46902
- const wouldFlipLeft = x + rectW > innerWidth * 0.6;
46903
- const labelFitsLeft = x - 6 - estLabelWidth > 0;
46904
- const flipLeft = wouldFlipLeft && labelFitsLeft;
46905
- evG.append("text").attr("x", flipLeft ? x - 6 : x + rectW + 6).attr("y", y).attr("dy", "0.35em").attr("text-anchor", flipLeft ? "end" : "start").attr("fill", textColor).attr("font-size", "13px").text(ev.label);
46906
- }
47250
+ evG.append("rect").attr("x", laneCenter - 6).attr("y", y).attr("width", 12).attr("height", rectH).attr("rx", 4).attr("fill", fill2).attr("stroke", stroke2).attr("stroke-width", 2);
47251
+ evG.append("text").attr("x", laneCenter + 14).attr("y", y + rectH / 2).attr("dy", "0.35em").attr("fill", textColor).attr("font-size", "10px").text(ev.label);
46907
47252
  } else {
46908
- const estLabelWidth = ev.label.length * 7;
46909
- const wouldFlipLeft = x > innerWidth * 0.6;
46910
- const labelFitsLeft = x - 10 - estLabelWidth > 0;
46911
- const flipLeft = wouldFlipLeft && labelFitsLeft;
46912
- evG.append("circle").attr("cx", x).attr("cy", y).attr("r", 5).attr("fill", shapeFill(palette, evColor, isDark, { solid })).attr("stroke", evColor).attr("stroke-width", 2);
46913
- evG.append("text").attr("x", flipLeft ? x - 10 : x + 10).attr("y", y).attr("dy", "0.35em").attr("text-anchor", flipLeft ? "end" : "start").attr("fill", textColor).attr("font-size", "12px").text(ev.label);
47253
+ evG.append("circle").attr("cx", laneCenter).attr("cy", y).attr("r", 4).attr("fill", shapeFill(palette, evColor, isDark, { solid })).attr("stroke", evColor).attr("stroke-width", 2);
47254
+ evG.append("text").attr("x", laneCenter + 10).attr("y", y).attr("dy", "0.35em").attr("fill", textColor).attr("font-size", "10px").text(ev.label);
46914
47255
  }
46915
- });
46916
- curY += laneSpan + GROUP_GAP3;
46917
- }
47256
+ }
47257
+ });
46918
47258
  } else {
46919
- const sorted = timelineEvents.slice().sort((a, b) => parseTimelineDate(a.date) - parseTimelineDate(b.date));
46920
- const scaleMargin = timelineScale ? 24 : 0;
46921
- const ERA_ROW_H = 22;
46922
- const MARKER_ROW_H = 22;
46923
- const eraReserve = timelineEras.length > 0 ? ERA_ROW_H : 0;
46924
- const markerReserve = timelineMarkers.length > 0 ? MARKER_ROW_H : 0;
46925
- const topScaleH = timelineScale ? 40 : 0;
47259
+ const scaleMargin = timelineScale ? 40 : 0;
47260
+ const markerMargin = timelineMarkers.length > 0 ? 30 : 0;
46926
47261
  const margin = {
46927
- top: 104 + topScaleH + eraReserve + markerReserve + tagLegendReserve,
46928
- right: 40,
46929
- bottom: 40 + scaleMargin,
46930
- left: 60
47262
+ top: 104 + markerMargin + tagLegendReserve,
47263
+ right: 200,
47264
+ bottom: 40,
47265
+ left: 60 + scaleMargin
46931
47266
  };
46932
- const markerLabelY = markerReserve ? -(topScaleH + MARKER_ROW_H / 2) : 0;
46933
- const eraLabelY = eraReserve ? -(topScaleH + markerReserve + ERA_ROW_H / 2) : 0;
46934
47267
  const innerWidth = width - margin.left - margin.right;
46935
47268
  const innerHeight = height - margin.top - margin.bottom;
46936
- const rowH = Math.min(28, innerHeight / sorted.length);
46937
- const xScale = d3Scale2.scaleLinear().domain([minDate - datePadding, maxDate + datePadding]).range([0, innerWidth]);
46938
- const svg = d3Selection22.select(container).append("svg").attr("width", width).attr("height", height).style("background", bgColor);
47269
+ const axisX = 20;
47270
+ const yScale = d3Scale2.scaleLinear().domain([minDate - datePadding, maxDate + datePadding]).range([0, innerHeight]);
47271
+ const sorted = timelineEvents.slice().sort((a, b) => parseTimelineDate(a.date) - parseTimelineDate(b.date));
47272
+ const svg = d3Selection22.select(container).append("svg").attr("viewBox", `0 0 ${width} ${height}`).attr("width", exportDims ? width : "100%").attr("preserveAspectRatio", "xMidYMin meet").style("background", bgColor);
46939
47273
  const g = svg.append("g").attr("transform", `translate(${margin.left},${margin.top})`);
46940
47274
  renderChartTitle(
46941
47275
  svg,
@@ -46948,36 +47282,34 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
46948
47282
  renderEras(
46949
47283
  g,
46950
47284
  timelineEras,
46951
- xScale,
46952
- false,
47285
+ yScale,
47286
+ true,
46953
47287
  innerWidth,
46954
47288
  innerHeight,
46955
47289
  (s, e) => fadeToEra(g, s, e),
46956
47290
  () => fadeReset(g),
46957
47291
  timelineScale,
46958
47292
  tooltip,
46959
- palette,
46960
- eraReserve ? eraLabelY : void 0
47293
+ palette
46961
47294
  );
46962
47295
  renderMarkers(
46963
47296
  g,
46964
47297
  timelineMarkers,
46965
- xScale,
46966
- false,
47298
+ yScale,
47299
+ true,
46967
47300
  innerWidth,
46968
47301
  innerHeight,
46969
47302
  (d) => fadeToMarker(g, d),
46970
47303
  () => fadeReset(g),
46971
47304
  timelineScale,
46972
47305
  tooltip,
46973
- palette,
46974
- markerReserve ? markerLabelY : void 0
47306
+ palette
46975
47307
  );
46976
47308
  if (timelineScale) {
46977
47309
  renderTimeScale(
46978
47310
  g,
46979
- xScale,
46980
- false,
47311
+ yScale,
47312
+ true,
46981
47313
  innerWidth,
46982
47314
  innerHeight,
46983
47315
  textColor,
@@ -46988,7 +47320,6 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
46988
47320
  );
46989
47321
  }
46990
47322
  if (timelineGroups.length > 0) {
46991
- const legendY = timelineScale ? -75 : -55;
46992
47323
  renderTimelineGroupLegend(
46993
47324
  g,
46994
47325
  timelineGroups,
@@ -46996,65 +47327,46 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
46996
47327
  textColor,
46997
47328
  palette,
46998
47329
  isDark,
46999
- legendY,
47330
+ -55,
47000
47331
  (name) => fadeToGroup(g, name),
47001
47332
  () => fadeReset(g)
47002
47333
  );
47003
47334
  }
47004
- sorted.forEach((ev, i) => {
47005
- const y = i * rowH + rowH / 2;
47006
- const x = xScale(parseTimelineDate(ev.date));
47335
+ g.append("line").attr("x1", axisX).attr("y1", 0).attr("x2", axisX).attr("y2", innerHeight).attr("stroke", mutedColor).attr("stroke-width", 1).attr("stroke-dasharray", "4,4");
47336
+ for (const ev of sorted) {
47337
+ const y = yScale(parseTimelineDate(ev.date));
47007
47338
  const color = eventColor(ev);
47008
47339
  const evG = g.append("g").attr("class", "tl-event").attr("data-group", ev.group || "").attr("data-line-number", String(ev.lineNumber)).attr("data-date", String(parseTimelineDate(ev.date))).attr(
47009
47340
  "data-end-date",
47010
47341
  ev.endDate ? String(parseTimelineDate(ev.endDate)) : null
47011
47342
  ).style("cursor", "pointer").on("mouseenter", function(event) {
47012
47343
  if (ev.group && timelineGroups.length > 0) fadeToGroup(g, ev.group);
47013
- if (timelineScale) {
47014
- showEventDatesOnScale(
47015
- g,
47016
- xScale,
47017
- ev.date,
47018
- ev.endDate,
47019
- innerHeight,
47020
- color
47021
- );
47022
- } else {
47023
- showTooltip(tooltip, buildEventTooltipHtml(ev), event);
47024
- }
47344
+ showTooltip(tooltip, buildEventTooltipHtml(ev), event);
47025
47345
  }).on("mouseleave", function() {
47026
47346
  fadeReset(g);
47027
- if (timelineScale) {
47028
- hideEventDatesOnScale(g);
47029
- } else {
47030
- hideTooltip(tooltip);
47031
- }
47347
+ hideTooltip(tooltip);
47032
47348
  }).on("mousemove", function(event) {
47033
- if (!timelineScale) {
47034
- showTooltip(tooltip, buildEventTooltipHtml(ev), event);
47035
- }
47349
+ showTooltip(tooltip, buildEventTooltipHtml(ev), event);
47036
47350
  }).on("click", () => {
47037
47351
  if (onClickItem && ev.lineNumber) onClickItem(ev.lineNumber);
47038
47352
  });
47039
47353
  setTagAttrs(evG, ev);
47040
47354
  if (ev.endDate) {
47041
- const x2 = xScale(parseTimelineDate(ev.endDate));
47042
- const rectW = Math.max(x2 - x, 4);
47043
- const estLabelWidth = ev.label.length * 7 + 16;
47044
- const labelFitsInside = rectW >= estLabelWidth;
47355
+ const y2 = yScale(parseTimelineDate(ev.endDate));
47356
+ const rectH = Math.max(y2 - y, 4);
47045
47357
  let fill2 = shapeFill(palette, color, isDark, { solid });
47046
47358
  let stroke2 = color;
47047
47359
  if (ev.uncertain) {
47048
- const gradientId = `uncertain-ts-${ev.lineNumber}`;
47049
- const strokeGradientId = `uncertain-ts-s-${ev.lineNumber}`;
47360
+ const gradientId = `uncertain-v-${ev.lineNumber}`;
47361
+ const strokeGradientId = `uncertain-v-s-${ev.lineNumber}`;
47050
47362
  const defs = svg.select("defs").node() || svg.append("defs").node();
47051
47363
  const defsEl = d3Selection22.select(defs);
47052
- defsEl.append("linearGradient").attr("id", gradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "100%").attr("y2", "0%").selectAll("stop").data([
47364
+ defsEl.append("linearGradient").attr("id", gradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "0%").attr("y2", "100%").selectAll("stop").data([
47053
47365
  { offset: "0%", opacity: 1 },
47054
47366
  { offset: "80%", opacity: 1 },
47055
47367
  { offset: "100%", opacity: 0 }
47056
47368
  ]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", mix(color, bg, 30)).attr("stop-opacity", (d) => d.opacity);
47057
- defsEl.append("linearGradient").attr("id", strokeGradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "100%").attr("y2", "0%").selectAll("stop").data([
47369
+ defsEl.append("linearGradient").attr("id", strokeGradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "0%").attr("y2", "100%").selectAll("stop").data([
47058
47370
  { offset: "0%", opacity: 1 },
47059
47371
  { offset: "80%", opacity: 1 },
47060
47372
  { offset: "100%", opacity: 0 }
@@ -47062,206 +47374,100 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
47062
47374
  fill2 = `url(#${gradientId})`;
47063
47375
  stroke2 = `url(#${strokeGradientId})`;
47064
47376
  }
47065
- evG.append("rect").attr("x", x).attr("y", y - BAR_H2 / 2).attr("width", rectW).attr("height", BAR_H2).attr("rx", 4).attr("fill", fill2).attr("stroke", stroke2).attr("stroke-width", 2);
47066
- if (labelFitsInside) {
47067
- evG.append("text").attr("x", x + 8).attr("y", y).attr("dy", "0.35em").attr("text-anchor", "start").attr("fill", textColor).attr("font-size", "13px").text(ev.label);
47068
- } else {
47069
- const wouldFlipLeft = x + rectW > innerWidth * 0.6;
47070
- const labelFitsLeft = x - 6 - estLabelWidth > 0;
47071
- const flipLeft = wouldFlipLeft && labelFitsLeft;
47072
- evG.append("text").attr("x", flipLeft ? x - 6 : x + rectW + 6).attr("y", y).attr("dy", "0.35em").attr("text-anchor", flipLeft ? "end" : "start").attr("fill", textColor).attr("font-size", "13px").text(ev.label);
47073
- }
47377
+ evG.append("rect").attr("x", axisX - 6).attr("y", y).attr("width", 12).attr("height", rectH).attr("rx", 4).attr("fill", fill2).attr("stroke", stroke2).attr("stroke-width", 2);
47378
+ evG.append("text").attr("x", axisX + 16).attr("y", y + rectH / 2).attr("dy", "0.35em").attr("fill", textColor).attr("font-size", "11px").text(ev.label);
47074
47379
  } else {
47075
- const estLabelWidth = ev.label.length * 7;
47076
- const wouldFlipLeft = x > innerWidth * 0.6;
47077
- const labelFitsLeft = x - 10 - estLabelWidth > 0;
47078
- const flipLeft = wouldFlipLeft && labelFitsLeft;
47079
- evG.append("circle").attr("cx", x).attr("cy", y).attr("r", 5).attr("fill", shapeFill(palette, color, isDark, { solid })).attr("stroke", color).attr("stroke-width", 2);
47080
- evG.append("text").attr("x", flipLeft ? x - 10 : x + 10).attr("y", y).attr("dy", "0.35em").attr("text-anchor", flipLeft ? "end" : "start").attr("fill", textColor).attr("font-size", "12px").text(ev.label);
47081
- }
47082
- });
47083
- }
47084
- if (parsed.timelineTagGroups.length > 0) {
47085
- const LG_HEIGHT = LEGEND_HEIGHT;
47086
- const LG_PILL_PAD = LEGEND_PILL_PAD;
47087
- const LG_PILL_FONT_SIZE = LEGEND_PILL_FONT_SIZE;
47088
- const LG_CAPSULE_PAD = LEGEND_CAPSULE_PAD;
47089
- const LG_DOT_R = LEGEND_DOT_R;
47090
- const LG_ENTRY_FONT_SIZE = LEGEND_ENTRY_FONT_SIZE;
47091
- const LG_ENTRY_DOT_GAP = LEGEND_ENTRY_DOT_GAP;
47092
- const LG_ENTRY_TRAIL = LEGEND_ENTRY_TRAIL;
47093
- const LG_ICON_W = 20;
47094
- const mainSvg = d3Selection22.select(container).select("svg");
47095
- const mainG = mainSvg.select("g");
47096
- if (!mainSvg.empty() && !mainG.empty()) {
47097
- let drawSwimlaneIcon4 = function(parent, x, y, isSwimActive) {
47098
- const iconG = parent.append("g").attr("class", "tl-swimlane-icon").attr("transform", `translate(${x}, ${y})`).style("cursor", "pointer");
47099
- const barColor = isSwimActive ? palette.primary : palette.textMuted;
47100
- const barOpacity = isSwimActive ? 1 : 0.35;
47101
- const bars = [
47102
- { y: 0, w: 8 },
47103
- { y: 4, w: 12 },
47104
- { y: 8, w: 6 }
47105
- ];
47106
- for (const bar of bars) {
47107
- iconG.append("rect").attr("x", 0).attr("y", bar.y).attr("width", bar.w).attr("height", 2).attr("rx", 1).attr("fill", barColor).attr("opacity", barOpacity);
47108
- }
47109
- return iconG;
47110
- }, relayout2 = function() {
47111
- renderTimeline(
47112
- container,
47113
- parsed,
47114
- palette,
47115
- isDark,
47116
- onClickItem,
47117
- exportDims,
47118
- currentActiveGroup,
47119
- currentSwimlaneGroup,
47120
- onTagStateChange,
47121
- viewMode
47122
- );
47123
- }, drawLegend2 = function() {
47124
- mainSvg.selectAll(".tl-tag-legend-group").remove();
47125
- mainSvg.selectAll(".tl-tag-legend-container").remove();
47126
- const effectiveColorKey = (currentActiveGroup ?? currentSwimlaneGroup)?.toLowerCase() ?? null;
47127
- const visibleGroups = viewMode ? legendGroups.filter(
47128
- (lg) => effectiveColorKey != null && lg.group.name.toLowerCase() === effectiveColorKey
47129
- ) : legendGroups;
47130
- if (visibleGroups.length === 0) return;
47131
- const legendContainer = mainSvg.append("g").attr("class", "tl-tag-legend-container");
47132
- if (currentActiveGroup) {
47133
- legendContainer.attr(
47134
- "data-legend-active",
47135
- currentActiveGroup.toLowerCase()
47136
- );
47137
- }
47138
- const iconAddon = viewMode ? 0 : LG_ICON_W;
47139
- const centralGroups = visibleGroups.map((lg) => ({
47140
- name: lg.group.name,
47141
- entries: lg.group.entries.map((e) => ({
47142
- value: e.value,
47143
- color: e.color
47144
- }))
47145
- }));
47146
- const centralActive = viewMode ? effectiveColorKey : currentActiveGroup;
47147
- const centralConfig = {
47148
- groups: centralGroups,
47149
- position: { placement: "top-center", titleRelation: "below-title" },
47150
- mode: "fixed",
47151
- capsulePillAddonWidth: iconAddon
47152
- };
47153
- const centralState = { activeGroup: centralActive };
47154
- const centralCallbacks = viewMode ? {} : {
47155
- onGroupToggle: (groupName) => {
47156
- currentActiveGroup = currentActiveGroup === groupName.toLowerCase() ? null : groupName.toLowerCase();
47157
- drawLegend2();
47158
- recolorEvents2();
47159
- onTagStateChange?.(currentActiveGroup, currentSwimlaneGroup);
47160
- },
47161
- onEntryHover: (groupName, entryValue) => {
47162
- const tagKey = groupName.toLowerCase();
47163
- if (entryValue) {
47164
- const tagVal = entryValue.toLowerCase();
47165
- fadeToTagValue(mainG, tagKey, tagVal);
47166
- mainSvg.selectAll("[data-legend-entry]").each(function() {
47167
- const el = d3Selection22.select(this);
47168
- const ev = el.attr("data-legend-entry");
47169
- const eg = el.attr("data-tag-group") ?? el.node()?.closest?.("[data-tag-group]")?.getAttribute("data-tag-group");
47170
- el.attr(
47171
- "opacity",
47172
- eg === tagKey && ev === tagVal ? 1 : FADE_OPACITY3
47173
- );
47174
- });
47175
- } else {
47176
- fadeReset(mainG);
47177
- mainSvg.selectAll("[data-legend-entry]").attr("opacity", 1);
47178
- }
47179
- },
47180
- onGroupRendered: (groupName, groupEl, isActive) => {
47181
- const groupKey = groupName.toLowerCase();
47182
- groupEl.attr("data-tag-group", groupKey);
47183
- if (isActive && !viewMode) {
47184
- const isSwimActive = currentSwimlaneGroup != null && currentSwimlaneGroup.toLowerCase() === groupKey;
47185
- const pillWidth3 = measureLegendText(groupName, LG_PILL_FONT_SIZE) + LG_PILL_PAD;
47186
- const pillXOff = LG_CAPSULE_PAD;
47187
- const iconX = pillXOff + pillWidth3 + 5;
47188
- const iconY = (LG_HEIGHT - 10) / 2;
47189
- const iconEl = drawSwimlaneIcon4(
47190
- groupEl,
47191
- iconX,
47192
- iconY,
47193
- isSwimActive
47194
- );
47195
- iconEl.attr("data-swimlane-toggle", groupKey).on("click", (event) => {
47196
- event.stopPropagation();
47197
- currentSwimlaneGroup = currentSwimlaneGroup === groupKey ? null : groupKey;
47198
- onTagStateChange?.(
47199
- currentActiveGroup,
47200
- currentSwimlaneGroup
47201
- );
47202
- relayout2();
47203
- });
47204
- }
47205
- }
47206
- };
47207
- const legendInnerG = legendContainer.append("g").attr("transform", `translate(0, ${legendY})`);
47208
- renderLegendD3(
47209
- legendInnerG,
47210
- centralConfig,
47211
- centralState,
47212
- palette,
47213
- isDark,
47214
- centralCallbacks,
47215
- width
47216
- );
47217
- }, recolorEvents2 = function() {
47218
- const colorTG = currentActiveGroup ?? swimlaneTagGroup ?? null;
47219
- mainG.selectAll(".tl-event").each(function() {
47220
- const el = d3Selection22.select(this);
47221
- const lineNum = el.attr("data-line-number");
47222
- const ev = lineNum ? eventByLine.get(lineNum) : void 0;
47223
- if (!ev) return;
47224
- let color;
47225
- if (colorTG) {
47226
- const tagColor = resolveTagColor(
47227
- ev.metadata,
47228
- parsed.timelineTagGroups,
47229
- colorTG
47230
- );
47231
- color = tagColor ?? (ev.group && groupColorMap.has(ev.group) ? groupColorMap.get(ev.group) : textColor);
47232
- } else {
47233
- color = ev.group && groupColorMap.has(ev.group) ? groupColorMap.get(ev.group) : textColor;
47234
- }
47235
- el.selectAll("rect").attr("fill", shapeFill(palette, color, isDark, { solid })).attr("stroke", color);
47236
- el.selectAll("circle:not(.tl-event-point-outline)").attr("fill", shapeFill(palette, color, isDark, { solid })).attr("stroke", color);
47237
- });
47238
- };
47239
- var drawSwimlaneIcon3 = drawSwimlaneIcon4, relayout = relayout2, drawLegend = drawLegend2, recolorEvents = recolorEvents2;
47240
- const legendY = title ? 50 : 10;
47241
- const legendGroups = parsed.timelineTagGroups.map((g) => {
47242
- const pillW = measureLegendText(g.name, LG_PILL_FONT_SIZE) + LG_PILL_PAD;
47243
- const iconSpace = viewMode ? 8 : LG_ICON_W + 4;
47244
- let entryX = LG_CAPSULE_PAD + pillW + iconSpace;
47245
- for (const entry of g.entries) {
47246
- const textX = entryX + LG_DOT_R * 2 + LG_ENTRY_DOT_GAP;
47247
- entryX = textX + measureLegendText(entry.value, LG_ENTRY_FONT_SIZE) + LG_ENTRY_TRAIL;
47248
- }
47249
- return {
47250
- group: g,
47251
- minifiedWidth: pillW,
47252
- expandedWidth: entryX + LG_CAPSULE_PAD
47253
- };
47254
- });
47255
- let currentActiveGroup = activeTagGroup ?? null;
47256
- let currentSwimlaneGroup = swimlaneTagGroup ?? null;
47257
- const eventByLine = /* @__PURE__ */ new Map();
47258
- for (const ev of timelineEvents) {
47259
- eventByLine.set(String(ev.lineNumber), ev);
47380
+ evG.append("circle").attr("cx", axisX).attr("cy", y).attr("r", 4).attr("fill", shapeFill(palette, color, isDark, { solid })).attr("stroke", color).attr("stroke-width", 2);
47381
+ evG.append("text").attr("x", axisX + 16).attr("y", y).attr("dy", "0.35em").attr("fill", textColor).attr("font-size", "11px").text(ev.label);
47260
47382
  }
47261
- drawLegend2();
47383
+ evG.append("text").attr("x", axisX - 14).attr(
47384
+ "y",
47385
+ ev.endDate ? yScale(parseTimelineDate(ev.date)) + Math.max(
47386
+ yScale(parseTimelineDate(ev.endDate)) - yScale(parseTimelineDate(ev.date)),
47387
+ 4
47388
+ ) / 2 : y
47389
+ ).attr("dy", "0.35em").attr("text-anchor", "end").attr("fill", mutedColor).attr("font-size", "10px").text(ev.date + (ev.endDate ? `\u2192${ev.endDate}` : ""));
47262
47390
  }
47263
47391
  }
47264
47392
  }
47393
+ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportDims, activeTagGroup, swimlaneTagGroup, onTagStateChange, viewMode) {
47394
+ const setup = setupTimeline(
47395
+ container,
47396
+ parsed,
47397
+ palette,
47398
+ isDark,
47399
+ exportDims,
47400
+ activeTagGroup,
47401
+ swimlaneTagGroup
47402
+ );
47403
+ if (!setup) return;
47404
+ swimlaneTagGroup = setup.swimlaneTagGroup;
47405
+ const { isVertical, tagLanes } = setup;
47406
+ const hovers = makeTimelineHoverHelpers();
47407
+ if (isVertical) {
47408
+ renderTimelineVertical(
47409
+ container,
47410
+ parsed,
47411
+ palette,
47412
+ isDark,
47413
+ setup,
47414
+ hovers,
47415
+ onClickItem,
47416
+ exportDims,
47417
+ swimlaneTagGroup,
47418
+ activeTagGroup,
47419
+ onTagStateChange,
47420
+ viewMode
47421
+ );
47422
+ return;
47423
+ }
47424
+ const useGroupedHorizontal = tagLanes != null || parsed.timelineSort === "group" && parsed.timelineGroups.length > 0;
47425
+ if (useGroupedHorizontal) {
47426
+ renderTimelineHorizontalGrouped(
47427
+ container,
47428
+ parsed,
47429
+ palette,
47430
+ isDark,
47431
+ setup,
47432
+ hovers,
47433
+ onClickItem,
47434
+ exportDims,
47435
+ swimlaneTagGroup,
47436
+ activeTagGroup,
47437
+ onTagStateChange,
47438
+ viewMode
47439
+ );
47440
+ } else {
47441
+ renderTimelineHorizontalTimeSort(
47442
+ container,
47443
+ parsed,
47444
+ palette,
47445
+ isDark,
47446
+ setup,
47447
+ hovers,
47448
+ onClickItem,
47449
+ exportDims,
47450
+ swimlaneTagGroup,
47451
+ activeTagGroup,
47452
+ onTagStateChange,
47453
+ viewMode
47454
+ );
47455
+ }
47456
+ renderTimelineTagLegendOverlay(
47457
+ container,
47458
+ parsed,
47459
+ palette,
47460
+ isDark,
47461
+ setup,
47462
+ hovers,
47463
+ onClickItem,
47464
+ exportDims,
47465
+ swimlaneTagGroup,
47466
+ activeTagGroup,
47467
+ onTagStateChange,
47468
+ viewMode
47469
+ );
47470
+ }
47265
47471
  function getRotateFn(mode) {
47266
47472
  if (mode === "mixed") return () => Math.random() > 0.5 ? 0 : 90;
47267
47473
  if (mode === "angled") return () => Math.round(Math.random() * 30 - 15);
@@ -47385,7 +47591,7 @@ function regionCentroid(circles, inside) {
47385
47591
  }
47386
47592
  return { x: sx / count, y: sy / count };
47387
47593
  }
47388
- function renderVenn(container, parsed, palette, isDark, onClickItem, exportDims) {
47594
+ function renderVenn(container, parsed, palette, _isDark, onClickItem, exportDims) {
47389
47595
  const { vennSets, vennOverlaps } = parsed;
47390
47596
  const title = parsed.noTitle ? null : parsed.title;
47391
47597
  if (vennSets.length < 2 || vennSets.length > 3) return;
@@ -47619,7 +47825,7 @@ function renderVenn(container, parsed, palette, isDark, onClickItem, exportDims)
47619
47825
  };
47620
47826
  const gcx = circles.reduce((s, c) => s + c.x, 0) / n;
47621
47827
  const gcy = circles.reduce((s, c) => s + c.y, 0) / n;
47622
- function exclusiveHSpan(px, py, ci) {
47828
+ function exclusiveHSpan(_px, py, ci) {
47623
47829
  const dy = py - circles[ci].y;
47624
47830
  const halfChord = Math.sqrt(
47625
47831
  Math.max(0, circles[ci].r * circles[ci].r - dy * dy)
@@ -48532,9 +48738,9 @@ async function renderForExport(content, theme, palette, viewState, options) {
48532
48738
  blHiddenTagValues.set(k, new Set(v));
48533
48739
  }
48534
48740
  }
48535
- const { layoutBoxesAndLines: layoutBoxesAndLines2 } = await Promise.resolve().then(() => (init_layout5(), layout_exports5));
48536
48741
  const { renderBoxesAndLinesForExport: renderBoxesAndLinesForExport2 } = await Promise.resolve().then(() => (init_renderer6(), renderer_exports6));
48537
- const blLayout = layoutBoxesAndLines2(blParsed);
48742
+ const { layoutBoxesAndLines: layoutBoxesAndLines2 } = await Promise.resolve().then(() => (init_layout5(), layout_exports5));
48743
+ const blLayout = await layoutBoxesAndLines2(blParsed);
48538
48744
  const PADDING3 = 20;
48539
48745
  const titleOffset = blParsed.title ? 40 : 0;
48540
48746
  const exportWidth = blLayout.width + PADDING3 * 2;
@@ -49626,6 +49832,7 @@ __export(index_exports, {
49626
49832
  decodeDiagramUrl: () => decodeDiagramUrl2,
49627
49833
  encodeDiagramUrl: () => encodeDiagramUrl2,
49628
49834
  formatDgmoError: () => formatDgmoError,
49835
+ getPalette: () => getPalette,
49629
49836
  palettes: () => palettes,
49630
49837
  render: () => render2,
49631
49838
  themes: () => themes,
@@ -49810,7 +50017,8 @@ async function render2(text, options) {
49810
50017
  const onError = options?.onError ?? "svg";
49811
50018
  const result = await render(text, {
49812
50019
  theme: options?.theme,
49813
- palette: palette.id
50020
+ palette: palette.id,
50021
+ viewState: options?.viewState
49814
50022
  });
49815
50023
  const errors = result.diagnostics.filter((d) => d.severity === "error");
49816
50024
  if (errors.length === 0) {
@@ -49850,7 +50058,8 @@ function encodeDiagramUrl2(text, options) {
49850
50058
  baseUrl: options?.baseUrl,
49851
50059
  palette: options?.palette?.id,
49852
50060
  theme: internalTheme,
49853
- filename: options?.filename
50061
+ filename: options?.filename,
50062
+ viewState: options?.viewState
49854
50063
  });
49855
50064
  return "error" in result && result.error ? null : result.url ?? null;
49856
50065
  }
@@ -49869,6 +50078,7 @@ function decodeDiagramUrl2(url) {
49869
50078
  decodeDiagramUrl,
49870
50079
  encodeDiagramUrl,
49871
50080
  formatDgmoError,
50081
+ getPalette,
49872
50082
  palettes,
49873
50083
  render,
49874
50084
  themes,