@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/internal.js CHANGED
@@ -2343,7 +2343,7 @@ function injectDefaultTagMetadata(entities, tagGroups, skip) {
2343
2343
  }
2344
2344
  }
2345
2345
  }
2346
- function resolveActiveTagGroup(_tagGroups, explicitActiveTag, programmaticOverride) {
2346
+ function resolveActiveTagGroup(tagGroups, explicitActiveTag, programmaticOverride) {
2347
2347
  if (programmaticOverride !== void 0) {
2348
2348
  if (!programmaticOverride) return null;
2349
2349
  if (programmaticOverride.toLowerCase() === "none") return null;
@@ -2353,6 +2353,7 @@ function resolveActiveTagGroup(_tagGroups, explicitActiveTag, programmaticOverri
2353
2353
  if (explicitActiveTag.toLowerCase() === "none") return null;
2354
2354
  return explicitActiveTag;
2355
2355
  }
2356
+ if (tagGroups.length > 0) return tagGroups[0].name;
2356
2357
  return null;
2357
2358
  }
2358
2359
  function matchTagBlockHeading(trimmed) {
@@ -5362,12 +5363,6 @@ function parseClassDiagram(content, palette) {
5362
5363
  diagnostics: [],
5363
5364
  error: null
5364
5365
  };
5365
- const _fail = (line12, message) => {
5366
- const diag = makeDgmoError(line12, message);
5367
- result.diagnostics.push(diag);
5368
- result.error = formatDgmoError(diag);
5369
- return result;
5370
- };
5371
5366
  const classMap = /* @__PURE__ */ new Map();
5372
5367
  const nameAliasMap = /* @__PURE__ */ new Map();
5373
5368
  function resolveAliasName(token) {
@@ -5762,12 +5757,6 @@ function parseERDiagram(content, palette) {
5762
5757
  diagnostics: [],
5763
5758
  error: null
5764
5759
  };
5765
- const _fail = (line12, message) => {
5766
- const diag = makeDgmoError(line12, message);
5767
- result.diagnostics.push(diag);
5768
- result.error = formatDgmoError(diag);
5769
- return result;
5770
- };
5771
5760
  const pushError = (line12, message) => {
5772
5761
  const diag = makeDgmoError(line12, message);
5773
5762
  result.diagnostics.push(diag);
@@ -7239,7 +7228,7 @@ function buildSankeyOption(parsed, textColor, colors, bg, titleConfig) {
7239
7228
  ]
7240
7229
  };
7241
7230
  }
7242
- function buildChordOption(parsed, palette, isDark, textColor, colors, bg, titleConfig) {
7231
+ function buildChordOption(parsed, palette, isDark, textColor, colors, _bg, titleConfig) {
7243
7232
  const nodeSet = /* @__PURE__ */ new Set();
7244
7233
  if (parsed.links) {
7245
7234
  for (const link of parsed.links) {
@@ -7353,7 +7342,7 @@ function evaluateExpression(expr, x) {
7353
7342
  return NaN;
7354
7343
  }
7355
7344
  }
7356
- function buildFunctionOption(parsed, palette, isDark, textColor, axisLineColor, gridOpacity, colors, titleConfig) {
7345
+ function buildFunctionOption(parsed, palette, _isDark, textColor, axisLineColor, gridOpacity, colors, titleConfig) {
7357
7346
  const xRange = parsed.xRange ?? { min: -10, max: 10 };
7358
7347
  const samples = 200;
7359
7348
  const step = (xRange.max - xRange.min) / samples;
@@ -8026,7 +8015,7 @@ function buildHeatmapOption(parsed, palette, isDark, textColor, axisLineColor, t
8026
8015
  ]
8027
8016
  };
8028
8017
  }
8029
- function buildFunnelOption(parsed, palette, isDark, textColor, colors, bg, titleConfig) {
8018
+ function buildFunnelOption(parsed, palette, isDark, textColor, colors, _bg, titleConfig) {
8030
8019
  const sorted = [...parsed.data].sort((a, b) => b.value - a.value);
8031
8020
  const data = sorted.map((d) => {
8032
8021
  const stroke2 = d.color ?? colors[parsed.data.indexOf(d) % colors.length];
@@ -8309,7 +8298,7 @@ function wrapLabel(text, maxChars) {
8309
8298
  if (current) lines.push(current);
8310
8299
  return lines.join("\n");
8311
8300
  }
8312
- function buildBarOption(parsed, palette, isDark, textColor, axisLineColor, splitLineColor, gridOpacity, colors, bg, titleConfig, chartWidth) {
8301
+ function buildBarOption(parsed, palette, isDark, textColor, axisLineColor, splitLineColor, gridOpacity, colors, _bg, titleConfig, chartWidth) {
8313
8302
  const { xLabel, yLabel } = resolveAxisLabels(parsed);
8314
8303
  const isHorizontal = parsed.orientation === "horizontal";
8315
8304
  const labels = parsed.data.map((d) => d.label);
@@ -8636,7 +8625,7 @@ function pieLabelLayout(parsed) {
8636
8625
  if (maxLen > 18) return { outerRadius: 55, fontSize: 13 };
8637
8626
  return { outerRadius: 70, fontSize: 14 };
8638
8627
  }
8639
- function buildPieOption(parsed, palette, isDark, textColor, colors, bg, titleConfig, isDoughnut) {
8628
+ function buildPieOption(parsed, palette, isDark, textColor, colors, _bg, titleConfig, isDoughnut) {
8640
8629
  const HIDE_AXES = { xAxis: { show: false }, yAxis: { show: false } };
8641
8630
  const data = parsed.data.map((d, i) => {
8642
8631
  const stroke2 = d.color ?? colors[i % colors.length];
@@ -8735,7 +8724,7 @@ function buildRadarOption(parsed, palette, isDark, textColor, gridOpacity, title
8735
8724
  ]
8736
8725
  };
8737
8726
  }
8738
- function buildPolarAreaOption(parsed, palette, isDark, textColor, colors, bg, titleConfig) {
8727
+ function buildPolarAreaOption(parsed, palette, isDark, textColor, colors, _bg, titleConfig) {
8739
8728
  const data = parsed.data.map((d, i) => {
8740
8729
  const stroke2 = d.color ?? colors[i % colors.length];
8741
8730
  return {
@@ -8778,7 +8767,7 @@ function buildPolarAreaOption(parsed, palette, isDark, textColor, colors, bg, ti
8778
8767
  ]
8779
8768
  };
8780
8769
  }
8781
- function buildBarStackedOption(parsed, palette, isDark, textColor, axisLineColor, splitLineColor, gridOpacity, colors, bg, titleConfig, chartWidth) {
8770
+ function buildBarStackedOption(parsed, palette, isDark, textColor, axisLineColor, splitLineColor, gridOpacity, colors, _bg, titleConfig, chartWidth) {
8782
8771
  const { xLabel, yLabel } = resolveAxisLabels(parsed);
8783
8772
  const isHorizontal = parsed.orientation === "horizontal";
8784
8773
  const seriesNames = parsed.seriesNames ?? [];
@@ -8918,8 +8907,8 @@ async function renderExtendedChartForExport(content, theme, palette) {
8918
8907
  const titleHeight = option.title && option.title.text ? 40 : 0;
8919
8908
  const legendY = 8 + titleHeight;
8920
8909
  const grid = option.grid;
8921
- const gridLeftPct = grid?.left ? parseFloat(String(grid.left)) : void 0;
8922
- const gridRightPct = grid?.right ? parseFloat(String(grid.right)) : void 0;
8910
+ const gridLeftPct = grid?.["left"] ? parseFloat(String(grid["left"])) : void 0;
8911
+ const gridRightPct = grid?.["right"] ? parseFloat(String(grid["right"])) : void 0;
8923
8912
  const { svg: legendSvgStr } = renderLegendSvg(legendGroups, {
8924
8913
  palette: effectivePalette,
8925
8914
  isDark,
@@ -9265,7 +9254,7 @@ function parseOrg(content, palette) {
9265
9254
  }
9266
9255
  return result;
9267
9256
  }
9268
- function parseNodeLabel(trimmed, _indent, lineNumber, palette, counter, metaAliasMap = /* @__PURE__ */ new Map(), warnFn, nameAliasMap) {
9257
+ function parseNodeLabel(trimmed, _indent, lineNumber, _palette, counter, metaAliasMap = /* @__PURE__ */ new Map(), warnFn, nameAliasMap) {
9269
9258
  const segments = trimmed.split("|").map((s) => s.trim());
9270
9259
  let label = segments[0];
9271
9260
  const asMatch = label.match(/^(.*?)\s+as\s+([A-Za-z][A-Za-z0-9_]{0,11})\s*$/);
@@ -9514,8 +9503,8 @@ function parseKanban(content, palette) {
9514
9503
  columnMetadata,
9515
9504
  parsePipeMetadata(pipeSegments, metaAliasMap)
9516
9505
  );
9517
- if (columnMetadata.wip) {
9518
- const wipVal = parseInt(columnMetadata.wip, 10);
9506
+ if (columnMetadata["wip"]) {
9507
+ const wipVal = parseInt(columnMetadata["wip"], 10);
9519
9508
  if (!isNaN(wipVal)) {
9520
9509
  wipLimit = wipVal;
9521
9510
  }
@@ -9894,7 +9883,7 @@ function parseC4(content, palette) {
9894
9883
  );
9895
9884
  const shape = inferC4Shape(
9896
9885
  nodeName,
9897
- metadata.tech ?? metadata.technology
9886
+ metadata["tech"] ?? metadata["technology"]
9898
9887
  );
9899
9888
  const dNode = {
9900
9889
  name: nodeName,
@@ -9997,11 +9986,11 @@ function parseC4(content, palette) {
9997
9986
  target = targetBody.substring(0, pipeIdx).trim();
9998
9987
  const metaPart = targetBody.substring(pipeIdx + 1).trim();
9999
9988
  const meta = parsePipeMetadata(["", metaPart], metaAliasMap);
10000
- if (meta.tech) {
10001
- technology = meta.tech;
9989
+ if (meta["tech"]) {
9990
+ technology = meta["tech"];
10002
9991
  }
10003
- if (meta.technology) {
10004
- technology = meta.technology;
9992
+ if (meta["technology"]) {
9993
+ technology = meta["technology"];
10005
9994
  }
10006
9995
  }
10007
9996
  const rel = {
@@ -10135,7 +10124,7 @@ function parseC4(content, palette) {
10135
10124
  metaAliasMap,
10136
10125
  () => pushError(lineNumber, MULTIPLE_PIPE_ERROR)
10137
10126
  );
10138
- const shape = explicitShape ?? inferC4Shape(namePart, metadata.tech ?? metadata.technology);
10127
+ const shape = explicitShape ?? inferC4Shape(namePart, metadata["tech"] ?? metadata["technology"]);
10139
10128
  let isADescription;
10140
10129
  if ("description" in metadata) {
10141
10130
  const descVal = metadata["description"].trim();
@@ -10195,7 +10184,7 @@ function parseC4(content, palette) {
10195
10184
  metaAliasMap,
10196
10185
  () => pushError(lineNumber, MULTIPLE_PIPE_ERROR)
10197
10186
  );
10198
- const shape = explicitShape ?? inferC4Shape(namePart, metadata.tech ?? metadata.technology);
10187
+ const shape = explicitShape ?? inferC4Shape(namePart, metadata["tech"] ?? metadata["technology"]);
10199
10188
  let prefixDescription;
10200
10189
  if ("description" in metadata) {
10201
10190
  const descVal = metadata["description"].trim();
@@ -10804,7 +10793,7 @@ function parseSitemap(content, palette) {
10804
10793
  }
10805
10794
  return result;
10806
10795
  }
10807
- function parseNodeLabel2(trimmed, lineNumber, palette, counter, metaAliasMap = /* @__PURE__ */ new Map(), warnFn, _diagnostics, nameAliasMap) {
10796
+ function parseNodeLabel2(trimmed, lineNumber, _palette, counter, metaAliasMap = /* @__PURE__ */ new Map(), warnFn, _diagnostics, nameAliasMap) {
10808
10797
  const segments = trimmed.split("|").map((s) => s.trim());
10809
10798
  let label = segments[0];
10810
10799
  const asMatch = label.match(/^(.*?)\s+as\s+([A-Za-z][A-Za-z0-9_]{0,11})\s*$/);
@@ -11095,11 +11084,11 @@ function parseInfra(content) {
11095
11084
  continue;
11096
11085
  }
11097
11086
  if (trimmed === "animate") {
11098
- result.options.animate = "on";
11087
+ result.options["animate"] = "on";
11099
11088
  continue;
11100
11089
  }
11101
11090
  if (trimmed === "no-animate") {
11102
- result.options.animate = "off";
11091
+ result.options["animate"] = "off";
11103
11092
  continue;
11104
11093
  }
11105
11094
  if (tryParseSharedOption(trimmed, result.options)) {
@@ -11253,8 +11242,8 @@ function parseInfra(content) {
11253
11242
  const pipeMeta = extractPipeMetadata(targetRaw);
11254
11243
  const targetName = pipeMeta.clean || targetRaw;
11255
11244
  warnUnparsedPipeMeta(targetName, lineNumber, warn);
11256
- const split = pipeMeta.tags.split ? parseFloat(pipeMeta.tags.split) : null;
11257
- const fanoutRaw = pipeMeta.tags.fanout ? parseInt(pipeMeta.tags.fanout, 10) : null;
11245
+ const split = pipeMeta.tags["split"] ? parseFloat(pipeMeta.tags["split"]) : null;
11246
+ const fanoutRaw = pipeMeta.tags["fanout"] ? parseInt(pipeMeta.tags["fanout"], 10) : null;
11258
11247
  if (fanoutRaw !== null && fanoutRaw < 1) {
11259
11248
  warn(
11260
11249
  lineNumber,
@@ -11285,8 +11274,8 @@ function parseInfra(content) {
11285
11274
  const pipeMeta = extractPipeMetadata(targetRaw);
11286
11275
  const targetName = pipeMeta.clean || targetRaw;
11287
11276
  warnUnparsedPipeMeta(targetName, lineNumber, warn);
11288
- const split = pipeMeta.tags.split ? parseFloat(pipeMeta.tags.split) : null;
11289
- const fanoutRaw = pipeMeta.tags.fanout ? parseInt(pipeMeta.tags.fanout, 10) : null;
11277
+ const split = pipeMeta.tags["split"] ? parseFloat(pipeMeta.tags["split"]) : null;
11278
+ const fanoutRaw = pipeMeta.tags["fanout"] ? parseInt(pipeMeta.tags["fanout"], 10) : null;
11290
11279
  if (fanoutRaw !== null && fanoutRaw < 1) {
11291
11280
  warn(
11292
11281
  lineNumber,
@@ -11320,8 +11309,8 @@ function parseInfra(content) {
11320
11309
  const pipeMeta = extractPipeMetadata(targetRaw);
11321
11310
  const targetName = pipeMeta.clean || targetRaw;
11322
11311
  warnUnparsedPipeMeta(targetName, lineNumber, warn);
11323
- const split = pipeMeta.tags.split ? parseFloat(pipeMeta.tags.split) : null;
11324
- const fanoutRaw = pipeMeta.tags.fanout ? parseInt(pipeMeta.tags.fanout, 10) : null;
11312
+ const split = pipeMeta.tags["split"] ? parseFloat(pipeMeta.tags["split"]) : null;
11313
+ const fanoutRaw = pipeMeta.tags["fanout"] ? parseInt(pipeMeta.tags["fanout"], 10) : null;
11325
11314
  if (fanoutRaw !== null && fanoutRaw < 1) {
11326
11315
  warn(
11327
11316
  lineNumber,
@@ -11352,8 +11341,8 @@ function parseInfra(content) {
11352
11341
  const pipeMeta = extractPipeMetadata(targetRaw);
11353
11342
  const targetName = pipeMeta.clean || targetRaw;
11354
11343
  warnUnparsedPipeMeta(targetName, lineNumber, warn);
11355
- const split = pipeMeta.tags.split ? parseFloat(pipeMeta.tags.split) : null;
11356
- const fanoutRaw = pipeMeta.tags.fanout ? parseInt(pipeMeta.tags.fanout, 10) : null;
11344
+ const split = pipeMeta.tags["split"] ? parseFloat(pipeMeta.tags["split"]) : null;
11345
+ const fanoutRaw = pipeMeta.tags["fanout"] ? parseInt(pipeMeta.tags["fanout"], 10) : null;
11357
11346
  if (fanoutRaw !== null && fanoutRaw < 1) {
11358
11347
  warn(
11359
11348
  lineNumber,
@@ -12060,15 +12049,15 @@ function parseGantt(content, palette) {
12060
12049
  metaAliasMap,
12061
12050
  () => warn(lineNumber, MULTIPLE_PIPE_ERROR)
12062
12051
  );
12063
- if (meta.lag || meta.lead) {
12064
- const key = meta.lag ? "lag" : "lead";
12052
+ if (meta["lag"] || meta["lead"]) {
12053
+ const key = meta["lag"] ? "lag" : "lead";
12065
12054
  softError(
12066
12055
  lineNumber,
12067
12056
  `"${key}" is no longer supported \u2014 use "offset: ${meta[key]}" instead.${key === "lead" ? ' Negate the value for lead behavior: "offset: -...".' : ""}`
12068
12057
  );
12069
12058
  }
12070
- if (meta.offset) {
12071
- const raw = meta.offset;
12059
+ if (meta["offset"]) {
12060
+ const raw = meta["offset"];
12072
12061
  if (raw.trim().startsWith("+")) {
12073
12062
  warn(
12074
12063
  lineNumber,
@@ -12455,15 +12444,15 @@ function parseGantt(content, palette) {
12455
12444
  metaAliasMap,
12456
12445
  () => warn(lineNumber, MULTIPLE_PIPE_ERROR)
12457
12446
  );
12458
- if (meta.lag || meta.lead) {
12459
- const key = meta.lag ? "lag" : "lead";
12447
+ if (meta["lag"] || meta["lead"]) {
12448
+ const key = meta["lag"] ? "lag" : "lead";
12460
12449
  softError(
12461
12450
  lineNumber,
12462
12451
  `"${key}" is no longer supported \u2014 use "offset: ${meta[key]}" instead.${key === "lead" ? ' Negate the value for lead behavior: "offset: -...".' : ""}`
12463
12452
  );
12464
12453
  }
12465
- if (meta.offset) {
12466
- const raw = meta.offset;
12454
+ if (meta["offset"]) {
12455
+ const raw = meta["offset"];
12467
12456
  if (raw.trim().startsWith("+")) {
12468
12457
  warn(
12469
12458
  lineNumber,
@@ -12534,9 +12523,9 @@ function parseGantt(content, palette) {
12534
12523
  () => warn(ln, MULTIPLE_PIPE_ERROR)
12535
12524
  ) : {};
12536
12525
  let progress = null;
12537
- if (metadata.progress) {
12538
- progress = parseFloat(metadata.progress);
12539
- delete metadata.progress;
12526
+ if (metadata["progress"]) {
12527
+ progress = parseFloat(metadata["progress"]);
12528
+ delete metadata["progress"];
12540
12529
  }
12541
12530
  for (const part of segments.slice(1).join(",").split(",")) {
12542
12531
  const seg = part.trim();
@@ -12545,16 +12534,16 @@ function parseGantt(content, palette) {
12545
12534
  progress = parseInt(progressMatch[1], 10);
12546
12535
  }
12547
12536
  }
12548
- if (metadata.lag || metadata.lead) {
12549
- const key = metadata.lag ? "lag" : "lead";
12537
+ if (metadata["lag"] || metadata["lead"]) {
12538
+ const key = metadata["lag"] ? "lag" : "lead";
12550
12539
  softError(
12551
12540
  ln,
12552
12541
  `"${key}" is no longer supported \u2014 use "offset: ${metadata[key]}" instead.${key === "lead" ? ' Negate the value for lead behavior: "offset: -...".' : ""}`
12553
12542
  );
12554
12543
  }
12555
12544
  let taskOffset;
12556
- if (metadata.offset) {
12557
- const raw = metadata.offset;
12545
+ if (metadata["offset"]) {
12546
+ const raw = metadata["offset"];
12558
12547
  if (raw.trim().startsWith("+")) {
12559
12548
  warn(
12560
12549
  ln,
@@ -12569,7 +12558,7 @@ function parseGantt(content, palette) {
12569
12558
  );
12570
12559
  }
12571
12560
  }
12572
- delete metadata.offset;
12561
+ delete metadata["offset"];
12573
12562
  }
12574
12563
  const groupPath = currentGroupPath();
12575
12564
  const inheritedMeta = {};
@@ -13092,7 +13081,7 @@ function parsePert(content, parseOpts = {}) {
13092
13081
  id,
13093
13082
  name,
13094
13083
  activityIds: [],
13095
- collapsed: meta.collapsed === "true",
13084
+ collapsed: meta["collapsed"] === "true",
13096
13085
  lineNumber,
13097
13086
  ...Object.keys(tags).length > 0 && { tags }
13098
13087
  });
@@ -13354,7 +13343,7 @@ function parsePert(content, parseOpts = {}) {
13354
13343
  name: decl.name,
13355
13344
  ...decl.alias !== void 0 && { alias: decl.alias },
13356
13345
  duration: estimate,
13357
- ...meta.confidence && { confidence: meta.confidence },
13346
+ ...meta["confidence"] && { confidence: meta["confidence"] },
13358
13347
  ...decl.groupHint !== void 0 && { groupId: decl.groupHint },
13359
13348
  lineNumber: decl.lineNumber,
13360
13349
  isMilestone,
@@ -14685,7 +14674,7 @@ function parseMindmap(content, palette) {
14685
14674
  }
14686
14675
  return result;
14687
14676
  }
14688
- function parseNodeLine2(trimmed, lineNumber, palette, counter, aliasMap, warnFn) {
14677
+ function parseNodeLine2(trimmed, lineNumber, _palette, counter, aliasMap, warnFn) {
14689
14678
  const segments = trimmed.split("|").map((s) => s.trim());
14690
14679
  const label = segments[0];
14691
14680
  const metadata = parsePipeMetadata(
@@ -15129,7 +15118,7 @@ function parseWireframe(content) {
15129
15118
  wrapper.isContainer = true;
15130
15119
  wrapper.orientation = "horizontal";
15131
15120
  wrapper.children = children;
15132
- wrapper.metadata._inlineRow = "true";
15121
+ wrapper.metadata["_inlineRow"] = "true";
15133
15122
  pushElement(wrapper);
15134
15123
  }
15135
15124
  for (let i = 0; i < lines.length; i++) {
@@ -15280,7 +15269,7 @@ function parseWireframe(content) {
15280
15269
  wrapper.isContainer = true;
15281
15270
  wrapper.orientation = "horizontal";
15282
15271
  wrapper.children.push(labelEl, fieldEl);
15283
- wrapper.metadata._labelField = "true";
15272
+ wrapper.metadata["_labelField"] = "true";
15284
15273
  pushElement(wrapper);
15285
15274
  }
15286
15275
  } else {
@@ -17101,9 +17090,9 @@ function parseRaci(content, palette) {
17101
17090
  let roleColor;
17102
17091
  if (segments.length > 1) {
17103
17092
  const meta = parsePipeMetadata(segments);
17104
- if (meta.color) {
17093
+ if (meta["color"]) {
17105
17094
  roleColor = resolveColorWithDiagnostic(
17106
- meta.color,
17095
+ meta["color"],
17107
17096
  j + 1,
17108
17097
  result.diagnostics,
17109
17098
  palette
@@ -17170,9 +17159,9 @@ function parseRaci(content, palette) {
17170
17159
  let phaseColor;
17171
17160
  if (phaseMatch[2]) {
17172
17161
  const meta = parsePipeMetadata(["", phaseMatch[2]]);
17173
- if (meta.color) {
17162
+ if (meta["color"]) {
17174
17163
  phaseColor = resolveColorWithDiagnostic(
17175
- meta.color,
17164
+ meta["color"],
17176
17165
  lineNumber,
17177
17166
  result.diagnostics,
17178
17167
  palette
@@ -17415,7 +17404,7 @@ var init_parser19 = __esm({
17415
17404
  });
17416
17405
 
17417
17406
  // src/chart-types.ts
17418
- var chartTypes, BETA_CHART_IDS;
17407
+ var chartTypes;
17419
17408
  var init_chart_types = __esm({
17420
17409
  "src/chart-types.ts"() {
17421
17410
  "use strict";
@@ -17874,7 +17863,6 @@ var init_chart_types = __esm({
17874
17863
  fallback: true
17875
17864
  }
17876
17865
  ];
17877
- BETA_CHART_IDS = /* @__PURE__ */ new Set(["c4", "venn"]);
17878
17866
  }
17879
17867
  });
17880
17868
 
@@ -19183,7 +19171,7 @@ function renderOrg(container, parsed, layout, palette, isDark, onClickItem, expo
19183
19171
  displayNames.set(group.name.toLowerCase(), group.name);
19184
19172
  }
19185
19173
  const rootNodeIds = new Set(parsed.roots.map((r) => r.id));
19186
- const colorOff = parsed.options?.color === "off";
19174
+ const colorOff = parsed.options?.["color"] === "off";
19187
19175
  for (const c of layout.containers) {
19188
19176
  const cG = contentG.append("g").attr("transform", `translate(${c.x}, ${c.y})`).attr("class", "org-container").attr("data-line-number", String(c.lineNumber));
19189
19177
  if (activeTagGroup) {
@@ -22384,7 +22372,7 @@ function renderERDiagram(container, parsed, layout, palette, isDark, onClickItem
22384
22372
  const seriesColors2 = getSeriesColors(palette);
22385
22373
  const semanticRoles = useSemanticColors ? classifyEREntities(parsed.tables, parsed.relationships) : null;
22386
22374
  const semanticActive = semanticRoles !== null && (semanticColorsActive ?? true);
22387
- const useLabels = parsed.options.notation === "labels";
22375
+ const useLabels = parsed.options["notation"] === "labels";
22388
22376
  for (const edge of layout.edges) {
22389
22377
  if (edge.points.length < 2) continue;
22390
22378
  const edgeG = contentG.append("g").attr("class", "er-edge-group").attr("data-line-number", String(edge.lineNumber));
@@ -22597,495 +22585,6 @@ var init_renderer5 = __esm({
22597
22585
  }
22598
22586
  });
22599
22587
 
22600
- // src/boxes-and-lines/layout.ts
22601
- var layout_exports5 = {};
22602
- __export(layout_exports5, {
22603
- layoutBoxesAndLines: () => layoutBoxesAndLines
22604
- });
22605
- import dagre4 from "@dagrejs/dagre";
22606
- function clipToRectBorder2(cx, cy, w, h, tx, ty) {
22607
- const dx = tx - cx;
22608
- const dy = ty - cy;
22609
- if (dx === 0 && dy === 0) return { x: cx, y: cy };
22610
- const hw = w / 2;
22611
- const hh = h / 2;
22612
- const sx = dx !== 0 ? hw / Math.abs(dx) : Infinity;
22613
- const sy = dy !== 0 ? hh / Math.abs(dy) : Infinity;
22614
- const s = Math.min(sx, sy);
22615
- return { x: cx + dx * s, y: cy + dy * s };
22616
- }
22617
- function splitCamelCase(word) {
22618
- const parts = [];
22619
- let start = 0;
22620
- for (let i = 1; i < word.length; i++) {
22621
- const prev = word[i - 1];
22622
- const curr = word[i];
22623
- const next = i + 1 < word.length ? word[i + 1] : "";
22624
- const lowerToUpper = prev >= "a" && prev <= "z" && curr >= "A" && curr <= "Z";
22625
- const upperRunEnd = prev >= "A" && prev <= "Z" && curr >= "A" && curr <= "Z" && next >= "a" && next <= "z";
22626
- if (lowerToUpper || upperRunEnd) {
22627
- parts.push(word.slice(start, i));
22628
- start = i;
22629
- }
22630
- }
22631
- parts.push(word.slice(start));
22632
- return parts.length > 1 ? parts : [word];
22633
- }
22634
- function estimateLabelLines(label, nodeWidth2 = NODE_WIDTH) {
22635
- const rawParts = label.split(/[\s-]+/);
22636
- const words = [];
22637
- for (const part of rawParts) {
22638
- if (!part) continue;
22639
- words.push(...splitCamelCase(part));
22640
- }
22641
- for (let fontSize = 13; fontSize >= 9; fontSize--) {
22642
- const charWidth = fontSize * 0.6;
22643
- const maxChars = Math.floor((nodeWidth2 - 24) / charWidth);
22644
- if (maxChars < 2) continue;
22645
- let lines = 1;
22646
- let current = "";
22647
- for (const word of words) {
22648
- const test = current ? `${current} ${word}` : word;
22649
- if (test.length <= maxChars) {
22650
- current = test;
22651
- } else {
22652
- lines++;
22653
- current = word;
22654
- }
22655
- }
22656
- if (lines <= MAX_LABEL_LINES) return Math.min(lines, MAX_LABEL_LINES);
22657
- }
22658
- return MAX_LABEL_LINES;
22659
- }
22660
- function computeNodeSize(node) {
22661
- if (!node.description || node.description.length === 0) {
22662
- return { width: NODE_WIDTH, height: NODE_HEIGHT };
22663
- }
22664
- const w = DESC_NODE_WIDTH;
22665
- const labelLines = estimateLabelLines(node.label, w);
22666
- const labelHeight = labelLines * 13 * LABEL_LINE_HEIGHT + LABEL_PAD;
22667
- const charsPerLine = Math.floor((w - 24) / (DESC_FONT_SIZE * 0.6));
22668
- let totalRenderedLines = 0;
22669
- for (const line12 of node.description) {
22670
- if (line12.length <= charsPerLine) {
22671
- totalRenderedLines += 1;
22672
- } else {
22673
- const words = line12.split(/\s+/);
22674
- let current = "";
22675
- let lineCount = 0;
22676
- for (const word of words) {
22677
- const fitted = word.length > charsPerLine ? word.slice(0, charsPerLine) : word;
22678
- const test = current ? `${current} ${fitted}` : fitted;
22679
- if (test.length <= charsPerLine) {
22680
- current = test;
22681
- } else {
22682
- if (current) lineCount++;
22683
- current = fitted;
22684
- }
22685
- }
22686
- if (current) lineCount++;
22687
- totalRenderedLines += lineCount;
22688
- }
22689
- }
22690
- totalRenderedLines = Math.min(totalRenderedLines, MAX_DESC_LINES);
22691
- const descriptionHeight = totalRenderedLines * DESC_FONT_SIZE * DESC_LINE_HEIGHT;
22692
- const totalHeight = labelHeight + SEPARATOR_GAP5 + DESC_PADDING + descriptionHeight + DESC_PADDING;
22693
- return { width: w, height: Math.max(NODE_HEIGHT, totalHeight) };
22694
- }
22695
- function layoutBoxesAndLines(parsed, collapseInfo, layoutOptions) {
22696
- const hideDescriptions = layoutOptions?.hideDescriptions ?? false;
22697
- const g = new dagre4.graphlib.Graph({ compound: true, multigraph: true });
22698
- g.setGraph({
22699
- rankdir: parsed.direction,
22700
- nodesep: NODESEP,
22701
- ranksep: RANKSEP,
22702
- marginx: MARGIN3,
22703
- marginy: MARGIN3
22704
- });
22705
- g.setDefaultEdgeLabel(() => ({}));
22706
- const collapsedGroupLabels = /* @__PURE__ */ new Set();
22707
- if (collapseInfo) {
22708
- const missingGroups = /* @__PURE__ */ new Set();
22709
- for (const og of collapseInfo.originalGroups) {
22710
- if (!parsed.groups.some((g2) => g2.label === og.label)) {
22711
- missingGroups.add(og.label);
22712
- }
22713
- }
22714
- for (const label of missingGroups) {
22715
- const og = collapseInfo.originalGroups.find((g2) => g2.label === label);
22716
- const parentLabel = og?.parentGroup;
22717
- if (!parentLabel || !missingGroups.has(parentLabel)) {
22718
- collapsedGroupLabels.add(label);
22719
- }
22720
- }
22721
- }
22722
- for (const label of collapsedGroupLabels) {
22723
- const gid = `__group_${label}`;
22724
- g.setNode(gid, { label, width: NODE_WIDTH, height: NODE_HEIGHT });
22725
- }
22726
- for (const group of parsed.groups) {
22727
- const gid = `__group_${group.label}`;
22728
- g.setNode(gid, {
22729
- label: group.label,
22730
- paddingLeft: CONTAINER_PAD_X3,
22731
- paddingRight: CONTAINER_PAD_X3,
22732
- paddingTop: CONTAINER_PAD_TOP2,
22733
- paddingBottom: CONTAINER_PAD_BOTTOM3
22734
- });
22735
- }
22736
- const originalGroupByLabel = /* @__PURE__ */ new Map();
22737
- if (collapseInfo) {
22738
- for (const og of collapseInfo.originalGroups) {
22739
- originalGroupByLabel.set(og.label, og);
22740
- }
22741
- }
22742
- for (const label of collapsedGroupLabels) {
22743
- const og = originalGroupByLabel.get(label);
22744
- if (og?.parentGroup && !collapsedGroupLabels.has(og.parentGroup)) {
22745
- const gid = `__group_${label}`;
22746
- const parentGid = `__group_${og.parentGroup}`;
22747
- if (g.hasNode(parentGid)) {
22748
- g.setParent(gid, parentGid);
22749
- }
22750
- }
22751
- }
22752
- const nodeSizes = /* @__PURE__ */ new Map();
22753
- let maxDescHeight = 0;
22754
- for (const node of parsed.nodes) {
22755
- const size = hideDescriptions ? { width: NODE_WIDTH, height: NODE_HEIGHT } : computeNodeSize(node);
22756
- nodeSizes.set(node.label, size);
22757
- if (!hideDescriptions && node.description && node.description.length > 0) {
22758
- maxDescHeight = Math.max(maxDescHeight, size.height);
22759
- }
22760
- }
22761
- if (maxDescHeight > 0) {
22762
- for (const node of parsed.nodes) {
22763
- if (node.description && node.description.length > 0) {
22764
- const size = nodeSizes.get(node.label);
22765
- nodeSizes.set(node.label, { width: size.width, height: maxDescHeight });
22766
- }
22767
- }
22768
- }
22769
- for (const node of parsed.nodes) {
22770
- const size = nodeSizes.get(node.label);
22771
- g.setNode(node.label, {
22772
- label: node.label,
22773
- width: size.width,
22774
- height: size.height
22775
- });
22776
- }
22777
- for (const group of parsed.groups) {
22778
- if (group.parentGroup) {
22779
- const childGid = `__group_${group.label}`;
22780
- const parentGid = `__group_${group.parentGroup}`;
22781
- if (g.hasNode(childGid) && g.hasNode(parentGid)) {
22782
- g.setParent(childGid, parentGid);
22783
- }
22784
- }
22785
- }
22786
- const groupLabelSet = new Set(parsed.groups.map((gr) => gr.label));
22787
- for (const group of parsed.groups) {
22788
- const gid = `__group_${group.label}`;
22789
- for (const child of group.children) {
22790
- if (groupLabelSet.has(child)) continue;
22791
- if (g.hasNode(child)) {
22792
- g.setParent(child, gid);
22793
- }
22794
- }
22795
- }
22796
- const expandedGroupIds = /* @__PURE__ */ new Set();
22797
- for (const group of parsed.groups) {
22798
- expandedGroupIds.add(`__group_${group.label}`);
22799
- }
22800
- const groupFirstChild = /* @__PURE__ */ new Map();
22801
- for (const group of parsed.groups) {
22802
- const gid = `__group_${group.label}`;
22803
- const firstChild = group.children.find(
22804
- (c) => !groupLabelSet.has(c) && g.hasNode(c)
22805
- );
22806
- if (firstChild) {
22807
- groupFirstChild.set(gid, firstChild);
22808
- }
22809
- }
22810
- const deferredEdgeIndices = [];
22811
- let proxyIdx = 0;
22812
- for (let i = 0; i < parsed.edges.length; i++) {
22813
- const edge = parsed.edges[i];
22814
- const src = edge.source;
22815
- const tgt = edge.target;
22816
- if (!g.hasNode(src) || !g.hasNode(tgt)) continue;
22817
- if (expandedGroupIds.has(src) || expandedGroupIds.has(tgt)) {
22818
- deferredEdgeIndices.push(i);
22819
- const proxySrc = expandedGroupIds.has(src) ? groupFirstChild.get(src) : src;
22820
- const proxyTgt = expandedGroupIds.has(tgt) ? groupFirstChild.get(tgt) : tgt;
22821
- if (proxySrc && proxyTgt && proxySrc !== proxyTgt) {
22822
- g.setEdge(
22823
- proxySrc,
22824
- proxyTgt,
22825
- { label: "", minlen: 1 },
22826
- `proxy${proxyIdx++}`
22827
- );
22828
- }
22829
- continue;
22830
- }
22831
- g.setEdge(src, tgt, { label: edge.label ?? "", minlen: 1 }, `e${i}`);
22832
- }
22833
- dagre4.layout(g);
22834
- const layoutNodes = [];
22835
- for (const node of parsed.nodes) {
22836
- const dagreNode = g.node(node.label);
22837
- if (!dagreNode) continue;
22838
- layoutNodes.push({
22839
- label: node.label,
22840
- x: dagreNode.x,
22841
- y: dagreNode.y,
22842
- width: dagreNode.width,
22843
- height: dagreNode.height
22844
- });
22845
- }
22846
- const layoutGroups = [];
22847
- for (const group of parsed.groups) {
22848
- const gid = `__group_${group.label}`;
22849
- const dagreNode = g.node(gid);
22850
- if (!dagreNode) continue;
22851
- layoutGroups.push({
22852
- label: group.label,
22853
- lineNumber: group.lineNumber,
22854
- x: dagreNode.x,
22855
- y: dagreNode.y,
22856
- width: dagreNode.width,
22857
- height: dagreNode.height,
22858
- collapsed: false
22859
- });
22860
- }
22861
- for (const label of collapsedGroupLabels) {
22862
- const gid = `__group_${label}`;
22863
- const dagreNode = g.node(gid);
22864
- if (!dagreNode) continue;
22865
- const og = collapseInfo?.originalGroups.find((g2) => g2.label === label);
22866
- layoutGroups.push({
22867
- label,
22868
- lineNumber: og?.lineNumber ?? 0,
22869
- x: dagreNode.x,
22870
- y: dagreNode.y,
22871
- width: dagreNode.width,
22872
- height: dagreNode.height,
22873
- collapsed: true,
22874
- childCount: collapseInfo?.collapsedChildCounts.get(label) ?? 0
22875
- });
22876
- }
22877
- const groupAlignShifts = /* @__PURE__ */ new Map();
22878
- {
22879
- const groupEdges = [];
22880
- for (const edge of parsed.edges) {
22881
- if (edge.source.startsWith("__group_") && edge.target.startsWith("__group_")) {
22882
- groupEdges.push(edge);
22883
- }
22884
- }
22885
- if (groupEdges.length > 0) {
22886
- const groupParent = /* @__PURE__ */ new Map();
22887
- const find = (x) => {
22888
- while (groupParent.has(x) && groupParent.get(x) !== x) {
22889
- groupParent.set(x, groupParent.get(groupParent.get(x)));
22890
- x = groupParent.get(x);
22891
- }
22892
- return x;
22893
- };
22894
- const union = (a, b) => {
22895
- const ra = find(a), rb = find(b);
22896
- if (ra !== rb) groupParent.set(ra, rb);
22897
- };
22898
- for (const edge of groupEdges) {
22899
- if (!groupParent.has(edge.source))
22900
- groupParent.set(edge.source, edge.source);
22901
- if (!groupParent.has(edge.target))
22902
- groupParent.set(edge.target, edge.target);
22903
- union(edge.source, edge.target);
22904
- }
22905
- const components = /* @__PURE__ */ new Map();
22906
- for (const lg of layoutGroups) {
22907
- const gid = `__group_${lg.label}`;
22908
- if (!groupParent.has(gid)) continue;
22909
- const root = find(gid);
22910
- if (!components.has(root)) components.set(root, []);
22911
- components.get(root).push(lg);
22912
- }
22913
- const axis = parsed.direction === "TB" ? "x" : "y";
22914
- for (const groups of components.values()) {
22915
- if (groups.length < 2) continue;
22916
- const dim = axis === "x" ? "width" : "height";
22917
- let widest = groups[0];
22918
- for (const g2 of groups) {
22919
- if (g2[dim] > widest[dim]) widest = g2;
22920
- }
22921
- const targetCenter = widest[axis];
22922
- for (const grp of groups) {
22923
- const dx = targetCenter - grp[axis];
22924
- if (dx === 0) continue;
22925
- grp[axis] += dx;
22926
- groupAlignShifts.set(`__group_${grp.label}`, dx);
22927
- const parsedGroup = parsed.groups.find(
22928
- (pg) => pg.label === grp.label
22929
- );
22930
- if (parsedGroup) {
22931
- for (const childLabel of parsedGroup.children) {
22932
- const childNode = layoutNodes.find((n) => n.label === childLabel);
22933
- if (childNode) childNode[axis] += dx;
22934
- }
22935
- }
22936
- }
22937
- }
22938
- }
22939
- }
22940
- const edgeYOffsets = new Array(parsed.edges.length).fill(0);
22941
- const edgeParallelCounts = new Array(parsed.edges.length).fill(1);
22942
- const parallelGroups = /* @__PURE__ */ new Map();
22943
- for (let i = 0; i < parsed.edges.length; i++) {
22944
- const edge = parsed.edges[i];
22945
- const [a, b] = edge.source < edge.target ? [edge.source, edge.target] : [edge.target, edge.source];
22946
- const key = `${a}\0${b}`;
22947
- if (!parallelGroups.has(key)) parallelGroups.set(key, []);
22948
- parallelGroups.get(key).push(i);
22949
- }
22950
- for (const group of parallelGroups.values()) {
22951
- const capped = group.slice(0, MAX_PARALLEL_EDGES);
22952
- for (const idx of group.slice(MAX_PARALLEL_EDGES)) {
22953
- edgeParallelCounts[idx] = 0;
22954
- }
22955
- if (capped.length < 2) continue;
22956
- const effectiveSpacing = PARALLEL_SPACING;
22957
- for (let j = 0; j < capped.length; j++) {
22958
- edgeYOffsets[capped[j]] = (j - (capped.length - 1) / 2) * effectiveSpacing;
22959
- edgeParallelCounts[capped[j]] = capped.length;
22960
- }
22961
- }
22962
- const deferredSet = new Set(deferredEdgeIndices);
22963
- const layoutEdges = [];
22964
- for (let i = 0; i < parsed.edges.length; i++) {
22965
- const edge = parsed.edges[i];
22966
- if (edgeParallelCounts[i] === 0) continue;
22967
- let points;
22968
- if (deferredSet.has(i)) {
22969
- const srcLayout = layoutGroups.find(
22970
- (lg) => `__group_${lg.label}` === edge.source
22971
- );
22972
- const tgtLayout = layoutGroups.find(
22973
- (lg) => `__group_${lg.label}` === edge.target
22974
- );
22975
- if (!srcLayout || !tgtLayout) {
22976
- const srcNode = g.node(edge.source);
22977
- const tgtNode = g.node(edge.target);
22978
- if (!srcNode || !tgtNode) continue;
22979
- const srcPt = clipToRectBorder2(
22980
- srcNode.x,
22981
- srcNode.y,
22982
- srcNode.width,
22983
- srcNode.height,
22984
- tgtNode.x,
22985
- tgtNode.y
22986
- );
22987
- const tgtPt = clipToRectBorder2(
22988
- tgtNode.x,
22989
- tgtNode.y,
22990
- tgtNode.width,
22991
- tgtNode.height,
22992
- srcNode.x,
22993
- srcNode.y
22994
- );
22995
- const midX = (srcPt.x + tgtPt.x) / 2;
22996
- const midY = (srcPt.y + tgtPt.y) / 2;
22997
- points = [srcPt, { x: midX, y: midY }, tgtPt];
22998
- } else if (parsed.direction === "TB") {
22999
- const cx = (srcLayout.x + tgtLayout.x) / 2;
23000
- const srcPt = { x: cx, y: srcLayout.y + srcLayout.height / 2 };
23001
- const tgtPt = { x: cx, y: tgtLayout.y - tgtLayout.height / 2 };
23002
- const midY = (srcPt.y + tgtPt.y) / 2;
23003
- points = [srcPt, { x: cx, y: midY }, tgtPt];
23004
- } else {
23005
- const cy = (srcLayout.y + tgtLayout.y) / 2;
23006
- const srcPt = { x: srcLayout.x + srcLayout.width / 2, y: cy };
23007
- const tgtPt = { x: tgtLayout.x - tgtLayout.width / 2, y: cy };
23008
- const midX = (srcPt.x + tgtPt.x) / 2;
23009
- points = [srcPt, { x: midX, y: cy }, tgtPt];
23010
- }
23011
- } else {
23012
- const dagreEdge = g.edge(edge.source, edge.target, `e${i}`);
23013
- points = dagreEdge?.points ?? [];
23014
- const srcShift = groupAlignShifts.get(edge.source) ?? 0;
23015
- const tgtShift = groupAlignShifts.get(edge.target) ?? 0;
23016
- if (srcShift !== 0 || tgtShift !== 0) {
23017
- const avgShift = (srcShift + tgtShift) / 2;
23018
- const prop = parsed.direction === "TB" ? "x" : "y";
23019
- points = points.map((p) => ({ ...p, [prop]: p[prop] + avgShift }));
23020
- }
23021
- }
23022
- let labelX;
23023
- let labelY;
23024
- if (edge.label && points.length >= 2) {
23025
- const mid = Math.floor(points.length / 2);
23026
- labelX = points[mid].x;
23027
- labelY = points[mid].y - 10;
23028
- }
23029
- layoutEdges.push({
23030
- source: edge.source,
23031
- target: edge.target,
23032
- label: edge.label,
23033
- bidirectional: edge.bidirectional,
23034
- lineNumber: edge.lineNumber,
23035
- points,
23036
- labelX,
23037
- labelY,
23038
- yOffset: edgeYOffsets[i],
23039
- parallelCount: edgeParallelCounts[i],
23040
- metadata: edge.metadata,
23041
- deferred: deferredSet.has(i) || void 0
23042
- });
23043
- }
23044
- let maxX = 0;
23045
- let maxY = 0;
23046
- for (const node of layoutNodes) {
23047
- maxX = Math.max(maxX, node.x + node.width / 2);
23048
- maxY = Math.max(maxY, node.y + node.height / 2);
23049
- }
23050
- for (const group of layoutGroups) {
23051
- maxX = Math.max(maxX, group.x + group.width / 2);
23052
- maxY = Math.max(maxY, group.y + group.height / 2);
23053
- }
23054
- return {
23055
- nodes: layoutNodes,
23056
- edges: layoutEdges,
23057
- groups: layoutGroups,
23058
- width: maxX + MARGIN3,
23059
- height: maxY + MARGIN3
23060
- };
23061
- }
23062
- var 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;
23063
- var init_layout5 = __esm({
23064
- "src/boxes-and-lines/layout.ts"() {
23065
- "use strict";
23066
- NODESEP = 60;
23067
- RANKSEP = 100;
23068
- MARGIN3 = 40;
23069
- CONTAINER_PAD_X3 = 30;
23070
- CONTAINER_PAD_TOP2 = 40;
23071
- CONTAINER_PAD_BOTTOM3 = 24;
23072
- MAX_PARALLEL_EDGES = 5;
23073
- PARALLEL_SPACING = 22;
23074
- PHI = 1.618;
23075
- NODE_HEIGHT = 60;
23076
- NODE_WIDTH = Math.round(NODE_HEIGHT * PHI);
23077
- DESC_NODE_WIDTH = 140;
23078
- DESC_FONT_SIZE = 10;
23079
- DESC_LINE_HEIGHT = 1.4;
23080
- DESC_PADDING = 8;
23081
- SEPARATOR_GAP5 = 4;
23082
- MAX_DESC_LINES = 6;
23083
- MAX_LABEL_LINES = 3;
23084
- LABEL_LINE_HEIGHT = 1.3;
23085
- LABEL_PAD = 12;
23086
- }
23087
- });
23088
-
23089
22588
  // src/utils/wrapped-desc.ts
23090
22589
  function wrapDescriptionLines(lines, charsPerLine, lengthFn = (s) => s.length) {
23091
22590
  const result = [];
@@ -23137,7 +22636,7 @@ __export(renderer_exports6, {
23137
22636
  });
23138
22637
  import * as d3Selection6 from "d3-selection";
23139
22638
  import * as d3Shape4 from "d3-shape";
23140
- function splitCamelCase2(word) {
22639
+ function splitCamelCase(word) {
23141
22640
  const parts = [];
23142
22641
  let start = 0;
23143
22642
  for (let i = 1; i < word.length; i++) {
@@ -23160,7 +22659,7 @@ function fitLabelToHeader(label, nodeWidth2, maxLines) {
23160
22659
  const words = [];
23161
22660
  for (const part of rawParts) {
23162
22661
  if (!part || /^\s+$/.test(part) || part === "-") continue;
23163
- words.push(...splitCamelCase2(part));
22662
+ words.push(...splitCamelCase(part));
23164
22663
  }
23165
22664
  for (let fontSize = NODE_FONT_SIZE; fontSize >= MIN_NODE_FONT_SIZE; fontSize--) {
23166
22665
  const charWidth2 = fontSize * CHAR_WIDTH_RATIO2;
@@ -23536,12 +23035,12 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
23536
23035
  }
23537
23036
  const sepY = -ln.height / 2 + headerH;
23538
23037
  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);
23539
- const descStartY = sepY + 4 + DESC_FONT_SIZE2;
23038
+ const descStartY = sepY + 4 + DESC_FONT_SIZE;
23540
23039
  const maxTextWidth = ln.width - NODE_TEXT_PADDING * 2;
23541
23040
  const charsPerLine = Math.floor(
23542
- maxTextWidth / (DESC_FONT_SIZE2 * CHAR_WIDTH_RATIO2)
23041
+ maxTextWidth / (DESC_FONT_SIZE * CHAR_WIDTH_RATIO2)
23543
23042
  );
23544
- const descLineH = DESC_FONT_SIZE2 * DESC_LINE_HEIGHT2;
23043
+ const descLineH = DESC_FONT_SIZE * DESC_LINE_HEIGHT;
23545
23044
  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;
23546
23045
  const normalizedLines = [];
23547
23046
  for (const descLine of desc) {
@@ -23557,8 +23056,8 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
23557
23056
  charsPerLine,
23558
23057
  displayLen
23559
23058
  );
23560
- const truncated = wrappedLinesShared.length > MAX_DESC_LINES2;
23561
- const visibleLines = truncated ? wrappedLinesShared.slice(0, MAX_DESC_LINES2) : wrappedLinesShared;
23059
+ const truncated = wrappedLinesShared.length > MAX_DESC_LINES;
23060
+ const visibleLines = truncated ? wrappedLinesShared.slice(0, MAX_DESC_LINES) : wrappedLinesShared;
23562
23061
  const BULLET_GLYPH_X = -ln.width / 2 + 6;
23563
23062
  const BULLET_BODY_X = BULLET_GLYPH_X + 10;
23564
23063
  for (let li = 0; li < visibleLines.length; li++) {
@@ -23569,11 +23068,11 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
23569
23068
  }
23570
23069
  const y2 = descStartY + li * descLineH;
23571
23070
  if (line12.kind === "bullet-first") {
23572
- 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");
23071
+ 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");
23573
23072
  }
23574
23073
  const isBullet = line12.kind === "bullet-first" || line12.kind === "bullet-cont";
23575
- 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);
23576
- renderInlineText(textEl, lineText, palette, DESC_FONT_SIZE2);
23074
+ 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);
23075
+ renderInlineText(textEl, lineText, palette, DESC_FONT_SIZE);
23577
23076
  }
23578
23077
  if (truncated) {
23579
23078
  const fullText = desc.join(" ");
@@ -23651,7 +23150,7 @@ function renderBoxesAndLinesForExport(container, parsed, layout, palette, isDark
23651
23150
  hiddenTagValues: options?.hiddenTagValues
23652
23151
  });
23653
23152
  }
23654
- var 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;
23153
+ var 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;
23655
23154
  var init_renderer6 = __esm({
23656
23155
  "src/boxes-and-lines/renderer.ts"() {
23657
23156
  "use strict";
@@ -23673,9 +23172,9 @@ var init_renderer6 = __esm({
23673
23172
  COLLAPSE_BAR_HEIGHT3 = 4;
23674
23173
  ARROWHEAD_W2 = 5;
23675
23174
  ARROWHEAD_H2 = 4;
23676
- DESC_FONT_SIZE2 = 10;
23677
- DESC_LINE_HEIGHT2 = 1.4;
23678
- MAX_DESC_LINES2 = 6;
23175
+ DESC_FONT_SIZE = 10;
23176
+ DESC_LINE_HEIGHT = 1.4;
23177
+ MAX_DESC_LINES = 6;
23679
23178
  CHAR_WIDTH_RATIO2 = 0.6;
23680
23179
  NODE_TEXT_PADDING = 12;
23681
23180
  GROUP_RX = 8;
@@ -23686,6 +23185,523 @@ var init_renderer6 = __esm({
23686
23185
  }
23687
23186
  });
23688
23187
 
23188
+ // src/boxes-and-lines/layout.ts
23189
+ var layout_exports5 = {};
23190
+ __export(layout_exports5, {
23191
+ layoutBoxesAndLines: () => layoutBoxesAndLines
23192
+ });
23193
+ import ELK from "elkjs/lib/elk.bundled.js";
23194
+ function splitCamelCase2(word) {
23195
+ const parts = [];
23196
+ let start = 0;
23197
+ for (let i = 1; i < word.length; i++) {
23198
+ const prev = word[i - 1];
23199
+ const curr = word[i];
23200
+ const next = i + 1 < word.length ? word[i + 1] : "";
23201
+ const lowerToUpper = prev >= "a" && prev <= "z" && curr >= "A" && curr <= "Z";
23202
+ const upperRunEnd = prev >= "A" && prev <= "Z" && curr >= "A" && curr <= "Z" && next >= "a" && next <= "z";
23203
+ if (lowerToUpper || upperRunEnd) {
23204
+ parts.push(word.slice(start, i));
23205
+ start = i;
23206
+ }
23207
+ }
23208
+ parts.push(word.slice(start));
23209
+ return parts.length > 1 ? parts : [word];
23210
+ }
23211
+ function estimateLabelLines(label, nodeWidth2 = NODE_WIDTH) {
23212
+ const rawParts = label.split(/[\s-]+/);
23213
+ const words = [];
23214
+ for (const part of rawParts) {
23215
+ if (!part) continue;
23216
+ words.push(...splitCamelCase2(part));
23217
+ }
23218
+ for (let fontSize = 13; fontSize >= 9; fontSize--) {
23219
+ const charWidth = fontSize * 0.6;
23220
+ const maxChars = Math.floor((nodeWidth2 - 24) / charWidth);
23221
+ if (maxChars < 2) continue;
23222
+ let lines = 1;
23223
+ let current = "";
23224
+ for (const word of words) {
23225
+ const test = current ? `${current} ${word}` : word;
23226
+ if (test.length <= maxChars) {
23227
+ current = test;
23228
+ } else {
23229
+ lines++;
23230
+ current = word;
23231
+ }
23232
+ }
23233
+ if (lines <= MAX_LABEL_LINES) return Math.min(lines, MAX_LABEL_LINES);
23234
+ }
23235
+ return MAX_LABEL_LINES;
23236
+ }
23237
+ function computeNodeSize(node) {
23238
+ if (!node.description || node.description.length === 0) {
23239
+ return { width: NODE_WIDTH, height: NODE_HEIGHT };
23240
+ }
23241
+ const w = DESC_NODE_WIDTH;
23242
+ const labelLines = estimateLabelLines(node.label, w);
23243
+ const labelHeight = labelLines * 13 * LABEL_LINE_HEIGHT + LABEL_PAD;
23244
+ const charsPerLine = Math.floor((w - 24) / (DESC_FONT_SIZE2 * 0.6));
23245
+ let totalRenderedLines = 0;
23246
+ for (const line12 of node.description) {
23247
+ if (line12.length <= charsPerLine) {
23248
+ totalRenderedLines += 1;
23249
+ } else {
23250
+ const words = line12.split(/\s+/);
23251
+ let current = "";
23252
+ let lineCount = 0;
23253
+ for (const word of words) {
23254
+ const fitted = word.length > charsPerLine ? word.slice(0, charsPerLine) : word;
23255
+ const test = current ? `${current} ${fitted}` : fitted;
23256
+ if (test.length <= charsPerLine) {
23257
+ current = test;
23258
+ } else {
23259
+ if (current) lineCount++;
23260
+ current = fitted;
23261
+ }
23262
+ }
23263
+ if (current) lineCount++;
23264
+ totalRenderedLines += lineCount;
23265
+ }
23266
+ }
23267
+ totalRenderedLines = Math.min(totalRenderedLines, MAX_DESC_LINES2);
23268
+ const descriptionHeight = totalRenderedLines * DESC_FONT_SIZE2 * DESC_LINE_HEIGHT2;
23269
+ const totalHeight = labelHeight + SEPARATOR_GAP5 + DESC_PADDING + descriptionHeight + DESC_PADDING;
23270
+ return { width: w, height: Math.max(NODE_HEIGHT, totalHeight) };
23271
+ }
23272
+ function getElk() {
23273
+ if (!elkInstance) elkInstance = new ELK();
23274
+ return elkInstance;
23275
+ }
23276
+ function baseOptions() {
23277
+ return {
23278
+ "elk.algorithm": "layered",
23279
+ // INCLUDE_CHILDREN lets ELK route edges across container boundaries.
23280
+ "elk.hierarchyHandling": "INCLUDE_CHILDREN",
23281
+ "elk.edgeRouting": "ORTHOGONAL",
23282
+ "elk.layered.unnecessaryBendpoints": "true",
23283
+ // Let edges leave from top/bottom of nodes (not just the flow-direction
23284
+ // sides) when it reduces crossings.
23285
+ "elk.layered.allowNonFlowPortsToSwitchSides": "true"
23286
+ };
23287
+ }
23288
+ function bkBaseline() {
23289
+ return {
23290
+ ...baseOptions(),
23291
+ "elk.layered.nodePlacement.strategy": "BRANDES_KOEPF",
23292
+ "elk.layered.nodePlacement.bk.fixedAlignment": "BALANCED",
23293
+ "elk.layered.nodePlacement.bk.edgeStraightening": "IMPROVE_STRAIGHTNESS",
23294
+ "elk.layered.compaction.connectedComponents": "true",
23295
+ "elk.layered.spacing.nodeNodeBetweenLayers": "90",
23296
+ "elk.spacing.nodeNode": "55",
23297
+ "elk.spacing.edgeNode": "55",
23298
+ "elk.spacing.edgeEdge": "18"
23299
+ };
23300
+ }
23301
+ function getVariants() {
23302
+ const bk = bkBaseline();
23303
+ return [
23304
+ {
23305
+ name: "bk-baseline",
23306
+ options: {
23307
+ ...bk,
23308
+ "elk.layered.crossingMinimization.greedySwitch.type": "ONE_SIDED"
23309
+ }
23310
+ },
23311
+ {
23312
+ name: "bk-aggressive",
23313
+ options: {
23314
+ ...bk,
23315
+ "elk.layered.crossingMinimization.greedySwitch.type": "TWO_SIDED",
23316
+ "elk.layered.thoroughness": "50"
23317
+ }
23318
+ },
23319
+ {
23320
+ name: "bk-wide",
23321
+ options: {
23322
+ ...bk,
23323
+ "elk.layered.crossingMinimization.greedySwitch.type": "TWO_SIDED",
23324
+ "elk.layered.thoroughness": "50",
23325
+ "elk.spacing.nodeNode": "70",
23326
+ "elk.spacing.edgeNode": "75",
23327
+ "elk.spacing.edgeEdge": "22",
23328
+ "elk.layered.spacing.nodeNodeBetweenLayers": "120"
23329
+ }
23330
+ },
23331
+ {
23332
+ name: "longest-path",
23333
+ options: {
23334
+ ...bk,
23335
+ "elk.layered.layering.strategy": "LONGEST_PATH",
23336
+ "elk.layered.crossingMinimization.greedySwitch.type": "TWO_SIDED",
23337
+ "elk.layered.thoroughness": "50"
23338
+ }
23339
+ },
23340
+ {
23341
+ name: "bounded-width",
23342
+ options: {
23343
+ ...bk,
23344
+ "elk.layered.layering.strategy": "COFFMAN_GRAHAM",
23345
+ "elk.layered.layering.coffmanGraham.layerBound": "3",
23346
+ "elk.layered.crossingMinimization.greedySwitch.type": "TWO_SIDED",
23347
+ "elk.layered.thoroughness": "50"
23348
+ }
23349
+ }
23350
+ ];
23351
+ }
23352
+ function countCrossings(edges) {
23353
+ let count = 0;
23354
+ for (let i = 0; i < edges.length; i++) {
23355
+ const a = edges[i].points;
23356
+ if (a.length < 2) continue;
23357
+ for (let j = i + 1; j < edges.length; j++) {
23358
+ const b = edges[j].points;
23359
+ if (b.length < 2) continue;
23360
+ if (edges[i].source === edges[j].source) continue;
23361
+ if (edges[i].source === edges[j].target) continue;
23362
+ if (edges[i].target === edges[j].source) continue;
23363
+ if (edges[i].target === edges[j].target) continue;
23364
+ for (let ai = 0; ai < a.length - 1; ai++) {
23365
+ for (let bi = 0; bi < b.length - 1; bi++) {
23366
+ if (segmentsCross(a[ai], a[ai + 1], b[bi], b[bi + 1])) count++;
23367
+ }
23368
+ }
23369
+ }
23370
+ }
23371
+ return count;
23372
+ }
23373
+ function segmentsCross(p1, p2, p3, p4) {
23374
+ const d1x = p2.x - p1.x;
23375
+ const d1y = p2.y - p1.y;
23376
+ const d2x = p4.x - p3.x;
23377
+ const d2y = p4.y - p3.y;
23378
+ const denom = d1x * d2y - d1y * d2x;
23379
+ if (Math.abs(denom) < 1e-9) return false;
23380
+ const t = ((p3.x - p1.x) * d2y - (p3.y - p1.y) * d2x) / denom;
23381
+ const s = ((p3.x - p1.x) * d1y - (p3.y - p1.y) * d1x) / denom;
23382
+ const EPS = 1e-3;
23383
+ return t > EPS && t < 1 - EPS && s > EPS && s < 1 - EPS;
23384
+ }
23385
+ function countTotalBends(edges) {
23386
+ let bends = 0;
23387
+ for (const e of edges) bends += Math.max(0, e.points.length - 2);
23388
+ return bends;
23389
+ }
23390
+ function scoreLayout(layout) {
23391
+ return {
23392
+ crossings: countCrossings(layout.edges),
23393
+ bends: countTotalBends(layout.edges),
23394
+ area: layout.width * layout.height
23395
+ };
23396
+ }
23397
+ function cmpScore(a, b) {
23398
+ const aBucket = a.crossings <= CROSSINGS_FORGIVENESS ? 0 : a.crossings;
23399
+ const bBucket = b.crossings <= CROSSINGS_FORGIVENESS ? 0 : b.crossings;
23400
+ if (aBucket !== bBucket) return aBucket - bBucket;
23401
+ if (a.area !== b.area) return a.area - b.area;
23402
+ return a.bends - b.bends;
23403
+ }
23404
+ async function layoutBoxesAndLines(parsed, collapseInfo, layoutOptions) {
23405
+ const hideDescriptions = layoutOptions?.hideDescriptions ?? false;
23406
+ const direction = parsed.direction === "TB" ? "DOWN" : "RIGHT";
23407
+ const collapsedGroupLabels = /* @__PURE__ */ new Set();
23408
+ if (collapseInfo) {
23409
+ const missingGroups = /* @__PURE__ */ new Set();
23410
+ for (const og of collapseInfo.originalGroups) {
23411
+ if (!parsed.groups.some((g) => g.label === og.label)) {
23412
+ missingGroups.add(og.label);
23413
+ }
23414
+ }
23415
+ for (const label of missingGroups) {
23416
+ const og = collapseInfo.originalGroups.find((g) => g.label === label);
23417
+ const parentLabel = og?.parentGroup;
23418
+ if (!parentLabel || !missingGroups.has(parentLabel)) {
23419
+ collapsedGroupLabels.add(label);
23420
+ }
23421
+ }
23422
+ }
23423
+ const nodeSizes = /* @__PURE__ */ new Map();
23424
+ let maxDescHeight = 0;
23425
+ for (const node of parsed.nodes) {
23426
+ const size = hideDescriptions ? { width: NODE_WIDTH, height: NODE_HEIGHT } : computeNodeSize(node);
23427
+ nodeSizes.set(node.label, size);
23428
+ if (!hideDescriptions && node.description && node.description.length > 0) {
23429
+ maxDescHeight = Math.max(maxDescHeight, size.height);
23430
+ }
23431
+ }
23432
+ if (maxDescHeight > 0) {
23433
+ for (const node of parsed.nodes) {
23434
+ if (node.description && node.description.length > 0) {
23435
+ const size = nodeSizes.get(node.label);
23436
+ nodeSizes.set(node.label, { width: size.width, height: maxDescHeight });
23437
+ }
23438
+ }
23439
+ }
23440
+ const expandedGroupSet = new Set(parsed.groups.map((g) => g.label));
23441
+ const gid = (label) => `__group_${label}`;
23442
+ function buildGraph() {
23443
+ const nodeById = /* @__PURE__ */ new Map();
23444
+ const parentOf = /* @__PURE__ */ new Map();
23445
+ for (const node of parsed.nodes) {
23446
+ const size = nodeSizes.get(node.label);
23447
+ nodeById.set(node.label, {
23448
+ id: node.label,
23449
+ width: size.width,
23450
+ height: size.height,
23451
+ labels: [{ text: node.label }]
23452
+ });
23453
+ }
23454
+ for (const group of parsed.groups) {
23455
+ nodeById.set(gid(group.label), {
23456
+ id: gid(group.label),
23457
+ labels: [{ text: group.label }],
23458
+ layoutOptions: {
23459
+ "elk.padding": `[top=${CONTAINER_PAD_TOP2},left=${CONTAINER_PAD_X3},bottom=${CONTAINER_PAD_BOTTOM3},right=${CONTAINER_PAD_X3}]`,
23460
+ // Suggest square-ish containers — has limited effect with
23461
+ // INCLUDE_CHILDREN but doesn't hurt.
23462
+ "elk.aspectRatio": "1.4"
23463
+ },
23464
+ children: [],
23465
+ edges: []
23466
+ });
23467
+ }
23468
+ for (const label of collapsedGroupLabels) {
23469
+ nodeById.set(gid(label), {
23470
+ id: gid(label),
23471
+ width: NODE_WIDTH,
23472
+ height: NODE_HEIGHT,
23473
+ labels: [{ text: label }]
23474
+ });
23475
+ }
23476
+ for (const group of parsed.groups) {
23477
+ if (group.parentGroup && nodeById.has(gid(group.parentGroup))) {
23478
+ parentOf.set(gid(group.label), gid(group.parentGroup));
23479
+ }
23480
+ }
23481
+ if (collapseInfo) {
23482
+ for (const label of collapsedGroupLabels) {
23483
+ const og = collapseInfo.originalGroups.find((g) => g.label === label);
23484
+ if (og?.parentGroup && !collapsedGroupLabels.has(og.parentGroup) && nodeById.has(gid(og.parentGroup))) {
23485
+ parentOf.set(gid(label), gid(og.parentGroup));
23486
+ }
23487
+ }
23488
+ }
23489
+ for (const group of parsed.groups) {
23490
+ for (const child of group.children) {
23491
+ if (expandedGroupSet.has(child)) continue;
23492
+ if (nodeById.has(child)) {
23493
+ parentOf.set(child, gid(group.label));
23494
+ }
23495
+ }
23496
+ }
23497
+ const roots = [];
23498
+ for (const [id, node] of nodeById) {
23499
+ const parentId = parentOf.get(id);
23500
+ if (parentId) {
23501
+ const parent = nodeById.get(parentId);
23502
+ parent.children = parent.children ?? [];
23503
+ parent.children.push(node);
23504
+ } else {
23505
+ roots.push(node);
23506
+ }
23507
+ }
23508
+ const rootEdges = [];
23509
+ for (let i = 0; i < parsed.edges.length; i++) {
23510
+ const edge = parsed.edges[i];
23511
+ if (!nodeById.has(edge.source) || !nodeById.has(edge.target)) continue;
23512
+ rootEdges.push({
23513
+ id: `e${i}`,
23514
+ sources: [edge.source],
23515
+ targets: [edge.target]
23516
+ });
23517
+ }
23518
+ return { roots, rootEdges };
23519
+ }
23520
+ async function runVariant(variant) {
23521
+ const { roots, rootEdges } = buildGraph();
23522
+ const elkRoot = {
23523
+ id: "root",
23524
+ layoutOptions: {
23525
+ ...variant.options,
23526
+ "elk.direction": direction,
23527
+ "elk.padding": `[top=${MARGIN3},left=${MARGIN3},bottom=${MARGIN3},right=${MARGIN3}]`
23528
+ },
23529
+ children: roots,
23530
+ edges: rootEdges
23531
+ };
23532
+ const result = await getElk().layout(elkRoot);
23533
+ return extractLayout(result);
23534
+ }
23535
+ function extractLayout(result) {
23536
+ const layoutNodes = [];
23537
+ const layoutGroups = [];
23538
+ const allEdges = [];
23539
+ const containerAbs = /* @__PURE__ */ new Map();
23540
+ function walk(n, offsetX, offsetY, isRoot) {
23541
+ const nx = (n.x ?? 0) + offsetX;
23542
+ const ny = (n.y ?? 0) + offsetY;
23543
+ const nw = n.width ?? 0;
23544
+ const nh = n.height ?? 0;
23545
+ if (isRoot) {
23546
+ containerAbs.set("root", { x: nx, y: ny });
23547
+ } else {
23548
+ const isGroup = n.id.startsWith("__group_");
23549
+ if (isGroup) {
23550
+ const label = n.id.slice("__group_".length);
23551
+ const collapsed = collapsedGroupLabels.has(label);
23552
+ const og = collapseInfo?.originalGroups.find(
23553
+ (g) => g.label === label
23554
+ );
23555
+ const pg = parsed.groups.find((g) => g.label === label);
23556
+ layoutGroups.push({
23557
+ label,
23558
+ lineNumber: pg?.lineNumber ?? og?.lineNumber ?? 0,
23559
+ x: nx + nw / 2,
23560
+ y: ny + nh / 2,
23561
+ width: nw,
23562
+ height: nh,
23563
+ collapsed,
23564
+ childCount: collapsed ? collapseInfo?.collapsedChildCounts.get(label) ?? 0 : void 0
23565
+ });
23566
+ if (!collapsed) containerAbs.set(n.id, { x: nx, y: ny });
23567
+ } else {
23568
+ layoutNodes.push({
23569
+ label: n.id,
23570
+ x: nx + nw / 2,
23571
+ y: ny + nh / 2,
23572
+ width: nw,
23573
+ height: nh
23574
+ });
23575
+ }
23576
+ }
23577
+ if (n.edges) for (const e of n.edges) allEdges.push(e);
23578
+ if (n.children) for (const c of n.children) walk(c, nx, ny, false);
23579
+ }
23580
+ walk(result, 0, 0, true);
23581
+ const edgeYOffsets = new Array(parsed.edges.length).fill(0);
23582
+ const edgeParallelCounts = new Array(parsed.edges.length).fill(1);
23583
+ const parallelGroups = /* @__PURE__ */ new Map();
23584
+ for (let i = 0; i < parsed.edges.length; i++) {
23585
+ const edge = parsed.edges[i];
23586
+ const [a, b] = edge.source < edge.target ? [edge.source, edge.target] : [edge.target, edge.source];
23587
+ const key = `${a}\0${b}`;
23588
+ if (!parallelGroups.has(key)) parallelGroups.set(key, []);
23589
+ parallelGroups.get(key).push(i);
23590
+ }
23591
+ for (const group of parallelGroups.values()) {
23592
+ const capped = group.slice(0, MAX_PARALLEL_EDGES);
23593
+ for (const idx of group.slice(MAX_PARALLEL_EDGES)) {
23594
+ edgeParallelCounts[idx] = 0;
23595
+ }
23596
+ if (capped.length < 2) continue;
23597
+ for (let j = 0; j < capped.length; j++) {
23598
+ edgeYOffsets[capped[j]] = (j - (capped.length - 1) / 2) * PARALLEL_SPACING;
23599
+ edgeParallelCounts[capped[j]] = capped.length;
23600
+ }
23601
+ }
23602
+ const edgeById = /* @__PURE__ */ new Map();
23603
+ for (const e of allEdges) edgeById.set(e.id, e);
23604
+ const layoutEdges = [];
23605
+ for (let i = 0; i < parsed.edges.length; i++) {
23606
+ const edge = parsed.edges[i];
23607
+ if (edgeParallelCounts[i] === 0) continue;
23608
+ const elkEdge = edgeById.get(`e${i}`);
23609
+ if (!elkEdge || !elkEdge.sections || elkEdge.sections.length === 0)
23610
+ continue;
23611
+ const container = elkEdge.container ?? "root";
23612
+ const off = containerAbs.get(container) ?? { x: 0, y: 0 };
23613
+ const s = elkEdge.sections[0];
23614
+ const points = [
23615
+ { x: s.startPoint.x + off.x, y: s.startPoint.y + off.y },
23616
+ ...(s.bendPoints ?? []).map((p) => ({
23617
+ x: p.x + off.x,
23618
+ y: p.y + off.y
23619
+ })),
23620
+ { x: s.endPoint.x + off.x, y: s.endPoint.y + off.y }
23621
+ ];
23622
+ let labelX;
23623
+ let labelY;
23624
+ if (edge.label && points.length >= 2) {
23625
+ const mid = Math.floor(points.length / 2);
23626
+ labelX = points[mid].x;
23627
+ labelY = points[mid].y - 10;
23628
+ }
23629
+ layoutEdges.push({
23630
+ source: edge.source,
23631
+ target: edge.target,
23632
+ label: edge.label,
23633
+ bidirectional: edge.bidirectional,
23634
+ lineNumber: edge.lineNumber,
23635
+ points,
23636
+ labelX,
23637
+ labelY,
23638
+ yOffset: edgeYOffsets[i],
23639
+ parallelCount: edgeParallelCounts[i],
23640
+ metadata: edge.metadata,
23641
+ deferred: true
23642
+ });
23643
+ }
23644
+ let maxX = 0;
23645
+ let maxY = 0;
23646
+ for (const node of layoutNodes) {
23647
+ maxX = Math.max(maxX, node.x + node.width / 2);
23648
+ maxY = Math.max(maxY, node.y + node.height / 2);
23649
+ }
23650
+ for (const group of layoutGroups) {
23651
+ maxX = Math.max(maxX, group.x + group.width / 2);
23652
+ maxY = Math.max(maxY, group.y + group.height / 2);
23653
+ }
23654
+ return {
23655
+ nodes: layoutNodes,
23656
+ edges: layoutEdges,
23657
+ groups: layoutGroups,
23658
+ width: maxX + MARGIN3,
23659
+ height: maxY + MARGIN3
23660
+ };
23661
+ }
23662
+ const N = parsed.nodes.length + parsed.groups.length;
23663
+ const E = parsed.edges.length;
23664
+ const trivial = N < 8 && E < 10;
23665
+ const variants = trivial ? [getVariants()[1]] : getVariants();
23666
+ const results = await Promise.all(variants.map((v) => runVariant(v)));
23667
+ let best = results[0];
23668
+ let bestScore = scoreLayout(best);
23669
+ for (let i = 1; i < results.length; i++) {
23670
+ const s = scoreLayout(results[i]);
23671
+ if (cmpScore(s, bestScore) < 0) {
23672
+ best = results[i];
23673
+ bestScore = s;
23674
+ }
23675
+ }
23676
+ return best;
23677
+ }
23678
+ var 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;
23679
+ var init_layout5 = __esm({
23680
+ "src/boxes-and-lines/layout.ts"() {
23681
+ "use strict";
23682
+ MARGIN3 = 40;
23683
+ CONTAINER_PAD_X3 = 30;
23684
+ CONTAINER_PAD_TOP2 = 40;
23685
+ CONTAINER_PAD_BOTTOM3 = 24;
23686
+ MAX_PARALLEL_EDGES = 5;
23687
+ PARALLEL_SPACING = 22;
23688
+ PHI = 1.618;
23689
+ NODE_HEIGHT = 60;
23690
+ NODE_WIDTH = Math.round(NODE_HEIGHT * PHI);
23691
+ DESC_NODE_WIDTH = 140;
23692
+ DESC_FONT_SIZE2 = 10;
23693
+ DESC_LINE_HEIGHT2 = 1.4;
23694
+ DESC_PADDING = 8;
23695
+ SEPARATOR_GAP5 = 4;
23696
+ MAX_DESC_LINES2 = 6;
23697
+ MAX_LABEL_LINES = 3;
23698
+ LABEL_LINE_HEIGHT = 1.3;
23699
+ LABEL_PAD = 12;
23700
+ elkInstance = null;
23701
+ CROSSINGS_FORGIVENESS = 1;
23702
+ }
23703
+ });
23704
+
23689
23705
  // src/mindmap/text-wrap.ts
23690
23706
  function tokenize(text) {
23691
23707
  const tokens = [];
@@ -23824,7 +23840,7 @@ var layout_exports6 = {};
23824
23840
  __export(layout_exports6, {
23825
23841
  layoutMindmap: () => layoutMindmap
23826
23842
  });
23827
- function layoutMindmap(parsed, palette, options) {
23843
+ function layoutMindmap(parsed, _palette, options) {
23828
23844
  const roots = parsed.roots;
23829
23845
  if (roots.length === 0) {
23830
23846
  return { nodes: [], edges: [], width: 0, height: 0 };
@@ -24720,7 +24736,7 @@ function layoutElement(el, x, y, width) {
24720
24736
  node.height = getElementHeight(el);
24721
24737
  return node;
24722
24738
  }
24723
- const isInlineRow = el.metadata._inlineRow === "true" || el.metadata._labelField === "true";
24739
+ const isInlineRow = el.metadata["_inlineRow"] === "true" || el.metadata["_labelField"] === "true";
24724
24740
  const padTop = isInlineRow ? 0 : GROUP_PADDING_TOP;
24725
24741
  const padBottom = isInlineRow ? 0 : GROUP_PADDING_BOTTOM;
24726
24742
  const padX = isInlineRow ? 0 : GROUP_PADDING_X;
@@ -24769,7 +24785,7 @@ function allocateEqualWidths(children, totalWidth) {
24769
24785
  }
24770
24786
  function getElementHeight(el) {
24771
24787
  if (el.type === "heading") {
24772
- return el.headingLevel === 2 ? ELEMENT_HEIGHTS.subheading ?? 36 : ELEMENT_HEIGHTS.heading ?? 48;
24788
+ return el.headingLevel === 2 ? ELEMENT_HEIGHTS["subheading"] ?? 36 : ELEMENT_HEIGHTS["heading"] ?? 48;
24773
24789
  }
24774
24790
  if (el.type === "textInput" && el.fieldVariant === "textarea") {
24775
24791
  return 80;
@@ -24783,16 +24799,16 @@ function getElementHeight(el) {
24783
24799
  if (el.type === "image") {
24784
24800
  if (el.imageHint === "round") return 80;
24785
24801
  if (el.imageHint === "wide") return 80;
24786
- return ELEMENT_HEIGHTS.image ?? 120;
24802
+ return ELEMENT_HEIGHTS["image"] ?? 120;
24787
24803
  }
24788
- if (el.metadata._labelField === "true") {
24804
+ if (el.metadata["_labelField"] === "true") {
24789
24805
  return 36;
24790
24806
  }
24791
24807
  return ELEMENT_HEIGHTS[el.type] ?? 24;
24792
24808
  }
24793
24809
  function getSpacingAfter(el) {
24794
24810
  if (el.type === "heading" && el.headingLevel === 2) {
24795
- return SPACING_AFTER.subheading ?? 12;
24811
+ return SPACING_AFTER["subheading"] ?? 12;
24796
24812
  }
24797
24813
  return SPACING_AFTER[el.type] ?? 8;
24798
24814
  }
@@ -24800,7 +24816,7 @@ function computeFieldAlignX(children) {
24800
24816
  let maxLabelWidth = 0;
24801
24817
  let labelFieldCount = 0;
24802
24818
  for (const child of children) {
24803
- if (child.metadata._labelField === "true" && child.children.length >= 2) {
24819
+ if (child.metadata["_labelField"] === "true" && child.children.length >= 2) {
24804
24820
  const labelEl = child.children[0];
24805
24821
  const labelWidth = labelEl.label.length * CHAR_WIDTH5;
24806
24822
  maxLabelWidth = Math.max(maxLabelWidth, labelWidth);
@@ -25012,7 +25028,7 @@ function renderNode(parent, node, ctx, depth) {
25012
25028
  function renderGroup(g, node, ctx, depth) {
25013
25029
  const { palette, isTransparent } = ctx;
25014
25030
  const el = node.element;
25015
- if (el.metadata._inlineRow === "true" || el.metadata._labelField === "true") {
25031
+ if (el.metadata["_inlineRow"] === "true" || el.metadata["_labelField"] === "true") {
25016
25032
  for (const child of node.children) {
25017
25033
  renderNode(g, child, ctx, depth);
25018
25034
  }
@@ -25140,7 +25156,7 @@ function renderDivider(g, node, ctx) {
25140
25156
  function renderText(g, node, ctx) {
25141
25157
  const { palette } = ctx;
25142
25158
  const el = node.element;
25143
- if (el.metadata._labelField === "true" && el.children.length >= 2) {
25159
+ if (el.metadata["_labelField"] === "true" && el.children.length >= 2) {
25144
25160
  for (const child of node.children) {
25145
25161
  renderNode(g, child, ctx, 0);
25146
25162
  }
@@ -25434,7 +25450,7 @@ __export(layout_exports8, {
25434
25450
  layoutC4Deployment: () => layoutC4Deployment,
25435
25451
  rollUpContextRelationships: () => rollUpContextRelationships
25436
25452
  });
25437
- import dagre5 from "@dagrejs/dagre";
25453
+ import dagre4 from "@dagrejs/dagre";
25438
25454
  function computeEdgePenalty(edgeList, nodePositions, degrees, nodeGeometry) {
25439
25455
  let penalty = 0;
25440
25456
  for (const edge of edgeList) {
@@ -25875,7 +25891,7 @@ function layoutC4Context(parsed, activeTagGroup) {
25875
25891
  }
25876
25892
  const contextRels = rollUpContextRelationships(parsed);
25877
25893
  const spacing = computeAdaptiveSpacing(contextRels);
25878
- const g = new dagre5.graphlib.Graph();
25894
+ const g = new dagre4.graphlib.Graph();
25879
25895
  g.setGraph({
25880
25896
  rankdir: "TB",
25881
25897
  nodesep: spacing.nodesep,
@@ -25896,7 +25912,7 @@ function layoutC4Context(parsed, activeTagGroup) {
25896
25912
  g.setEdge(rel.sourceName, rel.targetName, { label: rel.label ?? "" });
25897
25913
  }
25898
25914
  }
25899
- dagre5.layout(g);
25915
+ dagre4.layout(g);
25900
25916
  reduceCrossings(
25901
25917
  g,
25902
25918
  validRels.map((r) => ({ source: r.sourceName, target: r.targetName }))
@@ -26068,7 +26084,7 @@ function layoutC4Containers(parsed, systemName, activeTagGroup) {
26068
26084
  }
26069
26085
  }
26070
26086
  const hasGroups = elementToGroup.size > 0;
26071
- const g = hasGroups ? new dagre5.graphlib.Graph({ compound: true }) : new dagre5.graphlib.Graph();
26087
+ const g = hasGroups ? new dagre4.graphlib.Graph({ compound: true }) : new dagre4.graphlib.Graph();
26072
26088
  g.setDefaultEdgeLabel(() => ({}));
26073
26089
  if (hasGroups) {
26074
26090
  const seenGroups = /* @__PURE__ */ new Set();
@@ -26146,7 +26162,7 @@ function layoutC4Containers(parsed, systemName, activeTagGroup) {
26146
26162
  g.setEdge(rel.sourceName, rel.targetName, { label: rel.label ?? "" });
26147
26163
  }
26148
26164
  }
26149
- dagre5.layout(g);
26165
+ dagre4.layout(g);
26150
26166
  const nodeGroupMap = hasGroups ? new Map([...elementToGroup.entries()].map(([k, v]) => [k, v.name])) : void 0;
26151
26167
  reduceCrossings(
26152
26168
  g,
@@ -26472,7 +26488,7 @@ function layoutC4Components(parsed, systemName, containerName, activeTagGroup) {
26472
26488
  }
26473
26489
  }
26474
26490
  const hasGroups = elementToGroup.size > 0;
26475
- const g = hasGroups ? new dagre5.graphlib.Graph({ compound: true }) : new dagre5.graphlib.Graph();
26491
+ const g = hasGroups ? new dagre4.graphlib.Graph({ compound: true }) : new dagre4.graphlib.Graph();
26476
26492
  g.setDefaultEdgeLabel(() => ({}));
26477
26493
  if (hasGroups) {
26478
26494
  const seenGroups = /* @__PURE__ */ new Set();
@@ -26556,7 +26572,7 @@ function layoutC4Components(parsed, systemName, containerName, activeTagGroup) {
26556
26572
  g.setEdge(rel.sourceName, rel.targetName, { label: rel.label ?? "" });
26557
26573
  }
26558
26574
  }
26559
- dagre5.layout(g);
26575
+ dagre4.layout(g);
26560
26576
  const nodeGroupMap = hasGroups ? new Map([...elementToGroup.entries()].map(([k, v]) => [k, v.name])) : void 0;
26561
26577
  reduceCrossings(
26562
26578
  g,
@@ -26845,7 +26861,7 @@ function layoutC4Deployment(parsed, activeTagGroup) {
26845
26861
  for (const r of refEntries) {
26846
26862
  nameToElement.set(r.element.name, r.element);
26847
26863
  }
26848
- const g = new dagre5.graphlib.Graph({ compound: true });
26864
+ const g = new dagre4.graphlib.Graph({ compound: true });
26849
26865
  g.setDefaultEdgeLabel(() => ({}));
26850
26866
  for (const [infraId] of infraIds) {
26851
26867
  g.setNode(infraId, {});
@@ -26889,7 +26905,7 @@ function layoutC4Deployment(parsed, activeTagGroup) {
26889
26905
  g.setEdge(rel.sourceName, rel.targetName, { label: rel.label ?? "" });
26890
26906
  }
26891
26907
  }
26892
- dagre5.layout(g);
26908
+ dagre4.layout(g);
26893
26909
  const nodeInfraMap = /* @__PURE__ */ new Map();
26894
26910
  for (const r of refEntries) nodeInfraMap.set(r.element.name, r.infraId);
26895
26911
  reduceCrossings(
@@ -28121,7 +28137,7 @@ var layout_exports9 = {};
28121
28137
  __export(layout_exports9, {
28122
28138
  layoutGraph: () => layoutGraph
28123
28139
  });
28124
- import dagre6 from "@dagrejs/dagre";
28140
+ import dagre5 from "@dagrejs/dagre";
28125
28141
  function computeNodeWidth(label, shape) {
28126
28142
  if (shape === "pseudostate") return 24;
28127
28143
  const base = Math.max(120, label.length * 9 + 40);
@@ -28154,7 +28170,7 @@ function layoutGraph(graph, options) {
28154
28170
  if (allNodes.length === 0) {
28155
28171
  return { nodes: [], edges: [], groups: [], width: 0, height: 0 };
28156
28172
  }
28157
- const g = new dagre6.graphlib.Graph({ compound: true });
28173
+ const g = new dagre5.graphlib.Graph({ compound: true });
28158
28174
  g.setGraph({
28159
28175
  rankdir: graph.direction,
28160
28176
  nodesep: 50,
@@ -28190,7 +28206,7 @@ function layoutGraph(graph, options) {
28190
28206
  label: edge.label ?? ""
28191
28207
  });
28192
28208
  }
28193
- dagre6.layout(g);
28209
+ dagre5.layout(g);
28194
28210
  const collapsedGroupIds = collapsedChildCounts ? new Set(collapsedChildCounts.keys()) : /* @__PURE__ */ new Set();
28195
28211
  const layoutNodes = allNodes.map((node) => {
28196
28212
  const pos = g.node(node.id);
@@ -28624,7 +28640,7 @@ function renderFlowchart(container, graph, layout, palette, isDark, onClickItem,
28624
28640
  endTerminalIds.add(node.id);
28625
28641
  }
28626
28642
  }
28627
- const colorOff = graph.options?.color === "off";
28643
+ const colorOff = graph.options?.["color"] === "off";
28628
28644
  const solid = graph.options?.["solid-fill"] === "on";
28629
28645
  for (const node of layout.nodes) {
28630
28646
  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);
@@ -29553,7 +29569,7 @@ __export(layout_exports10, {
29553
29569
  layoutInfra: () => layoutInfra,
29554
29570
  separateGroups: () => separateGroups
29555
29571
  });
29556
- import dagre7 from "@dagrejs/dagre";
29572
+ import dagre6 from "@dagrejs/dagre";
29557
29573
  function countDisplayProps(node, expanded, options) {
29558
29574
  if (!expanded) return 0;
29559
29575
  let count = node.properties.filter((p) => DISPLAY_KEYS.has(p.key)).length;
@@ -29856,7 +29872,7 @@ function layoutInfra(computed, expandedNodeIds, collapsedNodes) {
29856
29872
  };
29857
29873
  }
29858
29874
  const isLR = computed.direction !== "TB";
29859
- const g = new dagre7.graphlib.Graph();
29875
+ const g = new dagre6.graphlib.Graph();
29860
29876
  g.setGraph({
29861
29877
  rankdir: computed.direction === "TB" ? "TB" : "LR",
29862
29878
  nodesep: isLR ? 70 : 60,
@@ -29907,7 +29923,7 @@ function layoutInfra(computed, expandedNodeIds, collapsedNodes) {
29907
29923
  g.setEdge(edge.sourceId, edge.targetId, { label: edge.label });
29908
29924
  }
29909
29925
  }
29910
- dagre7.layout(g);
29926
+ dagre6.layout(g);
29911
29927
  const layoutNodes = computed.nodes.map((node) => {
29912
29928
  const pos = g.node(node.id);
29913
29929
  return {
@@ -30816,7 +30832,7 @@ function renderGroups(svg, groups, palette, _isDark) {
30816
30832
  }
30817
30833
  }
30818
30834
  }
30819
- function renderEdgePaths(svg, edges, nodes, groups, palette, isDark, animate, direction, speedMultiplier = 1) {
30835
+ function renderEdgePaths(svg, edges, nodes, groups, palette, _isDark, animate, direction, speedMultiplier = 1) {
30820
30836
  const nodeMap = new Map(nodes.map((n) => [n.id, n]));
30821
30837
  const maxRps = Math.max(...edges.map((e) => e.computedRps), 1);
30822
30838
  const { srcPts, tgtPts } = computePortPts(edges, nodeMap, direction);
@@ -30857,7 +30873,7 @@ function renderEdgePaths(svg, edges, nodes, groups, palette, isDark, animate, di
30857
30873
  }
30858
30874
  }
30859
30875
  }
30860
- function renderEdgeLabels(svg, edges, nodes, groups, palette, isDark, animate, direction) {
30876
+ function renderEdgeLabels(svg, edges, nodes, groups, palette, _isDark, animate, direction) {
30861
30877
  const nodeMap = new Map(nodes.map((n) => [n.id, n]));
30862
30878
  const { srcPts, tgtPts } = computePortPts(edges, nodeMap, direction);
30863
30879
  for (const edge of edges) {
@@ -31596,7 +31612,7 @@ function sampleBetaPert(o, m, p, rng) {
31596
31612
  const beta = 1 + 4 * (p - m) / range;
31597
31613
  return o + sampleBeta(alpha, beta, rng) * range;
31598
31614
  }
31599
- function simulate(resolved, expanded, predecessors, successors, topo, terminals, poisoned, opts) {
31615
+ function simulate(resolved, expanded, _predecessors, _successors, topo, terminals, poisoned, opts) {
31600
31616
  const rng = mulberry32(opts.seed);
31601
31617
  const expById = /* @__PURE__ */ new Map();
31602
31618
  for (const e of expanded) expById.set(e.id, e);
@@ -32612,7 +32628,7 @@ __export(layout_exports11, {
32612
32628
  layoutPert: () => layoutPert,
32613
32629
  relayoutPert: () => relayoutPert
32614
32630
  });
32615
- import dagre8 from "@dagrejs/dagre";
32631
+ import dagre7 from "@dagrejs/dagre";
32616
32632
  function computeNodeSizing(resolved) {
32617
32633
  const unit = resolved.options.timeUnit;
32618
32634
  const sprintMode = resolved.options.sprintMode;
@@ -32720,7 +32736,7 @@ function relayoutPert(resolved, overrides, collapsedGroupIds = /* @__PURE__ */ n
32720
32736
  }
32721
32737
  }
32722
32738
  const dagreId = (id) => memberToGroup.get(id) ?? id;
32723
- const g = new dagre8.graphlib.Graph();
32739
+ const g = new dagre7.graphlib.Graph();
32724
32740
  g.setGraph({
32725
32741
  rankdir: resolved.options.direction,
32726
32742
  nodesep: 50,
@@ -32759,7 +32775,7 @@ function relayoutPert(resolved, overrides, collapsedGroupIds = /* @__PURE__ */ n
32759
32775
  seenEdges.add(k);
32760
32776
  g.setEdge(src, tgt, {});
32761
32777
  }
32762
- dagre8.layout(g);
32778
+ dagre7.layout(g);
32763
32779
  const swimApplied = applySwimLanes(
32764
32780
  g,
32765
32781
  resolved,
@@ -32879,7 +32895,7 @@ function relayoutPert(resolved, overrides, collapsedGroupIds = /* @__PURE__ */ n
32879
32895
  height: totalH + DIAGRAM_PADDING10
32880
32896
  };
32881
32897
  }
32882
- function applySwimLanes(g, resolved, memberToGroup, collapsedGroupIds) {
32898
+ function applySwimLanes(g, resolved, _memberToGroup, collapsedGroupIds) {
32883
32899
  const expanded = resolved.groups.filter(
32884
32900
  (rg) => !collapsedGroupIds.has(rg.group.id)
32885
32901
  );
@@ -33105,7 +33121,7 @@ function reduceCrossings2(g, direction) {
33105
33121
  buckets.get(key).push(id);
33106
33122
  }
33107
33123
  const edges = g.edges().map((e) => ({ v: e.v, w: e.w }));
33108
- const countCrossings = () => {
33124
+ const countCrossings2 = () => {
33109
33125
  let total = 0;
33110
33126
  for (let i = 0; i < edges.length; i++) {
33111
33127
  const a = edges[i];
@@ -33118,13 +33134,13 @@ function reduceCrossings2(g, direction) {
33118
33134
  const b1 = g.node(b.v);
33119
33135
  const b2 = g.node(b.w);
33120
33136
  if (!b1 || !b2) continue;
33121
- if (segmentsCross(a1, a2, b1, b2)) total++;
33137
+ if (segmentsCross2(a1, a2, b1, b2)) total++;
33122
33138
  }
33123
33139
  }
33124
33140
  return total;
33125
33141
  };
33126
33142
  const MAX_ITER = 8;
33127
- let baseline = countCrossings();
33143
+ let baseline = countCrossings2();
33128
33144
  if (baseline === 0) return;
33129
33145
  for (let iter = 0; iter < MAX_ITER; iter++) {
33130
33146
  let improved = false;
@@ -33142,7 +33158,7 @@ function reduceCrossings2(g, direction) {
33142
33158
  const bv = bn[slotAxis];
33143
33159
  an[slotAxis] = bv;
33144
33160
  bn[slotAxis] = av;
33145
- const after = countCrossings();
33161
+ const after = countCrossings2();
33146
33162
  if (after < baseline) {
33147
33163
  baseline = after;
33148
33164
  improved = true;
@@ -33163,7 +33179,7 @@ function reduceCrossings2(g, direction) {
33163
33179
  data.points = smoothEdge(src, tgt, direction);
33164
33180
  }
33165
33181
  }
33166
- function segmentsCross(a1, a2, b1, b2) {
33182
+ function segmentsCross2(a1, a2, b1, b2) {
33167
33183
  const ccw = (p, q, r) => (q.x - p.x) * (r.y - p.y) - (q.y - p.y) * (r.x - p.x);
33168
33184
  const d1 = ccw(b1, b2, a1);
33169
33185
  const d2 = ccw(b1, b2, a2);
@@ -35171,12 +35187,6 @@ function calculateSchedule(parsed) {
35171
35187
  const warn = (line12, message) => {
35172
35188
  diagnostics.push(makeDgmoError(line12, message, "warning"));
35173
35189
  };
35174
- const _fail = (line12, message) => {
35175
- const diag = makeDgmoError(line12, message);
35176
- diagnostics.push(diag);
35177
- result.error = formatDgmoError(diag);
35178
- return result;
35179
- };
35180
35190
  const holidaySet = buildHolidaySet(parsed.holidays);
35181
35191
  let projectStart;
35182
35192
  if (parsed.options.start) {
@@ -35201,7 +35211,6 @@ function calculateSchedule(parsed) {
35201
35211
  }
35202
35212
  buildImplicitDeps(parsed.nodes, taskMap);
35203
35213
  for (const task of allTasks2) {
35204
- const _node = taskMap.get(task.id);
35205
35214
  for (const dep of task.dependencies) {
35206
35215
  const resolved = resolveTaskName(dep.targetName, allTasks2);
35207
35216
  if (isResolverError(resolved)) {
@@ -36742,7 +36751,7 @@ function buildControlsToggles(hasCriticalPath, criticalPathActive, hasDependenci
36742
36751
  }
36743
36752
  return toggles;
36744
36753
  }
36745
- 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) {
36754
+ 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) {
36746
36755
  let visibleGroups;
36747
36756
  if (activeGroupName) {
36748
36757
  const activeGroup = tagGroups.filter(
@@ -37705,7 +37714,7 @@ function resolveTaskColor(rt, activeTagGroup, resolved, seriesColors2, palette)
37705
37714
  }
37706
37715
  return palette.accent || seriesColors2[0] || "#4a90d9";
37707
37716
  }
37708
- function renderTimeScaleHorizontal(g, scale, innerWidth, innerHeight, textColor) {
37717
+ function renderTimeScaleHorizontal(g, scale, _innerWidth, innerHeight, textColor) {
37709
37718
  const [domainMin, domainMax] = scale.domain();
37710
37719
  const ticks = computeTimeTicks(domainMin, domainMax, scale);
37711
37720
  if (ticks.length < 2) return;
@@ -37952,7 +37961,7 @@ function renderState(container, graph, layout, palette, isDark, onClickItem, exp
37952
37961
  for (const group of layout.groups) {
37953
37962
  if (group.collapsed) collapsedGroupIds.add(group.id);
37954
37963
  }
37955
- const colorOff = graph.options?.color === "off";
37964
+ const colorOff = graph.options?.["color"] === "off";
37956
37965
  const solid = graph.options?.["solid-fill"] === "on";
37957
37966
  for (const node of layout.nodes) {
37958
37967
  const isCollapsedGroup = collapsedGroupIds.has(node.id);
@@ -38351,7 +38360,7 @@ function renderQuadrantFocus(container, parsed, quadrantPosition, palette, isDar
38351
38360
  }
38352
38361
  }
38353
38362
  }
38354
- function renderQuarterCircle(svg, parsed, quadrant, qColor, palette, isDark, width, height, mutedColor, tooltip, rootContainer, onClickItem) {
38363
+ function renderQuarterCircle(svg, parsed, quadrant, qColor, palette, isDark, width, height, mutedColor, _tooltip, rootContainer, onClickItem) {
38355
38364
  const padding = 8;
38356
38365
  const size = Math.min(width - padding, height - padding);
38357
38366
  const maxRadius = size * 0.95;
@@ -39441,7 +39450,7 @@ function estimateListingHeight(parsed) {
39441
39450
  );
39442
39451
  return LISTING_LINE_HEIGHT * (maxBlipsInQuadrant + 1) + LISTING_LINE_HEIGHT + LISTING_TOP_MARGIN;
39443
39452
  }
39444
- function createBlipPopover(container, palette, isDark) {
39453
+ function createBlipPopover(container, _palette, isDark) {
39445
39454
  container.style.position = "relative";
39446
39455
  const existing = container.querySelector(
39447
39456
  "[data-blip-popover]"
@@ -41308,7 +41317,7 @@ function computeEdgeLabelPosition(midAngle, radius, cx, cy, lineCount, maxCharLe
41308
41317
  labelAngle: best.labelAngle
41309
41318
  };
41310
41319
  }
41311
- function fitToCanvas(nodes, edges, parsed, cx, cy, radius, width, height, _isClockwise) {
41320
+ function fitToCanvas(nodes, edges, parsed, _cx, _cy, radius, width, height, _isClockwise) {
41312
41321
  const PADDING3 = 30;
41313
41322
  let contentMinX = Infinity, contentMaxX = -Infinity;
41314
41323
  let contentMinY = Infinity, contentMaxY = -Infinity;
@@ -42818,7 +42827,7 @@ function renderPhaseBar(svg, phase, x, y, width, palette, collapsed, autoColor,
42818
42827
  });
42819
42828
  }
42820
42829
  }
42821
- function renderTaskRow(svg, task, parsed, x, y, labelW, roleX, roleColW, palette, surfaceBg, solid, taskDiagnostics, hasAnyDiagnostic, rowContent, onClickLine, _onMarkerDragStart) {
42830
+ function renderTaskRow(svg, task, parsed, x, y, labelW, roleX, roleColW, palette, surfaceBg, solid, taskDiagnostics, _hasAnyDiagnostic, rowContent, onClickLine, _onMarkerDragStart) {
42822
42831
  const rowG = svg.append("g").attr("class", "raci-task-row").attr("data-task-id", task.id).attr("data-line-number", String(task.lineNumber));
42823
42832
  const labelX = x + 8;
42824
42833
  const labelMaxW = labelW - 16;
@@ -43624,7 +43633,6 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
43624
43633
  const messages = collapsed ? collapsed.messages : parsed.messages;
43625
43634
  const elements = collapsed ? collapsed.elements : parsed.elements;
43626
43635
  const groups = collapsed ? collapsed.groups : parsed.groups;
43627
- const collapsedGroupIds = collapsed?.collapsedGroupIds ?? /* @__PURE__ */ new Map();
43628
43636
  const collapsedSections = options?.collapsedSections;
43629
43637
  const sourceParticipants = collapsed ? collapsed.participants : parsed.participants;
43630
43638
  const participants = applyPositionOverrides(
@@ -43652,7 +43660,7 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
43652
43660
  return Math.min(NOTE_MAX_W, laneMax);
43653
43661
  };
43654
43662
  const charsForWidth = (maxW) => Math.floor((maxW - NOTE_PAD_H * 2 - NOTE_FOLD) / NOTE_CHAR_W);
43655
- const activationsOff = parsedOptions.activations?.toLowerCase() === "off";
43663
+ const activationsOff = parsedOptions["activations"]?.toLowerCase() === "off";
43656
43664
  const activeTagGroup = resolveActiveTagGroup(
43657
43665
  parsed.tagGroups,
43658
43666
  parsedOptions["active-tag"],
@@ -46608,7 +46616,7 @@ function renderTimelineGroupLegend(g, groups, groupColorMap, textColor, palette,
46608
46616
  legendX += pillW + GAP;
46609
46617
  }
46610
46618
  }
46611
- function renderTimeline(container, parsed, palette, isDark, onClickItem, exportDims, activeTagGroup, swimlaneTagGroup, onTagStateChange, viewMode) {
46619
+ function setupTimeline(container, parsed, palette, isDark, exportDims, activeTagGroup, swimlaneTagGroup) {
46612
46620
  d3Selection22.select(container).selectAll(":not([data-d3-tooltip])").remove();
46613
46621
  const solid = parsed.solidFill === true;
46614
46622
  const {
@@ -46617,19 +46625,17 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
46617
46625
  timelineEras,
46618
46626
  timelineMarkers,
46619
46627
  timelineSort,
46620
- timelineScale,
46621
- timelineSwimlanes,
46622
46628
  orientation
46623
46629
  } = parsed;
46624
- const title = parsed.noTitle ? null : parsed.title;
46625
- if (timelineEvents.length === 0) return;
46626
- if (swimlaneTagGroup == null && timelineSort === "tag" && parsed.timelineDefaultSwimlaneTG) {
46627
- swimlaneTagGroup = parsed.timelineDefaultSwimlaneTG;
46630
+ if (timelineEvents.length === 0) return null;
46631
+ let resolvedSwimlaneTG = swimlaneTagGroup ?? null;
46632
+ if (resolvedSwimlaneTG == null && timelineSort === "tag" && parsed.timelineDefaultSwimlaneTG) {
46633
+ resolvedSwimlaneTG = parsed.timelineDefaultSwimlaneTG;
46628
46634
  }
46629
46635
  const tooltip = createTooltip2(container, palette, isDark);
46630
46636
  const width = exportDims?.width ?? container.clientWidth;
46631
46637
  const height = exportDims?.height ?? container.clientHeight;
46632
- if (width <= 0 || height <= 0) return;
46638
+ if (width <= 0 || height <= 0) return null;
46633
46639
  const isVertical = orientation === "vertical";
46634
46640
  const textColor = palette.text;
46635
46641
  const mutedColor = palette.border;
@@ -46641,8 +46647,8 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
46641
46647
  groupColorMap.set(grp.name, grp.color ?? colors[i % colors.length]);
46642
46648
  });
46643
46649
  let tagLanes = null;
46644
- if (swimlaneTagGroup) {
46645
- const tagKey = swimlaneTagGroup.toLowerCase();
46650
+ if (resolvedSwimlaneTG) {
46651
+ const tagKey = resolvedSwimlaneTG.toLowerCase();
46646
46652
  const tagGroup = parsed.timelineTagGroups.find(
46647
46653
  (g) => g.name.toLowerCase() === tagKey
46648
46654
  );
@@ -46673,7 +46679,7 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
46673
46679
  }
46674
46680
  }
46675
46681
  }
46676
- const effectiveColorTG = activeTagGroup ?? swimlaneTagGroup ?? null;
46682
+ const effectiveColorTG = activeTagGroup ?? resolvedSwimlaneTG ?? null;
46677
46683
  function eventColor(ev) {
46678
46684
  if (effectiveColorTG) {
46679
46685
  const tagColor = resolveTagColor(
@@ -46729,6 +46735,30 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
46729
46735
  }
46730
46736
  }
46731
46737
  const datePadding = (maxDate - minDate) * 0.05 || 0.5;
46738
+ const tagLegendReserve = parsed.timelineTagGroups.length > 0 ? 36 : 0;
46739
+ return {
46740
+ width,
46741
+ height,
46742
+ isVertical,
46743
+ tooltip,
46744
+ solid,
46745
+ textColor,
46746
+ mutedColor,
46747
+ bgColor,
46748
+ bg,
46749
+ swimlaneTagGroup: resolvedSwimlaneTG,
46750
+ groupColorMap,
46751
+ tagLanes,
46752
+ eventColor,
46753
+ minDate,
46754
+ maxDate,
46755
+ datePadding,
46756
+ earliestStartDateStr,
46757
+ latestEndDateStr,
46758
+ tagLegendReserve
46759
+ };
46760
+ }
46761
+ function makeTimelineHoverHelpers() {
46732
46762
  const FADE_OPACITY3 = 0.1;
46733
46763
  function fadeToGroup(g, groupName) {
46734
46764
  g.selectAll(".tl-event").each(function() {
@@ -46828,337 +46858,683 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
46828
46858
  evG.attr(`data-tag-${key}`, value.toLowerCase());
46829
46859
  }
46830
46860
  }
46831
- const tagLegendReserve = parsed.timelineTagGroups.length > 0 ? 36 : 0;
46832
- if (isVertical) {
46833
- const useGroupedVertical = tagLanes != null || timelineSort === "group" && timelineGroups.length > 0;
46834
- if (useGroupedVertical) {
46835
- let laneNames;
46836
- let laneEventsByName;
46837
- if (tagLanes) {
46838
- laneNames = tagLanes.map((l) => l.name);
46839
- laneEventsByName = new Map(tagLanes.map((l) => [l.name, l.events]));
46840
- } else {
46841
- const groupNames = timelineGroups.map((gr) => gr.name);
46842
- const ungroupedEvents = timelineEvents.filter(
46843
- (ev) => ev.group === null || !groupNames.includes(ev.group)
46844
- );
46845
- laneNames = ungroupedEvents.length > 0 ? [...groupNames, "(Other)"] : groupNames;
46846
- laneEventsByName = new Map(
46847
- laneNames.map((name) => [
46848
- name,
46849
- timelineEvents.filter(
46850
- (ev) => name === "(Other)" ? ev.group === null || !groupNames.includes(ev.group) : ev.group === name
46851
- )
46852
- ])
46853
- );
46861
+ return {
46862
+ FADE_OPACITY: FADE_OPACITY3,
46863
+ fadeToGroup,
46864
+ fadeToEra,
46865
+ fadeToMarker,
46866
+ fadeReset,
46867
+ fadeToTagValue,
46868
+ setTagAttrs
46869
+ };
46870
+ }
46871
+ function renderTimelineTagLegendOverlay(container, parsed, palette, isDark, setup, hovers, onClickItem, exportDims, swimlaneTagGroup, activeTagGroup, onTagStateChange, viewMode) {
46872
+ if (parsed.timelineTagGroups.length === 0) return;
46873
+ const { width, textColor, groupColorMap, solid } = setup;
46874
+ const { FADE_OPACITY: FADE_OPACITY3, fadeReset, fadeToTagValue } = hovers;
46875
+ const title = parsed.noTitle ? null : parsed.title;
46876
+ const { timelineEvents } = parsed;
46877
+ const LG_HEIGHT = LEGEND_HEIGHT;
46878
+ const LG_PILL_PAD = LEGEND_PILL_PAD;
46879
+ const LG_PILL_FONT_SIZE = LEGEND_PILL_FONT_SIZE;
46880
+ const LG_CAPSULE_PAD = LEGEND_CAPSULE_PAD;
46881
+ const LG_DOT_R = LEGEND_DOT_R;
46882
+ const LG_ENTRY_FONT_SIZE = LEGEND_ENTRY_FONT_SIZE;
46883
+ const LG_ENTRY_DOT_GAP = LEGEND_ENTRY_DOT_GAP;
46884
+ const LG_ENTRY_TRAIL = LEGEND_ENTRY_TRAIL;
46885
+ const LG_ICON_W = 20;
46886
+ const mainSvg = d3Selection22.select(container).select("svg");
46887
+ const mainG = mainSvg.select("g");
46888
+ if (!mainSvg.empty() && !mainG.empty()) {
46889
+ let drawSwimlaneIcon4 = function(parent, x, y, isSwimActive) {
46890
+ const iconG = parent.append("g").attr("class", "tl-swimlane-icon").attr("transform", `translate(${x}, ${y})`).style("cursor", "pointer");
46891
+ const barColor = isSwimActive ? palette.primary : palette.textMuted;
46892
+ const barOpacity = isSwimActive ? 1 : 0.35;
46893
+ const bars = [
46894
+ { y: 0, w: 8 },
46895
+ { y: 4, w: 12 },
46896
+ { y: 8, w: 6 }
46897
+ ];
46898
+ for (const bar of bars) {
46899
+ 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);
46854
46900
  }
46855
- const laneCount = laneNames.length;
46856
- const scaleMargin = timelineScale ? 40 : 0;
46857
- const markerMargin = timelineMarkers.length > 0 ? 30 : 0;
46858
- const margin = {
46859
- top: 104 + markerMargin + tagLegendReserve,
46860
- right: 40 + scaleMargin,
46861
- bottom: 40,
46862
- left: 60 + scaleMargin
46863
- };
46864
- const innerWidth = width - margin.left - margin.right;
46865
- const innerHeight = height - margin.top - margin.bottom;
46866
- const laneWidth = innerWidth / laneCount;
46867
- const yScale = d3Scale2.scaleLinear().domain([minDate - datePadding, maxDate + datePadding]).range([0, innerHeight]);
46868
- 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);
46869
- const g = svg.append("g").attr("transform", `translate(${margin.left},${margin.top})`);
46870
- renderChartTitle(
46871
- svg,
46872
- title,
46873
- parsed.titleLineNumber,
46874
- width,
46875
- textColor,
46876
- onClickItem
46877
- );
46878
- renderEras(
46879
- g,
46880
- timelineEras,
46881
- yScale,
46882
- true,
46883
- innerWidth,
46884
- innerHeight,
46885
- (s, e) => fadeToEra(g, s, e),
46886
- () => fadeReset(g),
46887
- timelineScale,
46888
- tooltip,
46889
- palette
46890
- );
46891
- renderMarkers(
46892
- g,
46893
- timelineMarkers,
46894
- yScale,
46895
- true,
46896
- innerWidth,
46897
- innerHeight,
46898
- (d) => fadeToMarker(g, d),
46899
- () => fadeReset(g),
46900
- timelineScale,
46901
- tooltip,
46902
- palette
46901
+ return iconG;
46902
+ }, relayout2 = function() {
46903
+ renderTimeline(
46904
+ container,
46905
+ parsed,
46906
+ palette,
46907
+ isDark,
46908
+ onClickItem,
46909
+ exportDims,
46910
+ currentActiveGroup,
46911
+ currentSwimlaneGroup,
46912
+ onTagStateChange,
46913
+ viewMode
46903
46914
  );
46904
- if (timelineScale) {
46905
- renderTimeScale(
46906
- g,
46907
- yScale,
46908
- true,
46909
- innerWidth,
46910
- innerHeight,
46911
- textColor,
46912
- minDate,
46913
- maxDate,
46914
- formatBoundaryLabel(earliestStartDateStr, latestEndDateStr),
46915
- formatBoundaryLabel(latestEndDateStr, earliestStartDateStr)
46915
+ }, drawLegend2 = function() {
46916
+ mainSvg.selectAll(".tl-tag-legend-group").remove();
46917
+ mainSvg.selectAll(".tl-tag-legend-container").remove();
46918
+ const effectiveColorKey = (currentActiveGroup ?? currentSwimlaneGroup)?.toLowerCase() ?? null;
46919
+ const visibleGroups = viewMode ? legendGroups.filter(
46920
+ (lg) => effectiveColorKey != null && lg.group.name.toLowerCase() === effectiveColorKey
46921
+ ) : legendGroups;
46922
+ if (visibleGroups.length === 0) return;
46923
+ const legendContainer = mainSvg.append("g").attr("class", "tl-tag-legend-container");
46924
+ if (currentActiveGroup) {
46925
+ legendContainer.attr(
46926
+ "data-legend-active",
46927
+ currentActiveGroup.toLowerCase()
46916
46928
  );
46917
46929
  }
46918
- if (timelineSwimlanes || tagLanes) {
46919
- laneNames.forEach((laneName, laneIdx) => {
46920
- const laneX = laneIdx * laneWidth;
46921
- const fillColor = laneIdx % 2 === 0 ? textColor : "transparent";
46922
- 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);
46923
- });
46924
- }
46925
- laneNames.forEach((laneName, laneIdx) => {
46926
- const laneX = laneIdx * laneWidth;
46927
- const laneColor = groupColorMap.get(laneName) ?? textColor;
46928
- const laneCenter = laneX + laneWidth / 2;
46929
- 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));
46930
- 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);
46931
- 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");
46932
- const laneEvents = laneEventsByName.get(laneName) ?? [];
46933
- for (const ev of laneEvents) {
46934
- const y = yScale(parseTimelineDate(ev.date));
46935
- 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(
46936
- "data-end-date",
46937
- ev.endDate ? String(parseTimelineDate(ev.endDate)) : null
46938
- ).style("cursor", "pointer").on("mouseenter", function(event) {
46939
- fadeToGroup(g, laneName);
46940
- showTooltip(tooltip, buildEventTooltipHtml(ev), event);
46941
- }).on("mouseleave", function() {
46942
- fadeReset(g);
46943
- hideTooltip(tooltip);
46944
- }).on("mousemove", function(event) {
46945
- showTooltip(tooltip, buildEventTooltipHtml(ev), event);
46946
- }).on("click", () => {
46947
- if (onClickItem && ev.lineNumber) onClickItem(ev.lineNumber);
46948
- });
46949
- setTagAttrs(evG, ev);
46950
- const evColor = eventColor(ev);
46951
- if (ev.endDate) {
46952
- const y2 = yScale(parseTimelineDate(ev.endDate));
46953
- const rectH = Math.max(y2 - y, 4);
46954
- let fill2 = shapeFill(palette, evColor, isDark, { solid });
46955
- let stroke2 = evColor;
46956
- if (ev.uncertain) {
46957
- const gradientId = `uncertain-vg-${ev.lineNumber}`;
46958
- const strokeGradientId = `uncertain-vg-s-${ev.lineNumber}`;
46959
- const defs = svg.select("defs").node() || svg.append("defs").node();
46960
- const defsEl = d3Selection22.select(defs);
46961
- defsEl.append("linearGradient").attr("id", gradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "0%").attr("y2", "100%").selectAll("stop").data([
46962
- { offset: "0%", opacity: 1 },
46963
- { offset: "80%", opacity: 1 },
46964
- { offset: "100%", opacity: 0 }
46965
- ]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", mix(laneColor, bg, 30)).attr("stop-opacity", (d) => d.opacity);
46966
- defsEl.append("linearGradient").attr("id", strokeGradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "0%").attr("y2", "100%").selectAll("stop").data([
46967
- { offset: "0%", opacity: 1 },
46968
- { offset: "80%", opacity: 1 },
46969
- { offset: "100%", opacity: 0 }
46970
- ]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", evColor).attr("stop-opacity", (d) => d.opacity);
46971
- fill2 = `url(#${gradientId})`;
46972
- stroke2 = `url(#${strokeGradientId})`;
46973
- }
46974
- 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);
46975
- 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);
46930
+ const iconAddon = viewMode ? 0 : LG_ICON_W;
46931
+ const centralGroups = visibleGroups.map((lg) => ({
46932
+ name: lg.group.name,
46933
+ entries: lg.group.entries.map((e) => ({
46934
+ value: e.value,
46935
+ color: e.color
46936
+ }))
46937
+ }));
46938
+ const centralActive = viewMode ? effectiveColorKey : currentActiveGroup;
46939
+ const centralConfig = {
46940
+ groups: centralGroups,
46941
+ position: { placement: "top-center", titleRelation: "below-title" },
46942
+ mode: "fixed",
46943
+ capsulePillAddonWidth: iconAddon
46944
+ };
46945
+ const centralState = { activeGroup: centralActive };
46946
+ const centralCallbacks = viewMode ? {} : {
46947
+ onGroupToggle: (groupName) => {
46948
+ currentActiveGroup = currentActiveGroup === groupName.toLowerCase() ? null : groupName.toLowerCase();
46949
+ drawLegend2();
46950
+ recolorEvents2();
46951
+ onTagStateChange?.(currentActiveGroup, currentSwimlaneGroup);
46952
+ },
46953
+ onEntryHover: (groupName, entryValue) => {
46954
+ const tagKey = groupName.toLowerCase();
46955
+ if (entryValue) {
46956
+ const tagVal = entryValue.toLowerCase();
46957
+ fadeToTagValue(mainG, tagKey, tagVal);
46958
+ mainSvg.selectAll("[data-legend-entry]").each(function() {
46959
+ const el = d3Selection22.select(this);
46960
+ const ev = el.attr("data-legend-entry");
46961
+ const eg = el.attr("data-tag-group") ?? el.node()?.closest?.("[data-tag-group]")?.getAttribute("data-tag-group");
46962
+ el.attr(
46963
+ "opacity",
46964
+ eg === tagKey && ev === tagVal ? 1 : FADE_OPACITY3
46965
+ );
46966
+ });
46976
46967
  } else {
46977
- 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);
46978
- evG.append("text").attr("x", laneCenter + 10).attr("y", y).attr("dy", "0.35em").attr("fill", textColor).attr("font-size", "10px").text(ev.label);
46968
+ fadeReset(mainG);
46969
+ mainSvg.selectAll("[data-legend-entry]").attr("opacity", 1);
46970
+ }
46971
+ },
46972
+ onGroupRendered: (groupName, groupEl, isActive) => {
46973
+ const groupKey = groupName.toLowerCase();
46974
+ groupEl.attr("data-tag-group", groupKey);
46975
+ if (isActive && !viewMode) {
46976
+ const isSwimActive = currentSwimlaneGroup != null && currentSwimlaneGroup.toLowerCase() === groupKey;
46977
+ const pillWidth3 = measureLegendText(groupName, LG_PILL_FONT_SIZE) + LG_PILL_PAD;
46978
+ const pillXOff = LG_CAPSULE_PAD;
46979
+ const iconX = pillXOff + pillWidth3 + 5;
46980
+ const iconY = (LG_HEIGHT - 10) / 2;
46981
+ const iconEl = drawSwimlaneIcon4(
46982
+ groupEl,
46983
+ iconX,
46984
+ iconY,
46985
+ isSwimActive
46986
+ );
46987
+ iconEl.attr("data-swimlane-toggle", groupKey).on("click", (event) => {
46988
+ event.stopPropagation();
46989
+ currentSwimlaneGroup = currentSwimlaneGroup === groupKey ? null : groupKey;
46990
+ onTagStateChange?.(
46991
+ currentActiveGroup,
46992
+ currentSwimlaneGroup
46993
+ );
46994
+ relayout2();
46995
+ });
46979
46996
  }
46980
46997
  }
46981
- });
46982
- } else {
46983
- const scaleMargin = timelineScale ? 40 : 0;
46984
- const markerMargin = timelineMarkers.length > 0 ? 30 : 0;
46985
- const margin = {
46986
- top: 104 + markerMargin + tagLegendReserve,
46987
- right: 200,
46988
- bottom: 40,
46989
- left: 60 + scaleMargin
46990
46998
  };
46991
- const innerWidth = width - margin.left - margin.right;
46992
- const innerHeight = height - margin.top - margin.bottom;
46993
- const axisX = 20;
46994
- const yScale = d3Scale2.scaleLinear().domain([minDate - datePadding, maxDate + datePadding]).range([0, innerHeight]);
46995
- const sorted = timelineEvents.slice().sort((a, b) => parseTimelineDate(a.date) - parseTimelineDate(b.date));
46996
- 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);
46997
- const g = svg.append("g").attr("transform", `translate(${margin.left},${margin.top})`);
46998
- renderChartTitle(
46999
- svg,
47000
- title,
47001
- parsed.titleLineNumber,
47002
- width,
47003
- textColor,
47004
- onClickItem
47005
- );
47006
- renderEras(
47007
- g,
47008
- timelineEras,
47009
- yScale,
47010
- true,
47011
- innerWidth,
47012
- innerHeight,
47013
- (s, e) => fadeToEra(g, s, e),
47014
- () => fadeReset(g),
47015
- timelineScale,
47016
- tooltip,
47017
- palette
47018
- );
47019
- renderMarkers(
47020
- g,
47021
- timelineMarkers,
47022
- yScale,
47023
- true,
47024
- innerWidth,
47025
- innerHeight,
47026
- (d) => fadeToMarker(g, d),
47027
- () => fadeReset(g),
47028
- timelineScale,
47029
- tooltip,
47030
- palette
46999
+ const legendInnerG = legendContainer.append("g").attr("transform", `translate(0, ${legendY})`);
47000
+ renderLegendD3(
47001
+ legendInnerG,
47002
+ centralConfig,
47003
+ centralState,
47004
+ palette,
47005
+ isDark,
47006
+ centralCallbacks,
47007
+ width
47031
47008
  );
47009
+ }, recolorEvents2 = function() {
47010
+ const colorTG = currentActiveGroup ?? swimlaneTagGroup ?? null;
47011
+ mainG.selectAll(".tl-event").each(function() {
47012
+ const el = d3Selection22.select(this);
47013
+ const lineNum = el.attr("data-line-number");
47014
+ const ev = lineNum ? eventByLine.get(lineNum) : void 0;
47015
+ if (!ev) return;
47016
+ let color;
47017
+ if (colorTG) {
47018
+ const tagColor = resolveTagColor(
47019
+ ev.metadata,
47020
+ parsed.timelineTagGroups,
47021
+ colorTG
47022
+ );
47023
+ color = tagColor ?? (ev.group && groupColorMap.has(ev.group) ? groupColorMap.get(ev.group) : textColor);
47024
+ } else {
47025
+ color = ev.group && groupColorMap.has(ev.group) ? groupColorMap.get(ev.group) : textColor;
47026
+ }
47027
+ el.selectAll("rect").attr("fill", shapeFill(palette, color, isDark, { solid })).attr("stroke", color);
47028
+ el.selectAll("circle:not(.tl-event-point-outline)").attr("fill", shapeFill(palette, color, isDark, { solid })).attr("stroke", color);
47029
+ });
47030
+ };
47031
+ var drawSwimlaneIcon3 = drawSwimlaneIcon4, relayout = relayout2, drawLegend = drawLegend2, recolorEvents = recolorEvents2;
47032
+ const legendY = title ? 50 : 10;
47033
+ const legendGroups = parsed.timelineTagGroups.map((g) => {
47034
+ const pillW = measureLegendText(g.name, LG_PILL_FONT_SIZE) + LG_PILL_PAD;
47035
+ const iconSpace = viewMode ? 8 : LG_ICON_W + 4;
47036
+ let entryX = LG_CAPSULE_PAD + pillW + iconSpace;
47037
+ for (const entry of g.entries) {
47038
+ const textX = entryX + LG_DOT_R * 2 + LG_ENTRY_DOT_GAP;
47039
+ entryX = textX + measureLegendText(entry.value, LG_ENTRY_FONT_SIZE) + LG_ENTRY_TRAIL;
47040
+ }
47041
+ return {
47042
+ group: g,
47043
+ minifiedWidth: pillW,
47044
+ expandedWidth: entryX + LG_CAPSULE_PAD
47045
+ };
47046
+ });
47047
+ let currentActiveGroup = activeTagGroup ?? null;
47048
+ let currentSwimlaneGroup = swimlaneTagGroup ?? null;
47049
+ const eventByLine = /* @__PURE__ */ new Map();
47050
+ for (const ev of timelineEvents) {
47051
+ eventByLine.set(String(ev.lineNumber), ev);
47052
+ }
47053
+ drawLegend2();
47054
+ }
47055
+ }
47056
+ function renderTimelineHorizontalTimeSort(container, parsed, palette, isDark, setup, hovers, onClickItem, _exportDims, _swimlaneTagGroup, _activeTagGroup, _onTagStateChange, _viewMode) {
47057
+ const {
47058
+ width,
47059
+ height,
47060
+ tooltip,
47061
+ solid,
47062
+ textColor,
47063
+ bgColor,
47064
+ bg,
47065
+ groupColorMap,
47066
+ eventColor,
47067
+ minDate,
47068
+ maxDate,
47069
+ datePadding,
47070
+ earliestStartDateStr,
47071
+ latestEndDateStr,
47072
+ tagLegendReserve
47073
+ } = setup;
47074
+ const { fadeToGroup, fadeToEra, fadeToMarker, fadeReset, setTagAttrs } = hovers;
47075
+ const {
47076
+ timelineEvents,
47077
+ timelineGroups,
47078
+ timelineEras,
47079
+ timelineMarkers,
47080
+ timelineScale
47081
+ } = parsed;
47082
+ const title = parsed.noTitle ? null : parsed.title;
47083
+ const BAR_H2 = 22;
47084
+ const sorted = timelineEvents.slice().sort((a, b) => parseTimelineDate(a.date) - parseTimelineDate(b.date));
47085
+ const scaleMargin = timelineScale ? 24 : 0;
47086
+ const ERA_ROW_H = 22;
47087
+ const MARKER_ROW_H = 22;
47088
+ const eraReserve = timelineEras.length > 0 ? ERA_ROW_H : 0;
47089
+ const markerReserve = timelineMarkers.length > 0 ? MARKER_ROW_H : 0;
47090
+ const topScaleH = timelineScale ? 40 : 0;
47091
+ const margin = {
47092
+ top: 104 + topScaleH + eraReserve + markerReserve + tagLegendReserve,
47093
+ right: 40,
47094
+ bottom: 40 + scaleMargin,
47095
+ left: 60
47096
+ };
47097
+ const markerLabelY = markerReserve ? -(topScaleH + MARKER_ROW_H / 2) : 0;
47098
+ const eraLabelY = eraReserve ? -(topScaleH + markerReserve + ERA_ROW_H / 2) : 0;
47099
+ const innerWidth = width - margin.left - margin.right;
47100
+ const innerHeight = height - margin.top - margin.bottom;
47101
+ const rowH = Math.min(28, innerHeight / sorted.length);
47102
+ const xScale = d3Scale2.scaleLinear().domain([minDate - datePadding, maxDate + datePadding]).range([0, innerWidth]);
47103
+ const svg = d3Selection22.select(container).append("svg").attr("width", width).attr("height", height).style("background", bgColor);
47104
+ const g = svg.append("g").attr("transform", `translate(${margin.left},${margin.top})`);
47105
+ renderChartTitle(
47106
+ svg,
47107
+ title,
47108
+ parsed.titleLineNumber,
47109
+ width,
47110
+ textColor,
47111
+ onClickItem
47112
+ );
47113
+ renderEras(
47114
+ g,
47115
+ timelineEras,
47116
+ xScale,
47117
+ false,
47118
+ innerWidth,
47119
+ innerHeight,
47120
+ (s, e) => fadeToEra(g, s, e),
47121
+ () => fadeReset(g),
47122
+ timelineScale,
47123
+ tooltip,
47124
+ palette,
47125
+ eraReserve ? eraLabelY : void 0
47126
+ );
47127
+ renderMarkers(
47128
+ g,
47129
+ timelineMarkers,
47130
+ xScale,
47131
+ false,
47132
+ innerWidth,
47133
+ innerHeight,
47134
+ (d) => fadeToMarker(g, d),
47135
+ () => fadeReset(g),
47136
+ timelineScale,
47137
+ tooltip,
47138
+ palette,
47139
+ markerReserve ? markerLabelY : void 0
47140
+ );
47141
+ if (timelineScale) {
47142
+ renderTimeScale(
47143
+ g,
47144
+ xScale,
47145
+ false,
47146
+ innerWidth,
47147
+ innerHeight,
47148
+ textColor,
47149
+ minDate,
47150
+ maxDate,
47151
+ formatBoundaryLabel(earliestStartDateStr, latestEndDateStr),
47152
+ formatBoundaryLabel(latestEndDateStr, earliestStartDateStr)
47153
+ );
47154
+ }
47155
+ if (timelineGroups.length > 0) {
47156
+ const legendY = timelineScale ? -75 : -55;
47157
+ renderTimelineGroupLegend(
47158
+ g,
47159
+ timelineGroups,
47160
+ groupColorMap,
47161
+ textColor,
47162
+ palette,
47163
+ isDark,
47164
+ legendY,
47165
+ (name) => fadeToGroup(g, name),
47166
+ () => fadeReset(g)
47167
+ );
47168
+ }
47169
+ sorted.forEach((ev, i) => {
47170
+ const y = i * rowH + rowH / 2;
47171
+ const x = xScale(parseTimelineDate(ev.date));
47172
+ const color = eventColor(ev);
47173
+ 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(
47174
+ "data-end-date",
47175
+ ev.endDate ? String(parseTimelineDate(ev.endDate)) : null
47176
+ ).style("cursor", "pointer").on("mouseenter", function(event) {
47177
+ if (ev.group && timelineGroups.length > 0) fadeToGroup(g, ev.group);
47032
47178
  if (timelineScale) {
47033
- renderTimeScale(
47179
+ showEventDatesOnScale(
47034
47180
  g,
47035
- yScale,
47036
- true,
47037
- innerWidth,
47181
+ xScale,
47182
+ ev.date,
47183
+ ev.endDate,
47038
47184
  innerHeight,
47039
- textColor,
47040
- minDate,
47041
- maxDate,
47042
- formatBoundaryLabel(earliestStartDateStr, latestEndDateStr),
47043
- formatBoundaryLabel(latestEndDateStr, earliestStartDateStr)
47185
+ color
47044
47186
  );
47187
+ } else {
47188
+ showTooltip(tooltip, buildEventTooltipHtml(ev), event);
47045
47189
  }
47046
- if (timelineGroups.length > 0) {
47047
- renderTimelineGroupLegend(
47048
- g,
47049
- timelineGroups,
47050
- groupColorMap,
47051
- textColor,
47052
- palette,
47053
- isDark,
47054
- -55,
47055
- (name) => fadeToGroup(g, name),
47056
- () => fadeReset(g)
47057
- );
47190
+ }).on("mouseleave", function() {
47191
+ fadeReset(g);
47192
+ if (timelineScale) {
47193
+ hideEventDatesOnScale(g);
47194
+ } else {
47195
+ hideTooltip(tooltip);
47058
47196
  }
47059
- 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");
47060
- for (const ev of sorted) {
47061
- const y = yScale(parseTimelineDate(ev.date));
47062
- const color = eventColor(ev);
47063
- 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(
47064
- "data-end-date",
47065
- ev.endDate ? String(parseTimelineDate(ev.endDate)) : null
47066
- ).style("cursor", "pointer").on("mouseenter", function(event) {
47067
- if (ev.group && timelineGroups.length > 0) fadeToGroup(g, ev.group);
47197
+ }).on("mousemove", function(event) {
47198
+ if (!timelineScale) {
47199
+ showTooltip(tooltip, buildEventTooltipHtml(ev), event);
47200
+ }
47201
+ }).on("click", () => {
47202
+ if (onClickItem && ev.lineNumber) onClickItem(ev.lineNumber);
47203
+ });
47204
+ setTagAttrs(evG, ev);
47205
+ if (ev.endDate) {
47206
+ const x2 = xScale(parseTimelineDate(ev.endDate));
47207
+ const rectW = Math.max(x2 - x, 4);
47208
+ const estLabelWidth = ev.label.length * 7 + 16;
47209
+ const labelFitsInside = rectW >= estLabelWidth;
47210
+ let fill2 = shapeFill(palette, color, isDark, { solid });
47211
+ let stroke2 = color;
47212
+ if (ev.uncertain) {
47213
+ const gradientId = `uncertain-ts-${ev.lineNumber}`;
47214
+ const strokeGradientId = `uncertain-ts-s-${ev.lineNumber}`;
47215
+ const defs = svg.select("defs").node() || svg.append("defs").node();
47216
+ const defsEl = d3Selection22.select(defs);
47217
+ defsEl.append("linearGradient").attr("id", gradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "100%").attr("y2", "0%").selectAll("stop").data([
47218
+ { offset: "0%", opacity: 1 },
47219
+ { offset: "80%", opacity: 1 },
47220
+ { offset: "100%", opacity: 0 }
47221
+ ]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", mix(color, bg, 30)).attr("stop-opacity", (d) => d.opacity);
47222
+ defsEl.append("linearGradient").attr("id", strokeGradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "100%").attr("y2", "0%").selectAll("stop").data([
47223
+ { offset: "0%", opacity: 1 },
47224
+ { offset: "80%", opacity: 1 },
47225
+ { offset: "100%", opacity: 0 }
47226
+ ]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", color).attr("stop-opacity", (d) => d.opacity);
47227
+ fill2 = `url(#${gradientId})`;
47228
+ stroke2 = `url(#${strokeGradientId})`;
47229
+ }
47230
+ 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);
47231
+ if (labelFitsInside) {
47232
+ 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);
47233
+ } else {
47234
+ const wouldFlipLeft = x + rectW > innerWidth * 0.6;
47235
+ const labelFitsLeft = x - 6 - estLabelWidth > 0;
47236
+ const flipLeft = wouldFlipLeft && labelFitsLeft;
47237
+ 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);
47238
+ }
47239
+ } else {
47240
+ const estLabelWidth = ev.label.length * 7;
47241
+ const wouldFlipLeft = x > innerWidth * 0.6;
47242
+ const labelFitsLeft = x - 10 - estLabelWidth > 0;
47243
+ const flipLeft = wouldFlipLeft && labelFitsLeft;
47244
+ 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);
47245
+ 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);
47246
+ }
47247
+ });
47248
+ }
47249
+ function renderTimelineHorizontalGrouped(container, parsed, palette, isDark, setup, hovers, onClickItem, _exportDims, _swimlaneTagGroup, _activeTagGroup, _onTagStateChange, _viewMode) {
47250
+ const {
47251
+ width,
47252
+ height,
47253
+ tooltip,
47254
+ solid,
47255
+ textColor,
47256
+ bgColor,
47257
+ bg,
47258
+ groupColorMap,
47259
+ tagLanes,
47260
+ eventColor,
47261
+ minDate,
47262
+ maxDate,
47263
+ datePadding,
47264
+ earliestStartDateStr,
47265
+ latestEndDateStr,
47266
+ tagLegendReserve
47267
+ } = setup;
47268
+ const { fadeToGroup, fadeToEra, fadeToMarker, fadeReset, setTagAttrs } = hovers;
47269
+ const {
47270
+ timelineEvents,
47271
+ timelineGroups,
47272
+ timelineEras,
47273
+ timelineMarkers,
47274
+ timelineScale,
47275
+ timelineSwimlanes
47276
+ } = parsed;
47277
+ const title = parsed.noTitle ? null : parsed.title;
47278
+ const BAR_H2 = 22;
47279
+ const GROUP_GAP3 = 12;
47280
+ let lanes;
47281
+ if (tagLanes) {
47282
+ lanes = tagLanes;
47283
+ } else {
47284
+ const groupNames = timelineGroups.map((gr) => gr.name);
47285
+ const ungroupedEvents = timelineEvents.filter(
47286
+ (ev) => ev.group === null || !groupNames.includes(ev.group)
47287
+ );
47288
+ const laneNames = ungroupedEvents.length > 0 ? [...groupNames, "(Other)"] : groupNames;
47289
+ lanes = laneNames.map((name) => ({
47290
+ name,
47291
+ events: timelineEvents.filter(
47292
+ (ev) => name === "(Other)" ? ev.group === null || !groupNames.includes(ev.group) : ev.group === name
47293
+ )
47294
+ }));
47295
+ }
47296
+ const totalEventRows = lanes.reduce((s, l) => s + l.events.length, 0);
47297
+ const scaleMargin = timelineScale ? 24 : 0;
47298
+ const ERA_ROW_H = 22;
47299
+ const MARKER_ROW_H = 22;
47300
+ const eraReserve = timelineEras.length > 0 ? ERA_ROW_H : 0;
47301
+ const markerReserve = timelineMarkers.length > 0 ? MARKER_ROW_H : 0;
47302
+ const topScaleH = timelineScale ? 40 : 0;
47303
+ const maxGroupNameLen = Math.max(...lanes.map((l) => l.name.length));
47304
+ const dynamicLeftMargin = Math.max(120, maxGroupNameLen * 7 + 30);
47305
+ const baseTopMargin = title ? 50 : 20;
47306
+ const margin = {
47307
+ top: baseTopMargin + topScaleH + eraReserve + markerReserve + tagLegendReserve,
47308
+ right: 40,
47309
+ bottom: 40 + scaleMargin,
47310
+ left: dynamicLeftMargin
47311
+ };
47312
+ const markerLabelY = markerReserve ? -(topScaleH + MARKER_ROW_H / 2) : 0;
47313
+ const eraLabelY = eraReserve ? -(topScaleH + markerReserve + ERA_ROW_H / 2) : 0;
47314
+ const innerWidth = width - margin.left - margin.right;
47315
+ const innerHeight = height - margin.top - margin.bottom;
47316
+ const totalGaps = (lanes.length - 1) * GROUP_GAP3;
47317
+ const rowH = Math.min(28, (innerHeight - totalGaps) / totalEventRows);
47318
+ const xScale = d3Scale2.scaleLinear().domain([minDate - datePadding, maxDate + datePadding]).range([0, innerWidth]);
47319
+ const svg = d3Selection22.select(container).append("svg").attr("width", width).attr("height", height).style("background", bgColor);
47320
+ const g = svg.append("g").attr("transform", `translate(${margin.left},${margin.top})`);
47321
+ renderChartTitle(
47322
+ svg,
47323
+ title,
47324
+ parsed.titleLineNumber,
47325
+ width,
47326
+ textColor,
47327
+ onClickItem
47328
+ );
47329
+ renderEras(
47330
+ g,
47331
+ timelineEras,
47332
+ xScale,
47333
+ false,
47334
+ innerWidth,
47335
+ innerHeight,
47336
+ (s, e) => fadeToEra(g, s, e),
47337
+ () => fadeReset(g),
47338
+ timelineScale,
47339
+ tooltip,
47340
+ palette,
47341
+ eraReserve ? eraLabelY : void 0
47342
+ );
47343
+ renderMarkers(
47344
+ g,
47345
+ timelineMarkers,
47346
+ xScale,
47347
+ false,
47348
+ innerWidth,
47349
+ innerHeight,
47350
+ (d) => fadeToMarker(g, d),
47351
+ () => fadeReset(g),
47352
+ timelineScale,
47353
+ tooltip,
47354
+ palette,
47355
+ markerReserve ? markerLabelY : void 0
47356
+ );
47357
+ if (timelineScale) {
47358
+ renderTimeScale(
47359
+ g,
47360
+ xScale,
47361
+ false,
47362
+ innerWidth,
47363
+ innerHeight,
47364
+ textColor,
47365
+ minDate,
47366
+ maxDate,
47367
+ formatBoundaryLabel(earliestStartDateStr, latestEndDateStr),
47368
+ formatBoundaryLabel(latestEndDateStr, earliestStartDateStr)
47369
+ );
47370
+ }
47371
+ let curY = 0;
47372
+ if (timelineSwimlanes || tagLanes) {
47373
+ let swimY = 0;
47374
+ lanes.forEach((lane, idx) => {
47375
+ const laneSpan = lane.events.length * rowH;
47376
+ const fillColor = idx % 2 === 0 ? textColor : "transparent";
47377
+ 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);
47378
+ swimY += laneSpan + GROUP_GAP3;
47379
+ });
47380
+ }
47381
+ for (const lane of lanes) {
47382
+ const laneColor = groupColorMap.get(lane.name) ?? textColor;
47383
+ const laneSpan = lane.events.length * rowH;
47384
+ const group = timelineGroups.find((grp) => grp.name === lane.name);
47385
+ 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", () => {
47386
+ if (onClickItem && group?.lineNumber) onClickItem(group.lineNumber);
47387
+ });
47388
+ 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);
47389
+ lane.events.forEach((ev, i) => {
47390
+ const y = curY + i * rowH + rowH / 2;
47391
+ const x = xScale(parseTimelineDate(ev.date));
47392
+ 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(
47393
+ "data-end-date",
47394
+ ev.endDate ? String(parseTimelineDate(ev.endDate)) : null
47395
+ ).style("cursor", "pointer").on("mouseenter", function(event) {
47396
+ fadeToGroup(g, lane.name);
47397
+ if (timelineScale) {
47398
+ showEventDatesOnScale(
47399
+ g,
47400
+ xScale,
47401
+ ev.date,
47402
+ ev.endDate,
47403
+ innerHeight,
47404
+ laneColor
47405
+ );
47406
+ } else {
47068
47407
  showTooltip(tooltip, buildEventTooltipHtml(ev), event);
47069
- }).on("mouseleave", function() {
47070
- fadeReset(g);
47408
+ }
47409
+ }).on("mouseleave", function() {
47410
+ fadeReset(g);
47411
+ if (timelineScale) {
47412
+ hideEventDatesOnScale(g);
47413
+ } else {
47071
47414
  hideTooltip(tooltip);
47072
- }).on("mousemove", function(event) {
47415
+ }
47416
+ }).on("mousemove", function(event) {
47417
+ if (!timelineScale) {
47073
47418
  showTooltip(tooltip, buildEventTooltipHtml(ev), event);
47074
- }).on("click", () => {
47075
- if (onClickItem && ev.lineNumber) onClickItem(ev.lineNumber);
47076
- });
47077
- setTagAttrs(evG, ev);
47078
- if (ev.endDate) {
47079
- const y2 = yScale(parseTimelineDate(ev.endDate));
47080
- const rectH = Math.max(y2 - y, 4);
47081
- let fill2 = shapeFill(palette, color, isDark, { solid });
47082
- let stroke2 = color;
47083
- if (ev.uncertain) {
47084
- const gradientId = `uncertain-v-${ev.lineNumber}`;
47085
- const strokeGradientId = `uncertain-v-s-${ev.lineNumber}`;
47086
- const defs = svg.select("defs").node() || svg.append("defs").node();
47087
- const defsEl = d3Selection22.select(defs);
47088
- defsEl.append("linearGradient").attr("id", gradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "0%").attr("y2", "100%").selectAll("stop").data([
47089
- { offset: "0%", opacity: 1 },
47090
- { offset: "80%", opacity: 1 },
47091
- { offset: "100%", opacity: 0 }
47092
- ]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", mix(color, bg, 30)).attr("stop-opacity", (d) => d.opacity);
47093
- defsEl.append("linearGradient").attr("id", strokeGradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "0%").attr("y2", "100%").selectAll("stop").data([
47094
- { offset: "0%", opacity: 1 },
47095
- { offset: "80%", opacity: 1 },
47096
- { offset: "100%", opacity: 0 }
47097
- ]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", color).attr("stop-opacity", (d) => d.opacity);
47098
- fill2 = `url(#${gradientId})`;
47099
- stroke2 = `url(#${strokeGradientId})`;
47100
- }
47101
- 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);
47102
- 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);
47419
+ }
47420
+ }).on("click", () => {
47421
+ if (onClickItem && ev.lineNumber) onClickItem(ev.lineNumber);
47422
+ });
47423
+ setTagAttrs(evG, ev);
47424
+ const evColor = eventColor(ev);
47425
+ if (ev.endDate) {
47426
+ const x2 = xScale(parseTimelineDate(ev.endDate));
47427
+ const rectW = Math.max(x2 - x, 4);
47428
+ const estLabelWidth = ev.label.length * 7 + 16;
47429
+ const labelFitsInside = rectW >= estLabelWidth;
47430
+ let fill2 = shapeFill(palette, evColor, isDark, { solid });
47431
+ let stroke2 = evColor;
47432
+ if (ev.uncertain) {
47433
+ const gradientId = `uncertain-${ev.lineNumber}`;
47434
+ const strokeGradientId = `uncertain-s-${ev.lineNumber}`;
47435
+ const defs = svg.select("defs").node() || svg.append("defs").node();
47436
+ const defsEl = d3Selection22.select(defs);
47437
+ defsEl.append("linearGradient").attr("id", gradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "100%").attr("y2", "0%").selectAll("stop").data([
47438
+ { offset: "0%", opacity: 1 },
47439
+ { offset: "80%", opacity: 1 },
47440
+ { offset: "100%", opacity: 0 }
47441
+ ]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", mix(evColor, bg, 30)).attr("stop-opacity", (d) => d.opacity);
47442
+ defsEl.append("linearGradient").attr("id", strokeGradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "100%").attr("y2", "0%").selectAll("stop").data([
47443
+ { offset: "0%", opacity: 1 },
47444
+ { offset: "80%", opacity: 1 },
47445
+ { offset: "100%", opacity: 0 }
47446
+ ]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", evColor).attr("stop-opacity", (d) => d.opacity);
47447
+ fill2 = `url(#${gradientId})`;
47448
+ stroke2 = `url(#${strokeGradientId})`;
47449
+ }
47450
+ 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);
47451
+ if (labelFitsInside) {
47452
+ 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);
47103
47453
  } else {
47104
- 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);
47105
- evG.append("text").attr("x", axisX + 16).attr("y", y).attr("dy", "0.35em").attr("fill", textColor).attr("font-size", "11px").text(ev.label);
47454
+ const wouldFlipLeft = x + rectW > innerWidth * 0.6;
47455
+ const labelFitsLeft = x - 6 - estLabelWidth > 0;
47456
+ const flipLeft = wouldFlipLeft && labelFitsLeft;
47457
+ 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);
47106
47458
  }
47107
- evG.append("text").attr("x", axisX - 14).attr(
47108
- "y",
47109
- ev.endDate ? yScale(parseTimelineDate(ev.date)) + Math.max(
47110
- yScale(parseTimelineDate(ev.endDate)) - yScale(parseTimelineDate(ev.date)),
47111
- 4
47112
- ) / 2 : y
47113
- ).attr("dy", "0.35em").attr("text-anchor", "end").attr("fill", mutedColor).attr("font-size", "10px").text(ev.date + (ev.endDate ? `\u2192${ev.endDate}` : ""));
47459
+ } else {
47460
+ const estLabelWidth = ev.label.length * 7;
47461
+ const wouldFlipLeft = x > innerWidth * 0.6;
47462
+ const labelFitsLeft = x - 10 - estLabelWidth > 0;
47463
+ const flipLeft = wouldFlipLeft && labelFitsLeft;
47464
+ 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);
47465
+ 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);
47114
47466
  }
47115
- }
47116
- return;
47467
+ });
47468
+ curY += laneSpan + GROUP_GAP3;
47117
47469
  }
47118
- const BAR_H2 = 22;
47119
- const GROUP_GAP3 = 12;
47120
- const useGroupedHorizontal = tagLanes != null || timelineSort === "group" && timelineGroups.length > 0;
47121
- if (useGroupedHorizontal) {
47122
- let lanes;
47470
+ }
47471
+ function renderTimelineVertical(container, parsed, palette, isDark, setup, hovers, onClickItem, exportDims, _swimlaneTagGroup, _activeTagGroup, _onTagStateChange, _viewMode) {
47472
+ const {
47473
+ width,
47474
+ height,
47475
+ tooltip,
47476
+ solid,
47477
+ textColor,
47478
+ mutedColor,
47479
+ bgColor,
47480
+ bg,
47481
+ groupColorMap,
47482
+ tagLanes,
47483
+ eventColor,
47484
+ minDate,
47485
+ maxDate,
47486
+ datePadding,
47487
+ earliestStartDateStr,
47488
+ latestEndDateStr,
47489
+ tagLegendReserve
47490
+ } = setup;
47491
+ const { fadeToGroup, fadeToEra, fadeToMarker, fadeReset, setTagAttrs } = hovers;
47492
+ const {
47493
+ timelineEvents,
47494
+ timelineGroups,
47495
+ timelineEras,
47496
+ timelineMarkers,
47497
+ timelineSort,
47498
+ timelineScale,
47499
+ timelineSwimlanes
47500
+ } = parsed;
47501
+ const title = parsed.noTitle ? null : parsed.title;
47502
+ const useGroupedVertical = tagLanes != null || timelineSort === "group" && timelineGroups.length > 0;
47503
+ if (useGroupedVertical) {
47504
+ let laneNames;
47505
+ let laneEventsByName;
47123
47506
  if (tagLanes) {
47124
- lanes = tagLanes;
47507
+ laneNames = tagLanes.map((l) => l.name);
47508
+ laneEventsByName = new Map(tagLanes.map((l) => [l.name, l.events]));
47125
47509
  } else {
47126
47510
  const groupNames = timelineGroups.map((gr) => gr.name);
47127
47511
  const ungroupedEvents = timelineEvents.filter(
47128
47512
  (ev) => ev.group === null || !groupNames.includes(ev.group)
47129
47513
  );
47130
- const laneNames = ungroupedEvents.length > 0 ? [...groupNames, "(Other)"] : groupNames;
47131
- lanes = laneNames.map((name) => ({
47132
- name,
47133
- events: timelineEvents.filter(
47134
- (ev) => name === "(Other)" ? ev.group === null || !groupNames.includes(ev.group) : ev.group === name
47135
- )
47136
- }));
47514
+ laneNames = ungroupedEvents.length > 0 ? [...groupNames, "(Other)"] : groupNames;
47515
+ laneEventsByName = new Map(
47516
+ laneNames.map((name) => [
47517
+ name,
47518
+ timelineEvents.filter(
47519
+ (ev) => name === "(Other)" ? ev.group === null || !groupNames.includes(ev.group) : ev.group === name
47520
+ )
47521
+ ])
47522
+ );
47137
47523
  }
47138
- const totalEventRows = lanes.reduce((s, l) => s + l.events.length, 0);
47139
- const scaleMargin = timelineScale ? 24 : 0;
47140
- const ERA_ROW_H = 22;
47141
- const MARKER_ROW_H = 22;
47142
- const eraReserve = timelineEras.length > 0 ? ERA_ROW_H : 0;
47143
- const markerReserve = timelineMarkers.length > 0 ? MARKER_ROW_H : 0;
47144
- const topScaleH = timelineScale ? 40 : 0;
47145
- const maxGroupNameLen = Math.max(...lanes.map((l) => l.name.length));
47146
- const dynamicLeftMargin = Math.max(120, maxGroupNameLen * 7 + 30);
47147
- const baseTopMargin = title ? 50 : 20;
47524
+ const laneCount = laneNames.length;
47525
+ const scaleMargin = timelineScale ? 40 : 0;
47526
+ const markerMargin = timelineMarkers.length > 0 ? 30 : 0;
47148
47527
  const margin = {
47149
- top: baseTopMargin + topScaleH + eraReserve + markerReserve + tagLegendReserve,
47150
- right: 40,
47151
- bottom: 40 + scaleMargin,
47152
- left: dynamicLeftMargin
47528
+ top: 104 + markerMargin + tagLegendReserve,
47529
+ right: 40 + scaleMargin,
47530
+ bottom: 40,
47531
+ left: 60 + scaleMargin
47153
47532
  };
47154
- const markerLabelY = markerReserve ? -(topScaleH + MARKER_ROW_H / 2) : 0;
47155
- const eraLabelY = eraReserve ? -(topScaleH + markerReserve + ERA_ROW_H / 2) : 0;
47156
47533
  const innerWidth = width - margin.left - margin.right;
47157
47534
  const innerHeight = height - margin.top - margin.bottom;
47158
- const totalGaps = (lanes.length - 1) * GROUP_GAP3;
47159
- const rowH = Math.min(28, (innerHeight - totalGaps) / totalEventRows);
47160
- const xScale = d3Scale2.scaleLinear().domain([minDate - datePadding, maxDate + datePadding]).range([0, innerWidth]);
47161
- const svg = d3Selection22.select(container).append("svg").attr("width", width).attr("height", height).style("background", bgColor);
47535
+ const laneWidth = innerWidth / laneCount;
47536
+ const yScale = d3Scale2.scaleLinear().domain([minDate - datePadding, maxDate + datePadding]).range([0, innerHeight]);
47537
+ 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);
47162
47538
  const g = svg.append("g").attr("transform", `translate(${margin.left},${margin.top})`);
47163
47539
  renderChartTitle(
47164
47540
  svg,
@@ -47171,36 +47547,34 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
47171
47547
  renderEras(
47172
47548
  g,
47173
47549
  timelineEras,
47174
- xScale,
47175
- false,
47550
+ yScale,
47551
+ true,
47176
47552
  innerWidth,
47177
47553
  innerHeight,
47178
47554
  (s, e) => fadeToEra(g, s, e),
47179
47555
  () => fadeReset(g),
47180
47556
  timelineScale,
47181
47557
  tooltip,
47182
- palette,
47183
- eraReserve ? eraLabelY : void 0
47558
+ palette
47184
47559
  );
47185
47560
  renderMarkers(
47186
47561
  g,
47187
47562
  timelineMarkers,
47188
- xScale,
47189
- false,
47563
+ yScale,
47564
+ true,
47190
47565
  innerWidth,
47191
47566
  innerHeight,
47192
47567
  (d) => fadeToMarker(g, d),
47193
47568
  () => fadeReset(g),
47194
47569
  timelineScale,
47195
47570
  tooltip,
47196
- palette,
47197
- markerReserve ? markerLabelY : void 0
47571
+ palette
47198
47572
  );
47199
47573
  if (timelineScale) {
47200
47574
  renderTimeScale(
47201
47575
  g,
47202
- xScale,
47203
- false,
47576
+ yScale,
47577
+ true,
47204
47578
  innerWidth,
47205
47579
  innerHeight,
47206
47580
  textColor,
@@ -47210,78 +47584,55 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
47210
47584
  formatBoundaryLabel(latestEndDateStr, earliestStartDateStr)
47211
47585
  );
47212
47586
  }
47213
- let curY = 0;
47214
47587
  if (timelineSwimlanes || tagLanes) {
47215
- let swimY = 0;
47216
- lanes.forEach((lane, idx) => {
47217
- const laneSpan = lane.events.length * rowH;
47218
- const fillColor = idx % 2 === 0 ? textColor : "transparent";
47219
- 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);
47220
- swimY += laneSpan + GROUP_GAP3;
47588
+ laneNames.forEach((laneName, laneIdx) => {
47589
+ const laneX = laneIdx * laneWidth;
47590
+ const fillColor = laneIdx % 2 === 0 ? textColor : "transparent";
47591
+ 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);
47221
47592
  });
47222
47593
  }
47223
- for (const lane of lanes) {
47224
- const laneColor = groupColorMap.get(lane.name) ?? textColor;
47225
- const laneSpan = lane.events.length * rowH;
47226
- const group = timelineGroups.find((grp) => grp.name === lane.name);
47227
- 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", () => {
47228
- if (onClickItem && group?.lineNumber) onClickItem(group.lineNumber);
47229
- });
47230
- 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);
47231
- lane.events.forEach((ev, i) => {
47232
- const y = curY + i * rowH + rowH / 2;
47233
- const x = xScale(parseTimelineDate(ev.date));
47234
- 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(
47594
+ laneNames.forEach((laneName, laneIdx) => {
47595
+ const laneX = laneIdx * laneWidth;
47596
+ const laneColor = groupColorMap.get(laneName) ?? textColor;
47597
+ const laneCenter = laneX + laneWidth / 2;
47598
+ 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));
47599
+ 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);
47600
+ 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");
47601
+ const laneEvents = laneEventsByName.get(laneName) ?? [];
47602
+ for (const ev of laneEvents) {
47603
+ const y = yScale(parseTimelineDate(ev.date));
47604
+ 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(
47235
47605
  "data-end-date",
47236
47606
  ev.endDate ? String(parseTimelineDate(ev.endDate)) : null
47237
47607
  ).style("cursor", "pointer").on("mouseenter", function(event) {
47238
- fadeToGroup(g, lane.name);
47239
- if (timelineScale) {
47240
- showEventDatesOnScale(
47241
- g,
47242
- xScale,
47243
- ev.date,
47244
- ev.endDate,
47245
- innerHeight,
47246
- laneColor
47247
- );
47248
- } else {
47249
- showTooltip(tooltip, buildEventTooltipHtml(ev), event);
47250
- }
47608
+ fadeToGroup(g, laneName);
47609
+ showTooltip(tooltip, buildEventTooltipHtml(ev), event);
47251
47610
  }).on("mouseleave", function() {
47252
47611
  fadeReset(g);
47253
- if (timelineScale) {
47254
- hideEventDatesOnScale(g);
47255
- } else {
47256
- hideTooltip(tooltip);
47257
- }
47612
+ hideTooltip(tooltip);
47258
47613
  }).on("mousemove", function(event) {
47259
- if (!timelineScale) {
47260
- showTooltip(tooltip, buildEventTooltipHtml(ev), event);
47261
- }
47614
+ showTooltip(tooltip, buildEventTooltipHtml(ev), event);
47262
47615
  }).on("click", () => {
47263
47616
  if (onClickItem && ev.lineNumber) onClickItem(ev.lineNumber);
47264
47617
  });
47265
47618
  setTagAttrs(evG, ev);
47266
47619
  const evColor = eventColor(ev);
47267
47620
  if (ev.endDate) {
47268
- const x2 = xScale(parseTimelineDate(ev.endDate));
47269
- const rectW = Math.max(x2 - x, 4);
47270
- const estLabelWidth = ev.label.length * 7 + 16;
47271
- const labelFitsInside = rectW >= estLabelWidth;
47621
+ const y2 = yScale(parseTimelineDate(ev.endDate));
47622
+ const rectH = Math.max(y2 - y, 4);
47272
47623
  let fill2 = shapeFill(palette, evColor, isDark, { solid });
47273
47624
  let stroke2 = evColor;
47274
47625
  if (ev.uncertain) {
47275
- const gradientId = `uncertain-${ev.lineNumber}`;
47276
- const strokeGradientId = `uncertain-s-${ev.lineNumber}`;
47626
+ const gradientId = `uncertain-vg-${ev.lineNumber}`;
47627
+ const strokeGradientId = `uncertain-vg-s-${ev.lineNumber}`;
47277
47628
  const defs = svg.select("defs").node() || svg.append("defs").node();
47278
47629
  const defsEl = d3Selection22.select(defs);
47279
- defsEl.append("linearGradient").attr("id", gradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "100%").attr("y2", "0%").selectAll("stop").data([
47630
+ defsEl.append("linearGradient").attr("id", gradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "0%").attr("y2", "100%").selectAll("stop").data([
47280
47631
  { offset: "0%", opacity: 1 },
47281
47632
  { offset: "80%", opacity: 1 },
47282
47633
  { offset: "100%", opacity: 0 }
47283
- ]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", mix(evColor, bg, 30)).attr("stop-opacity", (d) => d.opacity);
47284
- defsEl.append("linearGradient").attr("id", strokeGradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "100%").attr("y2", "0%").selectAll("stop").data([
47634
+ ]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", mix(laneColor, bg, 30)).attr("stop-opacity", (d) => d.opacity);
47635
+ defsEl.append("linearGradient").attr("id", strokeGradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "0%").attr("y2", "100%").selectAll("stop").data([
47285
47636
  { offset: "0%", opacity: 1 },
47286
47637
  { offset: "80%", opacity: 1 },
47287
47638
  { offset: "100%", opacity: 0 }
@@ -47289,47 +47640,29 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
47289
47640
  fill2 = `url(#${gradientId})`;
47290
47641
  stroke2 = `url(#${strokeGradientId})`;
47291
47642
  }
47292
- 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);
47293
- if (labelFitsInside) {
47294
- 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);
47295
- } else {
47296
- const wouldFlipLeft = x + rectW > innerWidth * 0.6;
47297
- const labelFitsLeft = x - 6 - estLabelWidth > 0;
47298
- const flipLeft = wouldFlipLeft && labelFitsLeft;
47299
- 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);
47300
- }
47643
+ 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);
47644
+ 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);
47301
47645
  } else {
47302
- const estLabelWidth = ev.label.length * 7;
47303
- const wouldFlipLeft = x > innerWidth * 0.6;
47304
- const labelFitsLeft = x - 10 - estLabelWidth > 0;
47305
- const flipLeft = wouldFlipLeft && labelFitsLeft;
47306
- 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);
47307
- 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);
47646
+ 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);
47647
+ evG.append("text").attr("x", laneCenter + 10).attr("y", y).attr("dy", "0.35em").attr("fill", textColor).attr("font-size", "10px").text(ev.label);
47308
47648
  }
47309
- });
47310
- curY += laneSpan + GROUP_GAP3;
47311
- }
47649
+ }
47650
+ });
47312
47651
  } else {
47313
- const sorted = timelineEvents.slice().sort((a, b) => parseTimelineDate(a.date) - parseTimelineDate(b.date));
47314
- const scaleMargin = timelineScale ? 24 : 0;
47315
- const ERA_ROW_H = 22;
47316
- const MARKER_ROW_H = 22;
47317
- const eraReserve = timelineEras.length > 0 ? ERA_ROW_H : 0;
47318
- const markerReserve = timelineMarkers.length > 0 ? MARKER_ROW_H : 0;
47319
- const topScaleH = timelineScale ? 40 : 0;
47652
+ const scaleMargin = timelineScale ? 40 : 0;
47653
+ const markerMargin = timelineMarkers.length > 0 ? 30 : 0;
47320
47654
  const margin = {
47321
- top: 104 + topScaleH + eraReserve + markerReserve + tagLegendReserve,
47322
- right: 40,
47323
- bottom: 40 + scaleMargin,
47324
- left: 60
47655
+ top: 104 + markerMargin + tagLegendReserve,
47656
+ right: 200,
47657
+ bottom: 40,
47658
+ left: 60 + scaleMargin
47325
47659
  };
47326
- const markerLabelY = markerReserve ? -(topScaleH + MARKER_ROW_H / 2) : 0;
47327
- const eraLabelY = eraReserve ? -(topScaleH + markerReserve + ERA_ROW_H / 2) : 0;
47328
47660
  const innerWidth = width - margin.left - margin.right;
47329
47661
  const innerHeight = height - margin.top - margin.bottom;
47330
- const rowH = Math.min(28, innerHeight / sorted.length);
47331
- const xScale = d3Scale2.scaleLinear().domain([minDate - datePadding, maxDate + datePadding]).range([0, innerWidth]);
47332
- const svg = d3Selection22.select(container).append("svg").attr("width", width).attr("height", height).style("background", bgColor);
47662
+ const axisX = 20;
47663
+ const yScale = d3Scale2.scaleLinear().domain([minDate - datePadding, maxDate + datePadding]).range([0, innerHeight]);
47664
+ const sorted = timelineEvents.slice().sort((a, b) => parseTimelineDate(a.date) - parseTimelineDate(b.date));
47665
+ 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);
47333
47666
  const g = svg.append("g").attr("transform", `translate(${margin.left},${margin.top})`);
47334
47667
  renderChartTitle(
47335
47668
  svg,
@@ -47342,36 +47675,34 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
47342
47675
  renderEras(
47343
47676
  g,
47344
47677
  timelineEras,
47345
- xScale,
47346
- false,
47678
+ yScale,
47679
+ true,
47347
47680
  innerWidth,
47348
47681
  innerHeight,
47349
47682
  (s, e) => fadeToEra(g, s, e),
47350
47683
  () => fadeReset(g),
47351
47684
  timelineScale,
47352
47685
  tooltip,
47353
- palette,
47354
- eraReserve ? eraLabelY : void 0
47686
+ palette
47355
47687
  );
47356
47688
  renderMarkers(
47357
47689
  g,
47358
47690
  timelineMarkers,
47359
- xScale,
47360
- false,
47691
+ yScale,
47692
+ true,
47361
47693
  innerWidth,
47362
47694
  innerHeight,
47363
47695
  (d) => fadeToMarker(g, d),
47364
47696
  () => fadeReset(g),
47365
47697
  timelineScale,
47366
47698
  tooltip,
47367
- palette,
47368
- markerReserve ? markerLabelY : void 0
47699
+ palette
47369
47700
  );
47370
47701
  if (timelineScale) {
47371
47702
  renderTimeScale(
47372
47703
  g,
47373
- xScale,
47374
- false,
47704
+ yScale,
47705
+ true,
47375
47706
  innerWidth,
47376
47707
  innerHeight,
47377
47708
  textColor,
@@ -47382,7 +47713,6 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
47382
47713
  );
47383
47714
  }
47384
47715
  if (timelineGroups.length > 0) {
47385
- const legendY = timelineScale ? -75 : -55;
47386
47716
  renderTimelineGroupLegend(
47387
47717
  g,
47388
47718
  timelineGroups,
@@ -47390,65 +47720,46 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
47390
47720
  textColor,
47391
47721
  palette,
47392
47722
  isDark,
47393
- legendY,
47723
+ -55,
47394
47724
  (name) => fadeToGroup(g, name),
47395
47725
  () => fadeReset(g)
47396
47726
  );
47397
47727
  }
47398
- sorted.forEach((ev, i) => {
47399
- const y = i * rowH + rowH / 2;
47400
- const x = xScale(parseTimelineDate(ev.date));
47728
+ 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");
47729
+ for (const ev of sorted) {
47730
+ const y = yScale(parseTimelineDate(ev.date));
47401
47731
  const color = eventColor(ev);
47402
47732
  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(
47403
47733
  "data-end-date",
47404
47734
  ev.endDate ? String(parseTimelineDate(ev.endDate)) : null
47405
47735
  ).style("cursor", "pointer").on("mouseenter", function(event) {
47406
47736
  if (ev.group && timelineGroups.length > 0) fadeToGroup(g, ev.group);
47407
- if (timelineScale) {
47408
- showEventDatesOnScale(
47409
- g,
47410
- xScale,
47411
- ev.date,
47412
- ev.endDate,
47413
- innerHeight,
47414
- color
47415
- );
47416
- } else {
47417
- showTooltip(tooltip, buildEventTooltipHtml(ev), event);
47418
- }
47737
+ showTooltip(tooltip, buildEventTooltipHtml(ev), event);
47419
47738
  }).on("mouseleave", function() {
47420
47739
  fadeReset(g);
47421
- if (timelineScale) {
47422
- hideEventDatesOnScale(g);
47423
- } else {
47424
- hideTooltip(tooltip);
47425
- }
47740
+ hideTooltip(tooltip);
47426
47741
  }).on("mousemove", function(event) {
47427
- if (!timelineScale) {
47428
- showTooltip(tooltip, buildEventTooltipHtml(ev), event);
47429
- }
47742
+ showTooltip(tooltip, buildEventTooltipHtml(ev), event);
47430
47743
  }).on("click", () => {
47431
47744
  if (onClickItem && ev.lineNumber) onClickItem(ev.lineNumber);
47432
47745
  });
47433
47746
  setTagAttrs(evG, ev);
47434
47747
  if (ev.endDate) {
47435
- const x2 = xScale(parseTimelineDate(ev.endDate));
47436
- const rectW = Math.max(x2 - x, 4);
47437
- const estLabelWidth = ev.label.length * 7 + 16;
47438
- const labelFitsInside = rectW >= estLabelWidth;
47748
+ const y2 = yScale(parseTimelineDate(ev.endDate));
47749
+ const rectH = Math.max(y2 - y, 4);
47439
47750
  let fill2 = shapeFill(palette, color, isDark, { solid });
47440
47751
  let stroke2 = color;
47441
47752
  if (ev.uncertain) {
47442
- const gradientId = `uncertain-ts-${ev.lineNumber}`;
47443
- const strokeGradientId = `uncertain-ts-s-${ev.lineNumber}`;
47753
+ const gradientId = `uncertain-v-${ev.lineNumber}`;
47754
+ const strokeGradientId = `uncertain-v-s-${ev.lineNumber}`;
47444
47755
  const defs = svg.select("defs").node() || svg.append("defs").node();
47445
47756
  const defsEl = d3Selection22.select(defs);
47446
- defsEl.append("linearGradient").attr("id", gradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "100%").attr("y2", "0%").selectAll("stop").data([
47757
+ defsEl.append("linearGradient").attr("id", gradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "0%").attr("y2", "100%").selectAll("stop").data([
47447
47758
  { offset: "0%", opacity: 1 },
47448
47759
  { offset: "80%", opacity: 1 },
47449
47760
  { offset: "100%", opacity: 0 }
47450
47761
  ]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", mix(color, bg, 30)).attr("stop-opacity", (d) => d.opacity);
47451
- defsEl.append("linearGradient").attr("id", strokeGradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "100%").attr("y2", "0%").selectAll("stop").data([
47762
+ defsEl.append("linearGradient").attr("id", strokeGradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "0%").attr("y2", "100%").selectAll("stop").data([
47452
47763
  { offset: "0%", opacity: 1 },
47453
47764
  { offset: "80%", opacity: 1 },
47454
47765
  { offset: "100%", opacity: 0 }
@@ -47456,206 +47767,100 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
47456
47767
  fill2 = `url(#${gradientId})`;
47457
47768
  stroke2 = `url(#${strokeGradientId})`;
47458
47769
  }
47459
- 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);
47460
- if (labelFitsInside) {
47461
- 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);
47462
- } else {
47463
- const wouldFlipLeft = x + rectW > innerWidth * 0.6;
47464
- const labelFitsLeft = x - 6 - estLabelWidth > 0;
47465
- const flipLeft = wouldFlipLeft && labelFitsLeft;
47466
- 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);
47467
- }
47770
+ 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);
47771
+ 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);
47468
47772
  } else {
47469
- const estLabelWidth = ev.label.length * 7;
47470
- const wouldFlipLeft = x > innerWidth * 0.6;
47471
- const labelFitsLeft = x - 10 - estLabelWidth > 0;
47472
- const flipLeft = wouldFlipLeft && labelFitsLeft;
47473
- 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);
47474
- 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);
47475
- }
47476
- });
47477
- }
47478
- if (parsed.timelineTagGroups.length > 0) {
47479
- const LG_HEIGHT = LEGEND_HEIGHT;
47480
- const LG_PILL_PAD = LEGEND_PILL_PAD;
47481
- const LG_PILL_FONT_SIZE = LEGEND_PILL_FONT_SIZE;
47482
- const LG_CAPSULE_PAD = LEGEND_CAPSULE_PAD;
47483
- const LG_DOT_R = LEGEND_DOT_R;
47484
- const LG_ENTRY_FONT_SIZE = LEGEND_ENTRY_FONT_SIZE;
47485
- const LG_ENTRY_DOT_GAP = LEGEND_ENTRY_DOT_GAP;
47486
- const LG_ENTRY_TRAIL = LEGEND_ENTRY_TRAIL;
47487
- const LG_ICON_W = 20;
47488
- const mainSvg = d3Selection22.select(container).select("svg");
47489
- const mainG = mainSvg.select("g");
47490
- if (!mainSvg.empty() && !mainG.empty()) {
47491
- let drawSwimlaneIcon4 = function(parent, x, y, isSwimActive) {
47492
- const iconG = parent.append("g").attr("class", "tl-swimlane-icon").attr("transform", `translate(${x}, ${y})`).style("cursor", "pointer");
47493
- const barColor = isSwimActive ? palette.primary : palette.textMuted;
47494
- const barOpacity = isSwimActive ? 1 : 0.35;
47495
- const bars = [
47496
- { y: 0, w: 8 },
47497
- { y: 4, w: 12 },
47498
- { y: 8, w: 6 }
47499
- ];
47500
- for (const bar of bars) {
47501
- 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);
47502
- }
47503
- return iconG;
47504
- }, relayout2 = function() {
47505
- renderTimeline(
47506
- container,
47507
- parsed,
47508
- palette,
47509
- isDark,
47510
- onClickItem,
47511
- exportDims,
47512
- currentActiveGroup,
47513
- currentSwimlaneGroup,
47514
- onTagStateChange,
47515
- viewMode
47516
- );
47517
- }, drawLegend2 = function() {
47518
- mainSvg.selectAll(".tl-tag-legend-group").remove();
47519
- mainSvg.selectAll(".tl-tag-legend-container").remove();
47520
- const effectiveColorKey = (currentActiveGroup ?? currentSwimlaneGroup)?.toLowerCase() ?? null;
47521
- const visibleGroups = viewMode ? legendGroups.filter(
47522
- (lg) => effectiveColorKey != null && lg.group.name.toLowerCase() === effectiveColorKey
47523
- ) : legendGroups;
47524
- if (visibleGroups.length === 0) return;
47525
- const legendContainer = mainSvg.append("g").attr("class", "tl-tag-legend-container");
47526
- if (currentActiveGroup) {
47527
- legendContainer.attr(
47528
- "data-legend-active",
47529
- currentActiveGroup.toLowerCase()
47530
- );
47531
- }
47532
- const iconAddon = viewMode ? 0 : LG_ICON_W;
47533
- const centralGroups = visibleGroups.map((lg) => ({
47534
- name: lg.group.name,
47535
- entries: lg.group.entries.map((e) => ({
47536
- value: e.value,
47537
- color: e.color
47538
- }))
47539
- }));
47540
- const centralActive = viewMode ? effectiveColorKey : currentActiveGroup;
47541
- const centralConfig = {
47542
- groups: centralGroups,
47543
- position: { placement: "top-center", titleRelation: "below-title" },
47544
- mode: "fixed",
47545
- capsulePillAddonWidth: iconAddon
47546
- };
47547
- const centralState = { activeGroup: centralActive };
47548
- const centralCallbacks = viewMode ? {} : {
47549
- onGroupToggle: (groupName) => {
47550
- currentActiveGroup = currentActiveGroup === groupName.toLowerCase() ? null : groupName.toLowerCase();
47551
- drawLegend2();
47552
- recolorEvents2();
47553
- onTagStateChange?.(currentActiveGroup, currentSwimlaneGroup);
47554
- },
47555
- onEntryHover: (groupName, entryValue) => {
47556
- const tagKey = groupName.toLowerCase();
47557
- if (entryValue) {
47558
- const tagVal = entryValue.toLowerCase();
47559
- fadeToTagValue(mainG, tagKey, tagVal);
47560
- mainSvg.selectAll("[data-legend-entry]").each(function() {
47561
- const el = d3Selection22.select(this);
47562
- const ev = el.attr("data-legend-entry");
47563
- const eg = el.attr("data-tag-group") ?? el.node()?.closest?.("[data-tag-group]")?.getAttribute("data-tag-group");
47564
- el.attr(
47565
- "opacity",
47566
- eg === tagKey && ev === tagVal ? 1 : FADE_OPACITY3
47567
- );
47568
- });
47569
- } else {
47570
- fadeReset(mainG);
47571
- mainSvg.selectAll("[data-legend-entry]").attr("opacity", 1);
47572
- }
47573
- },
47574
- onGroupRendered: (groupName, groupEl, isActive) => {
47575
- const groupKey = groupName.toLowerCase();
47576
- groupEl.attr("data-tag-group", groupKey);
47577
- if (isActive && !viewMode) {
47578
- const isSwimActive = currentSwimlaneGroup != null && currentSwimlaneGroup.toLowerCase() === groupKey;
47579
- const pillWidth3 = measureLegendText(groupName, LG_PILL_FONT_SIZE) + LG_PILL_PAD;
47580
- const pillXOff = LG_CAPSULE_PAD;
47581
- const iconX = pillXOff + pillWidth3 + 5;
47582
- const iconY = (LG_HEIGHT - 10) / 2;
47583
- const iconEl = drawSwimlaneIcon4(
47584
- groupEl,
47585
- iconX,
47586
- iconY,
47587
- isSwimActive
47588
- );
47589
- iconEl.attr("data-swimlane-toggle", groupKey).on("click", (event) => {
47590
- event.stopPropagation();
47591
- currentSwimlaneGroup = currentSwimlaneGroup === groupKey ? null : groupKey;
47592
- onTagStateChange?.(
47593
- currentActiveGroup,
47594
- currentSwimlaneGroup
47595
- );
47596
- relayout2();
47597
- });
47598
- }
47599
- }
47600
- };
47601
- const legendInnerG = legendContainer.append("g").attr("transform", `translate(0, ${legendY})`);
47602
- renderLegendD3(
47603
- legendInnerG,
47604
- centralConfig,
47605
- centralState,
47606
- palette,
47607
- isDark,
47608
- centralCallbacks,
47609
- width
47610
- );
47611
- }, recolorEvents2 = function() {
47612
- const colorTG = currentActiveGroup ?? swimlaneTagGroup ?? null;
47613
- mainG.selectAll(".tl-event").each(function() {
47614
- const el = d3Selection22.select(this);
47615
- const lineNum = el.attr("data-line-number");
47616
- const ev = lineNum ? eventByLine.get(lineNum) : void 0;
47617
- if (!ev) return;
47618
- let color;
47619
- if (colorTG) {
47620
- const tagColor = resolveTagColor(
47621
- ev.metadata,
47622
- parsed.timelineTagGroups,
47623
- colorTG
47624
- );
47625
- color = tagColor ?? (ev.group && groupColorMap.has(ev.group) ? groupColorMap.get(ev.group) : textColor);
47626
- } else {
47627
- color = ev.group && groupColorMap.has(ev.group) ? groupColorMap.get(ev.group) : textColor;
47628
- }
47629
- el.selectAll("rect").attr("fill", shapeFill(palette, color, isDark, { solid })).attr("stroke", color);
47630
- el.selectAll("circle:not(.tl-event-point-outline)").attr("fill", shapeFill(palette, color, isDark, { solid })).attr("stroke", color);
47631
- });
47632
- };
47633
- var drawSwimlaneIcon3 = drawSwimlaneIcon4, relayout = relayout2, drawLegend = drawLegend2, recolorEvents = recolorEvents2;
47634
- const legendY = title ? 50 : 10;
47635
- const legendGroups = parsed.timelineTagGroups.map((g) => {
47636
- const pillW = measureLegendText(g.name, LG_PILL_FONT_SIZE) + LG_PILL_PAD;
47637
- const iconSpace = viewMode ? 8 : LG_ICON_W + 4;
47638
- let entryX = LG_CAPSULE_PAD + pillW + iconSpace;
47639
- for (const entry of g.entries) {
47640
- const textX = entryX + LG_DOT_R * 2 + LG_ENTRY_DOT_GAP;
47641
- entryX = textX + measureLegendText(entry.value, LG_ENTRY_FONT_SIZE) + LG_ENTRY_TRAIL;
47642
- }
47643
- return {
47644
- group: g,
47645
- minifiedWidth: pillW,
47646
- expandedWidth: entryX + LG_CAPSULE_PAD
47647
- };
47648
- });
47649
- let currentActiveGroup = activeTagGroup ?? null;
47650
- let currentSwimlaneGroup = swimlaneTagGroup ?? null;
47651
- const eventByLine = /* @__PURE__ */ new Map();
47652
- for (const ev of timelineEvents) {
47653
- eventByLine.set(String(ev.lineNumber), ev);
47773
+ 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);
47774
+ evG.append("text").attr("x", axisX + 16).attr("y", y).attr("dy", "0.35em").attr("fill", textColor).attr("font-size", "11px").text(ev.label);
47654
47775
  }
47655
- drawLegend2();
47776
+ evG.append("text").attr("x", axisX - 14).attr(
47777
+ "y",
47778
+ ev.endDate ? yScale(parseTimelineDate(ev.date)) + Math.max(
47779
+ yScale(parseTimelineDate(ev.endDate)) - yScale(parseTimelineDate(ev.date)),
47780
+ 4
47781
+ ) / 2 : y
47782
+ ).attr("dy", "0.35em").attr("text-anchor", "end").attr("fill", mutedColor).attr("font-size", "10px").text(ev.date + (ev.endDate ? `\u2192${ev.endDate}` : ""));
47656
47783
  }
47657
47784
  }
47658
47785
  }
47786
+ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportDims, activeTagGroup, swimlaneTagGroup, onTagStateChange, viewMode) {
47787
+ const setup = setupTimeline(
47788
+ container,
47789
+ parsed,
47790
+ palette,
47791
+ isDark,
47792
+ exportDims,
47793
+ activeTagGroup,
47794
+ swimlaneTagGroup
47795
+ );
47796
+ if (!setup) return;
47797
+ swimlaneTagGroup = setup.swimlaneTagGroup;
47798
+ const { isVertical, tagLanes } = setup;
47799
+ const hovers = makeTimelineHoverHelpers();
47800
+ if (isVertical) {
47801
+ renderTimelineVertical(
47802
+ container,
47803
+ parsed,
47804
+ palette,
47805
+ isDark,
47806
+ setup,
47807
+ hovers,
47808
+ onClickItem,
47809
+ exportDims,
47810
+ swimlaneTagGroup,
47811
+ activeTagGroup,
47812
+ onTagStateChange,
47813
+ viewMode
47814
+ );
47815
+ return;
47816
+ }
47817
+ const useGroupedHorizontal = tagLanes != null || parsed.timelineSort === "group" && parsed.timelineGroups.length > 0;
47818
+ if (useGroupedHorizontal) {
47819
+ renderTimelineHorizontalGrouped(
47820
+ container,
47821
+ parsed,
47822
+ palette,
47823
+ isDark,
47824
+ setup,
47825
+ hovers,
47826
+ onClickItem,
47827
+ exportDims,
47828
+ swimlaneTagGroup,
47829
+ activeTagGroup,
47830
+ onTagStateChange,
47831
+ viewMode
47832
+ );
47833
+ } else {
47834
+ renderTimelineHorizontalTimeSort(
47835
+ container,
47836
+ parsed,
47837
+ palette,
47838
+ isDark,
47839
+ setup,
47840
+ hovers,
47841
+ onClickItem,
47842
+ exportDims,
47843
+ swimlaneTagGroup,
47844
+ activeTagGroup,
47845
+ onTagStateChange,
47846
+ viewMode
47847
+ );
47848
+ }
47849
+ renderTimelineTagLegendOverlay(
47850
+ container,
47851
+ parsed,
47852
+ palette,
47853
+ isDark,
47854
+ setup,
47855
+ hovers,
47856
+ onClickItem,
47857
+ exportDims,
47858
+ swimlaneTagGroup,
47859
+ activeTagGroup,
47860
+ onTagStateChange,
47861
+ viewMode
47862
+ );
47863
+ }
47659
47864
  function getRotateFn(mode) {
47660
47865
  if (mode === "mixed") return () => Math.random() > 0.5 ? 0 : 90;
47661
47866
  if (mode === "angled") return () => Math.round(Math.random() * 30 - 15);
@@ -47826,7 +48031,7 @@ function regionCentroid(circles, inside) {
47826
48031
  }
47827
48032
  return { x: sx / count, y: sy / count };
47828
48033
  }
47829
- function renderVenn(container, parsed, palette, isDark, onClickItem, exportDims) {
48034
+ function renderVenn(container, parsed, palette, _isDark, onClickItem, exportDims) {
47830
48035
  const { vennSets, vennOverlaps } = parsed;
47831
48036
  const title = parsed.noTitle ? null : parsed.title;
47832
48037
  if (vennSets.length < 2 || vennSets.length > 3) return;
@@ -48060,7 +48265,7 @@ function renderVenn(container, parsed, palette, isDark, onClickItem, exportDims)
48060
48265
  };
48061
48266
  const gcx = circles.reduce((s, c) => s + c.x, 0) / n;
48062
48267
  const gcy = circles.reduce((s, c) => s + c.y, 0) / n;
48063
- function exclusiveHSpan(px, py, ci) {
48268
+ function exclusiveHSpan(_px, py, ci) {
48064
48269
  const dy = py - circles[ci].y;
48065
48270
  const halfChord = Math.sqrt(
48066
48271
  Math.max(0, circles[ci].r * circles[ci].r - dy * dy)
@@ -48973,9 +49178,9 @@ async function renderForExport(content, theme, palette, viewState, options) {
48973
49178
  blHiddenTagValues.set(k, new Set(v));
48974
49179
  }
48975
49180
  }
48976
- const { layoutBoxesAndLines: layoutBoxesAndLines2 } = await Promise.resolve().then(() => (init_layout5(), layout_exports5));
48977
49181
  const { renderBoxesAndLinesForExport: renderBoxesAndLinesForExport2 } = await Promise.resolve().then(() => (init_renderer6(), renderer_exports6));
48978
- const blLayout = layoutBoxesAndLines2(blParsed);
49182
+ const { layoutBoxesAndLines: layoutBoxesAndLines2 } = await Promise.resolve().then(() => (init_layout5(), layout_exports5));
49183
+ const blLayout = await layoutBoxesAndLines2(blParsed);
48979
49184
  const PADDING3 = 20;
48980
49185
  const titleOffset = blParsed.title ? 40 : 0;
48981
49186
  const exportWidth = blLayout.width + PADDING3 * 2;
@@ -50056,7 +50261,7 @@ var require_lz_string = __commonJS({
50056
50261
  }
50057
50262
  });
50058
50263
 
50059
- // src/internal.ts
50264
+ // src/advanced.ts
50060
50265
  init_diagnostics();
50061
50266
  init_arrows();
50062
50267
 
@@ -50127,7 +50332,7 @@ async function render(content, options) {
50127
50332
  return { svg, diagnostics };
50128
50333
  }
50129
50334
 
50130
- // src/internal.ts
50335
+ // src/advanced.ts
50131
50336
  init_chart_types();
50132
50337
 
50133
50338
  // src/chart-type-scoring.ts
@@ -50204,7 +50409,7 @@ function suggestChartTypes(prompt) {
50204
50409
  };
50205
50410
  }
50206
50411
 
50207
- // src/internal.ts
50412
+ // src/advanced.ts
50208
50413
  init_dgmo_router();
50209
50414
  init_chart();
50210
50415
  init_echarts();
@@ -50256,7 +50461,7 @@ function collapseStateGroups(parsed, collapsedGroups) {
50256
50461
  };
50257
50462
  }
50258
50463
 
50259
- // src/internal.ts
50464
+ // src/advanced.ts
50260
50465
  init_parser2();
50261
50466
  init_layout3();
50262
50467
  init_renderer4();
@@ -50334,7 +50539,7 @@ function collapseBoxesAndLines(parsed, collapsedGroups) {
50334
50539
  };
50335
50540
  }
50336
50541
 
50337
- // src/internal.ts
50542
+ // src/advanced.ts
50338
50543
  init_parser7();
50339
50544
  init_layout2();
50340
50545
  init_renderer2();
@@ -50476,7 +50681,7 @@ function validateComputed(computed) {
50476
50681
  return diagnostics;
50477
50682
  }
50478
50683
 
50479
- // src/internal.ts
50684
+ // src/advanced.ts
50480
50685
  init_roles();
50481
50686
  init_layout10();
50482
50687
  init_renderer10();
@@ -50512,7 +50717,7 @@ function normalizePertSourceForShare(dsl) {
50512
50717
  return out.join("\n");
50513
50718
  }
50514
50719
 
50515
- // src/internal.ts
50720
+ // src/advanced.ts
50516
50721
  init_monte_carlo();
50517
50722
  init_renderer11();
50518
50723
  init_collapse();
@@ -51040,7 +51245,7 @@ function mergeTagGroups(inline, tagsFile, imported) {
51040
51245
  return Array.from(seen.values());
51041
51246
  }
51042
51247
 
51043
- // src/internal.ts
51248
+ // src/advanced.ts
51044
51249
  init_layout9();
51045
51250
  init_flowchart_renderer();
51046
51251
  init_echarts();
@@ -51153,7 +51358,7 @@ init_parser8();
51153
51358
  init_parser2();
51154
51359
  init_parser10();
51155
51360
  init_parsing();
51156
- init_dgmo_router();
51361
+ init_chart_types();
51157
51362
  var extractorRegistry = /* @__PURE__ */ new Map();
51158
51363
  function registerExtractor(kind, fn) {
51159
51364
  extractorRegistry.set(kind, fn);
@@ -51632,9 +51837,12 @@ for (const [type, spec] of COMPLETION_REGISTRY) {
51632
51837
  };
51633
51838
  }
51634
51839
  }
51840
+ var CHART_TYPE_DESCRIPTIONS2 = Object.fromEntries(
51841
+ chartTypes.map((c) => [c.id, c.description])
51842
+ );
51635
51843
  var CHART_TYPES = [...ALL_CHART_TYPES].filter((t) => t !== "multi-line").map((name) => ({
51636
51844
  name,
51637
- description: CHART_TYPE_DESCRIPTIONS[name] ?? name
51845
+ description: CHART_TYPE_DESCRIPTIONS2[name] ?? name
51638
51846
  }));
51639
51847
  var ENTITY_TYPES = /* @__PURE__ */ new Map([
51640
51848
  [
@@ -52340,7 +52548,7 @@ function extractJourneyMapSymbols(docText) {
52340
52548
  };
52341
52549
  }
52342
52550
 
52343
- // src/internal.ts
52551
+ // src/advanced.ts
52344
52552
  init_parsing();
52345
52553
  init_palettes();
52346
52554
 
@@ -52351,13 +52559,12 @@ var themes = {
52351
52559
  transparent: "transparent"
52352
52560
  };
52353
52561
 
52354
- // src/internal.ts
52562
+ // src/advanced.ts
52355
52563
  init_dgmo_router();
52356
52564
  export {
52357
52565
  ALL_CHART_TYPES,
52358
52566
  AMBIGUITY_THRESHOLD,
52359
52567
  ARROW_DIAGNOSTIC_CODES,
52360
- BETA_CHART_IDS,
52361
52568
  CHART_TYPES,
52362
52569
  CHART_TYPE_DESCRIPTIONS,
52363
52570
  COMPLETION_REGISTRY,