@diagrammo/dgmo 0.15.0 → 0.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/README.md +14 -1
  2. package/dist/advanced.cjs +53069 -0
  3. package/dist/advanced.d.cts +4691 -0
  4. package/dist/advanced.d.ts +4691 -0
  5. package/dist/advanced.js +52823 -0
  6. package/dist/auto.cjs +1495 -1288
  7. package/dist/auto.js +132 -109
  8. package/dist/auto.mjs +1491 -1284
  9. package/dist/cli.cjs +173 -150
  10. package/dist/index.cjs +1486 -1276
  11. package/dist/index.d.cts +45 -1
  12. package/dist/index.d.ts +45 -1
  13. package/dist/index.js +1481 -1272
  14. package/dist/internal.cjs +1497 -1289
  15. package/dist/internal.d.cts +80 -79
  16. package/dist/internal.d.ts +80 -79
  17. package/dist/internal.js +1492 -1285
  18. package/dist/pert.cjs +325 -0
  19. package/dist/pert.d.cts +542 -0
  20. package/dist/pert.d.ts +542 -0
  21. package/dist/pert.js +294 -0
  22. package/package.json +28 -3
  23. package/src/advanced.ts +731 -0
  24. package/src/auto/index.ts +14 -13
  25. package/src/boxes-and-lines/layout.ts +481 -445
  26. package/src/c4/parser.ts +7 -7
  27. package/src/chart-types.ts +0 -5
  28. package/src/class/parser.ts +1 -9
  29. package/src/cli.ts +9 -7
  30. package/src/completion-types.ts +28 -0
  31. package/src/completion.ts +15 -18
  32. package/src/cycle/layout.ts +2 -2
  33. package/src/d3.ts +1455 -1122
  34. package/src/echarts.ts +11 -11
  35. package/src/er/parser.ts +1 -9
  36. package/src/er/renderer.ts +1 -1
  37. package/src/gantt/calculator.ts +1 -11
  38. package/src/gantt/parser.ts +16 -16
  39. package/src/gantt/renderer.ts +2 -2
  40. package/src/graph/flowchart-parser.ts +1 -1
  41. package/src/graph/flowchart-renderer.ts +1 -1
  42. package/src/graph/state-renderer.ts +1 -1
  43. package/src/index.ts +17 -1
  44. package/src/infra/parser.ts +19 -19
  45. package/src/infra/renderer.ts +2 -2
  46. package/src/internal.ts +9 -721
  47. package/src/kanban/parser.ts +2 -2
  48. package/src/mindmap/layout.ts +1 -1
  49. package/src/mindmap/parser.ts +1 -1
  50. package/src/org/parser.ts +1 -1
  51. package/src/org/renderer.ts +1 -1
  52. package/src/pert/layout.ts +1 -1
  53. package/src/pert/monte-carlo.ts +2 -2
  54. package/src/pert/parser.ts +3 -3
  55. package/src/raci/parser.ts +4 -4
  56. package/src/raci/renderer.ts +1 -1
  57. package/src/sequence/renderer.ts +1 -4
  58. package/src/sitemap/parser.ts +1 -1
  59. package/src/tech-radar/interactive.ts +1 -1
  60. package/src/tech-radar/renderer.ts +1 -1
  61. package/src/utils/tag-groups.ts +11 -12
  62. package/src/wireframe/layout.ts +11 -7
  63. package/src/wireframe/parser.ts +2 -2
  64. package/src/wireframe/renderer.ts +5 -2
package/dist/index.js CHANGED
@@ -2236,7 +2236,7 @@ function injectDefaultTagMetadata(entities, tagGroups, skip) {
2236
2236
  }
2237
2237
  }
2238
2238
  }
2239
- function resolveActiveTagGroup(_tagGroups, explicitActiveTag, programmaticOverride) {
2239
+ function resolveActiveTagGroup(tagGroups, explicitActiveTag, programmaticOverride) {
2240
2240
  if (programmaticOverride !== void 0) {
2241
2241
  if (!programmaticOverride) return null;
2242
2242
  if (programmaticOverride.toLowerCase() === "none") return null;
@@ -2246,6 +2246,7 @@ function resolveActiveTagGroup(_tagGroups, explicitActiveTag, programmaticOverri
2246
2246
  if (explicitActiveTag.toLowerCase() === "none") return null;
2247
2247
  return explicitActiveTag;
2248
2248
  }
2249
+ if (tagGroups.length > 0) return tagGroups[0].name;
2249
2250
  return null;
2250
2251
  }
2251
2252
  function matchTagBlockHeading(trimmed) {
@@ -5326,12 +5327,6 @@ function parseClassDiagram(content, palette) {
5326
5327
  diagnostics: [],
5327
5328
  error: null
5328
5329
  };
5329
- const _fail = (line12, message) => {
5330
- const diag = makeDgmoError(line12, message);
5331
- result.diagnostics.push(diag);
5332
- result.error = formatDgmoError(diag);
5333
- return result;
5334
- };
5335
5330
  const classMap = /* @__PURE__ */ new Map();
5336
5331
  const nameAliasMap = /* @__PURE__ */ new Map();
5337
5332
  function resolveAliasName(token) {
@@ -5726,12 +5721,6 @@ function parseERDiagram(content, palette) {
5726
5721
  diagnostics: [],
5727
5722
  error: null
5728
5723
  };
5729
- const _fail = (line12, message) => {
5730
- const diag = makeDgmoError(line12, message);
5731
- result.diagnostics.push(diag);
5732
- result.error = formatDgmoError(diag);
5733
- return result;
5734
- };
5735
5724
  const pushError = (line12, message) => {
5736
5725
  const diag = makeDgmoError(line12, message);
5737
5726
  result.diagnostics.push(diag);
@@ -7190,7 +7179,7 @@ function buildSankeyOption(parsed, textColor, colors, bg, titleConfig) {
7190
7179
  ]
7191
7180
  };
7192
7181
  }
7193
- function buildChordOption(parsed, palette, isDark, textColor, colors, bg, titleConfig) {
7182
+ function buildChordOption(parsed, palette, isDark, textColor, colors, _bg, titleConfig) {
7194
7183
  const nodeSet = /* @__PURE__ */ new Set();
7195
7184
  if (parsed.links) {
7196
7185
  for (const link of parsed.links) {
@@ -7304,7 +7293,7 @@ function evaluateExpression(expr, x) {
7304
7293
  return NaN;
7305
7294
  }
7306
7295
  }
7307
- function buildFunctionOption(parsed, palette, isDark, textColor, axisLineColor, gridOpacity, colors, titleConfig) {
7296
+ function buildFunctionOption(parsed, palette, _isDark, textColor, axisLineColor, gridOpacity, colors, titleConfig) {
7308
7297
  const xRange = parsed.xRange ?? { min: -10, max: 10 };
7309
7298
  const samples = 200;
7310
7299
  const step = (xRange.max - xRange.min) / samples;
@@ -7977,7 +7966,7 @@ function buildHeatmapOption(parsed, palette, isDark, textColor, axisLineColor, t
7977
7966
  ]
7978
7967
  };
7979
7968
  }
7980
- function buildFunnelOption(parsed, palette, isDark, textColor, colors, bg, titleConfig) {
7969
+ function buildFunnelOption(parsed, palette, isDark, textColor, colors, _bg, titleConfig) {
7981
7970
  const sorted = [...parsed.data].sort((a, b) => b.value - a.value);
7982
7971
  const data = sorted.map((d) => {
7983
7972
  const stroke2 = d.color ?? colors[parsed.data.indexOf(d) % colors.length];
@@ -8260,7 +8249,7 @@ function wrapLabel(text, maxChars) {
8260
8249
  if (current) lines.push(current);
8261
8250
  return lines.join("\n");
8262
8251
  }
8263
- function buildBarOption(parsed, palette, isDark, textColor, axisLineColor, splitLineColor, gridOpacity, colors, bg, titleConfig, chartWidth) {
8252
+ function buildBarOption(parsed, palette, isDark, textColor, axisLineColor, splitLineColor, gridOpacity, colors, _bg, titleConfig, chartWidth) {
8264
8253
  const { xLabel, yLabel } = resolveAxisLabels(parsed);
8265
8254
  const isHorizontal = parsed.orientation === "horizontal";
8266
8255
  const labels = parsed.data.map((d) => d.label);
@@ -8587,7 +8576,7 @@ function pieLabelLayout(parsed) {
8587
8576
  if (maxLen > 18) return { outerRadius: 55, fontSize: 13 };
8588
8577
  return { outerRadius: 70, fontSize: 14 };
8589
8578
  }
8590
- function buildPieOption(parsed, palette, isDark, textColor, colors, bg, titleConfig, isDoughnut) {
8579
+ function buildPieOption(parsed, palette, isDark, textColor, colors, _bg, titleConfig, isDoughnut) {
8591
8580
  const HIDE_AXES = { xAxis: { show: false }, yAxis: { show: false } };
8592
8581
  const data = parsed.data.map((d, i) => {
8593
8582
  const stroke2 = d.color ?? colors[i % colors.length];
@@ -8686,7 +8675,7 @@ function buildRadarOption(parsed, palette, isDark, textColor, gridOpacity, title
8686
8675
  ]
8687
8676
  };
8688
8677
  }
8689
- function buildPolarAreaOption(parsed, palette, isDark, textColor, colors, bg, titleConfig) {
8678
+ function buildPolarAreaOption(parsed, palette, isDark, textColor, colors, _bg, titleConfig) {
8690
8679
  const data = parsed.data.map((d, i) => {
8691
8680
  const stroke2 = d.color ?? colors[i % colors.length];
8692
8681
  return {
@@ -8729,7 +8718,7 @@ function buildPolarAreaOption(parsed, palette, isDark, textColor, colors, bg, ti
8729
8718
  ]
8730
8719
  };
8731
8720
  }
8732
- function buildBarStackedOption(parsed, palette, isDark, textColor, axisLineColor, splitLineColor, gridOpacity, colors, bg, titleConfig, chartWidth) {
8721
+ function buildBarStackedOption(parsed, palette, isDark, textColor, axisLineColor, splitLineColor, gridOpacity, colors, _bg, titleConfig, chartWidth) {
8733
8722
  const { xLabel, yLabel } = resolveAxisLabels(parsed);
8734
8723
  const isHorizontal = parsed.orientation === "horizontal";
8735
8724
  const seriesNames = parsed.seriesNames ?? [];
@@ -8869,8 +8858,8 @@ async function renderExtendedChartForExport(content, theme, palette) {
8869
8858
  const titleHeight = option.title && option.title.text ? 40 : 0;
8870
8859
  const legendY = 8 + titleHeight;
8871
8860
  const grid = option.grid;
8872
- const gridLeftPct = grid?.left ? parseFloat(String(grid.left)) : void 0;
8873
- const gridRightPct = grid?.right ? parseFloat(String(grid.right)) : void 0;
8861
+ const gridLeftPct = grid?.["left"] ? parseFloat(String(grid["left"])) : void 0;
8862
+ const gridRightPct = grid?.["right"] ? parseFloat(String(grid["right"])) : void 0;
8874
8863
  const { svg: legendSvgStr } = renderLegendSvg(legendGroups, {
8875
8864
  palette: effectivePalette,
8876
8865
  isDark,
@@ -9216,7 +9205,7 @@ function parseOrg(content, palette) {
9216
9205
  }
9217
9206
  return result;
9218
9207
  }
9219
- function parseNodeLabel(trimmed, _indent, lineNumber, palette, counter, metaAliasMap = /* @__PURE__ */ new Map(), warnFn, nameAliasMap) {
9208
+ function parseNodeLabel(trimmed, _indent, lineNumber, _palette, counter, metaAliasMap = /* @__PURE__ */ new Map(), warnFn, nameAliasMap) {
9220
9209
  const segments = trimmed.split("|").map((s) => s.trim());
9221
9210
  let label = segments[0];
9222
9211
  const asMatch = label.match(/^(.*?)\s+as\s+([A-Za-z][A-Za-z0-9_]{0,11})\s*$/);
@@ -9465,8 +9454,8 @@ function parseKanban(content, palette) {
9465
9454
  columnMetadata,
9466
9455
  parsePipeMetadata(pipeSegments, metaAliasMap)
9467
9456
  );
9468
- if (columnMetadata.wip) {
9469
- const wipVal = parseInt(columnMetadata.wip, 10);
9457
+ if (columnMetadata["wip"]) {
9458
+ const wipVal = parseInt(columnMetadata["wip"], 10);
9470
9459
  if (!isNaN(wipVal)) {
9471
9460
  wipLimit = wipVal;
9472
9461
  }
@@ -9845,7 +9834,7 @@ function parseC4(content, palette) {
9845
9834
  );
9846
9835
  const shape = inferC4Shape(
9847
9836
  nodeName,
9848
- metadata.tech ?? metadata.technology
9837
+ metadata["tech"] ?? metadata["technology"]
9849
9838
  );
9850
9839
  const dNode = {
9851
9840
  name: nodeName,
@@ -9948,11 +9937,11 @@ function parseC4(content, palette) {
9948
9937
  target = targetBody.substring(0, pipeIdx).trim();
9949
9938
  const metaPart = targetBody.substring(pipeIdx + 1).trim();
9950
9939
  const meta = parsePipeMetadata(["", metaPart], metaAliasMap);
9951
- if (meta.tech) {
9952
- technology = meta.tech;
9940
+ if (meta["tech"]) {
9941
+ technology = meta["tech"];
9953
9942
  }
9954
- if (meta.technology) {
9955
- technology = meta.technology;
9943
+ if (meta["technology"]) {
9944
+ technology = meta["technology"];
9956
9945
  }
9957
9946
  }
9958
9947
  const rel = {
@@ -10086,7 +10075,7 @@ function parseC4(content, palette) {
10086
10075
  metaAliasMap,
10087
10076
  () => pushError(lineNumber, MULTIPLE_PIPE_ERROR)
10088
10077
  );
10089
- const shape = explicitShape ?? inferC4Shape(namePart, metadata.tech ?? metadata.technology);
10078
+ const shape = explicitShape ?? inferC4Shape(namePart, metadata["tech"] ?? metadata["technology"]);
10090
10079
  let isADescription;
10091
10080
  if ("description" in metadata) {
10092
10081
  const descVal = metadata["description"].trim();
@@ -10146,7 +10135,7 @@ function parseC4(content, palette) {
10146
10135
  metaAliasMap,
10147
10136
  () => pushError(lineNumber, MULTIPLE_PIPE_ERROR)
10148
10137
  );
10149
- const shape = explicitShape ?? inferC4Shape(namePart, metadata.tech ?? metadata.technology);
10138
+ const shape = explicitShape ?? inferC4Shape(namePart, metadata["tech"] ?? metadata["technology"]);
10150
10139
  let prefixDescription;
10151
10140
  if ("description" in metadata) {
10152
10141
  const descVal = metadata["description"].trim();
@@ -10755,7 +10744,7 @@ function parseSitemap(content, palette) {
10755
10744
  }
10756
10745
  return result;
10757
10746
  }
10758
- function parseNodeLabel2(trimmed, lineNumber, palette, counter, metaAliasMap = /* @__PURE__ */ new Map(), warnFn, _diagnostics, nameAliasMap) {
10747
+ function parseNodeLabel2(trimmed, lineNumber, _palette, counter, metaAliasMap = /* @__PURE__ */ new Map(), warnFn, _diagnostics, nameAliasMap) {
10759
10748
  const segments = trimmed.split("|").map((s) => s.trim());
10760
10749
  let label = segments[0];
10761
10750
  const asMatch = label.match(/^(.*?)\s+as\s+([A-Za-z][A-Za-z0-9_]{0,11})\s*$/);
@@ -11046,11 +11035,11 @@ function parseInfra(content) {
11046
11035
  continue;
11047
11036
  }
11048
11037
  if (trimmed === "animate") {
11049
- result.options.animate = "on";
11038
+ result.options["animate"] = "on";
11050
11039
  continue;
11051
11040
  }
11052
11041
  if (trimmed === "no-animate") {
11053
- result.options.animate = "off";
11042
+ result.options["animate"] = "off";
11054
11043
  continue;
11055
11044
  }
11056
11045
  if (tryParseSharedOption(trimmed, result.options)) {
@@ -11204,8 +11193,8 @@ function parseInfra(content) {
11204
11193
  const pipeMeta = extractPipeMetadata(targetRaw);
11205
11194
  const targetName = pipeMeta.clean || targetRaw;
11206
11195
  warnUnparsedPipeMeta(targetName, lineNumber, warn);
11207
- const split = pipeMeta.tags.split ? parseFloat(pipeMeta.tags.split) : null;
11208
- const fanoutRaw = pipeMeta.tags.fanout ? parseInt(pipeMeta.tags.fanout, 10) : null;
11196
+ const split = pipeMeta.tags["split"] ? parseFloat(pipeMeta.tags["split"]) : null;
11197
+ const fanoutRaw = pipeMeta.tags["fanout"] ? parseInt(pipeMeta.tags["fanout"], 10) : null;
11209
11198
  if (fanoutRaw !== null && fanoutRaw < 1) {
11210
11199
  warn(
11211
11200
  lineNumber,
@@ -11236,8 +11225,8 @@ function parseInfra(content) {
11236
11225
  const pipeMeta = extractPipeMetadata(targetRaw);
11237
11226
  const targetName = pipeMeta.clean || targetRaw;
11238
11227
  warnUnparsedPipeMeta(targetName, lineNumber, warn);
11239
- const split = pipeMeta.tags.split ? parseFloat(pipeMeta.tags.split) : null;
11240
- const fanoutRaw = pipeMeta.tags.fanout ? parseInt(pipeMeta.tags.fanout, 10) : null;
11228
+ const split = pipeMeta.tags["split"] ? parseFloat(pipeMeta.tags["split"]) : null;
11229
+ const fanoutRaw = pipeMeta.tags["fanout"] ? parseInt(pipeMeta.tags["fanout"], 10) : null;
11241
11230
  if (fanoutRaw !== null && fanoutRaw < 1) {
11242
11231
  warn(
11243
11232
  lineNumber,
@@ -11271,8 +11260,8 @@ function parseInfra(content) {
11271
11260
  const pipeMeta = extractPipeMetadata(targetRaw);
11272
11261
  const targetName = pipeMeta.clean || targetRaw;
11273
11262
  warnUnparsedPipeMeta(targetName, lineNumber, warn);
11274
- const split = pipeMeta.tags.split ? parseFloat(pipeMeta.tags.split) : null;
11275
- const fanoutRaw = pipeMeta.tags.fanout ? parseInt(pipeMeta.tags.fanout, 10) : null;
11263
+ const split = pipeMeta.tags["split"] ? parseFloat(pipeMeta.tags["split"]) : null;
11264
+ const fanoutRaw = pipeMeta.tags["fanout"] ? parseInt(pipeMeta.tags["fanout"], 10) : null;
11276
11265
  if (fanoutRaw !== null && fanoutRaw < 1) {
11277
11266
  warn(
11278
11267
  lineNumber,
@@ -11303,8 +11292,8 @@ function parseInfra(content) {
11303
11292
  const pipeMeta = extractPipeMetadata(targetRaw);
11304
11293
  const targetName = pipeMeta.clean || targetRaw;
11305
11294
  warnUnparsedPipeMeta(targetName, lineNumber, warn);
11306
- const split = pipeMeta.tags.split ? parseFloat(pipeMeta.tags.split) : null;
11307
- const fanoutRaw = pipeMeta.tags.fanout ? parseInt(pipeMeta.tags.fanout, 10) : null;
11295
+ const split = pipeMeta.tags["split"] ? parseFloat(pipeMeta.tags["split"]) : null;
11296
+ const fanoutRaw = pipeMeta.tags["fanout"] ? parseInt(pipeMeta.tags["fanout"], 10) : null;
11308
11297
  if (fanoutRaw !== null && fanoutRaw < 1) {
11309
11298
  warn(
11310
11299
  lineNumber,
@@ -12011,15 +12000,15 @@ function parseGantt(content, palette) {
12011
12000
  metaAliasMap,
12012
12001
  () => warn(lineNumber, MULTIPLE_PIPE_ERROR)
12013
12002
  );
12014
- if (meta.lag || meta.lead) {
12015
- const key = meta.lag ? "lag" : "lead";
12003
+ if (meta["lag"] || meta["lead"]) {
12004
+ const key = meta["lag"] ? "lag" : "lead";
12016
12005
  softError(
12017
12006
  lineNumber,
12018
12007
  `"${key}" is no longer supported \u2014 use "offset: ${meta[key]}" instead.${key === "lead" ? ' Negate the value for lead behavior: "offset: -...".' : ""}`
12019
12008
  );
12020
12009
  }
12021
- if (meta.offset) {
12022
- const raw = meta.offset;
12010
+ if (meta["offset"]) {
12011
+ const raw = meta["offset"];
12023
12012
  if (raw.trim().startsWith("+")) {
12024
12013
  warn(
12025
12014
  lineNumber,
@@ -12406,15 +12395,15 @@ function parseGantt(content, palette) {
12406
12395
  metaAliasMap,
12407
12396
  () => warn(lineNumber, MULTIPLE_PIPE_ERROR)
12408
12397
  );
12409
- if (meta.lag || meta.lead) {
12410
- const key = meta.lag ? "lag" : "lead";
12398
+ if (meta["lag"] || meta["lead"]) {
12399
+ const key = meta["lag"] ? "lag" : "lead";
12411
12400
  softError(
12412
12401
  lineNumber,
12413
12402
  `"${key}" is no longer supported \u2014 use "offset: ${meta[key]}" instead.${key === "lead" ? ' Negate the value for lead behavior: "offset: -...".' : ""}`
12414
12403
  );
12415
12404
  }
12416
- if (meta.offset) {
12417
- const raw = meta.offset;
12405
+ if (meta["offset"]) {
12406
+ const raw = meta["offset"];
12418
12407
  if (raw.trim().startsWith("+")) {
12419
12408
  warn(
12420
12409
  lineNumber,
@@ -12485,9 +12474,9 @@ function parseGantt(content, palette) {
12485
12474
  () => warn(ln, MULTIPLE_PIPE_ERROR)
12486
12475
  ) : {};
12487
12476
  let progress = null;
12488
- if (metadata.progress) {
12489
- progress = parseFloat(metadata.progress);
12490
- delete metadata.progress;
12477
+ if (metadata["progress"]) {
12478
+ progress = parseFloat(metadata["progress"]);
12479
+ delete metadata["progress"];
12491
12480
  }
12492
12481
  for (const part of segments.slice(1).join(",").split(",")) {
12493
12482
  const seg = part.trim();
@@ -12496,16 +12485,16 @@ function parseGantt(content, palette) {
12496
12485
  progress = parseInt(progressMatch[1], 10);
12497
12486
  }
12498
12487
  }
12499
- if (metadata.lag || metadata.lead) {
12500
- const key = metadata.lag ? "lag" : "lead";
12488
+ if (metadata["lag"] || metadata["lead"]) {
12489
+ const key = metadata["lag"] ? "lag" : "lead";
12501
12490
  softError(
12502
12491
  ln,
12503
12492
  `"${key}" is no longer supported \u2014 use "offset: ${metadata[key]}" instead.${key === "lead" ? ' Negate the value for lead behavior: "offset: -...".' : ""}`
12504
12493
  );
12505
12494
  }
12506
12495
  let taskOffset;
12507
- if (metadata.offset) {
12508
- const raw = metadata.offset;
12496
+ if (metadata["offset"]) {
12497
+ const raw = metadata["offset"];
12509
12498
  if (raw.trim().startsWith("+")) {
12510
12499
  warn(
12511
12500
  ln,
@@ -12520,7 +12509,7 @@ function parseGantt(content, palette) {
12520
12509
  );
12521
12510
  }
12522
12511
  }
12523
- delete metadata.offset;
12512
+ delete metadata["offset"];
12524
12513
  }
12525
12514
  const groupPath = currentGroupPath();
12526
12515
  const inheritedMeta = {};
@@ -13043,7 +13032,7 @@ function parsePert(content, parseOpts = {}) {
13043
13032
  id,
13044
13033
  name,
13045
13034
  activityIds: [],
13046
- collapsed: meta.collapsed === "true",
13035
+ collapsed: meta["collapsed"] === "true",
13047
13036
  lineNumber,
13048
13037
  ...Object.keys(tags).length > 0 && { tags }
13049
13038
  });
@@ -13305,7 +13294,7 @@ function parsePert(content, parseOpts = {}) {
13305
13294
  name: decl.name,
13306
13295
  ...decl.alias !== void 0 && { alias: decl.alias },
13307
13296
  duration: estimate,
13308
- ...meta.confidence && { confidence: meta.confidence },
13297
+ ...meta["confidence"] && { confidence: meta["confidence"] },
13309
13298
  ...decl.groupHint !== void 0 && { groupId: decl.groupHint },
13310
13299
  lineNumber: decl.lineNumber,
13311
13300
  isMilestone,
@@ -14636,7 +14625,7 @@ function parseMindmap(content, palette) {
14636
14625
  }
14637
14626
  return result;
14638
14627
  }
14639
- function parseNodeLine2(trimmed, lineNumber, palette, counter, aliasMap, warnFn) {
14628
+ function parseNodeLine2(trimmed, lineNumber, _palette, counter, aliasMap, warnFn) {
14640
14629
  const segments = trimmed.split("|").map((s) => s.trim());
14641
14630
  const label = segments[0];
14642
14631
  const metadata = parsePipeMetadata(
@@ -15080,7 +15069,7 @@ function parseWireframe(content) {
15080
15069
  wrapper.isContainer = true;
15081
15070
  wrapper.orientation = "horizontal";
15082
15071
  wrapper.children = children;
15083
- wrapper.metadata._inlineRow = "true";
15072
+ wrapper.metadata["_inlineRow"] = "true";
15084
15073
  pushElement(wrapper);
15085
15074
  }
15086
15075
  for (let i = 0; i < lines.length; i++) {
@@ -15231,7 +15220,7 @@ function parseWireframe(content) {
15231
15220
  wrapper.isContainer = true;
15232
15221
  wrapper.orientation = "horizontal";
15233
15222
  wrapper.children.push(labelEl, fieldEl);
15234
- wrapper.metadata._labelField = "true";
15223
+ wrapper.metadata["_labelField"] = "true";
15235
15224
  pushElement(wrapper);
15236
15225
  }
15237
15226
  } else {
@@ -17052,9 +17041,9 @@ function parseRaci(content, palette) {
17052
17041
  let roleColor;
17053
17042
  if (segments.length > 1) {
17054
17043
  const meta = parsePipeMetadata(segments);
17055
- if (meta.color) {
17044
+ if (meta["color"]) {
17056
17045
  roleColor = resolveColorWithDiagnostic(
17057
- meta.color,
17046
+ meta["color"],
17058
17047
  j + 1,
17059
17048
  result.diagnostics,
17060
17049
  palette
@@ -17121,9 +17110,9 @@ function parseRaci(content, palette) {
17121
17110
  let phaseColor;
17122
17111
  if (phaseMatch[2]) {
17123
17112
  const meta = parsePipeMetadata(["", phaseMatch[2]]);
17124
- if (meta.color) {
17113
+ if (meta["color"]) {
17125
17114
  phaseColor = resolveColorWithDiagnostic(
17126
- meta.color,
17115
+ meta["color"],
17127
17116
  lineNumber,
17128
17117
  result.diagnostics,
17129
17118
  palette
@@ -19133,7 +19122,7 @@ function renderOrg(container, parsed, layout, palette, isDark, onClickItem, expo
19133
19122
  displayNames.set(group.name.toLowerCase(), group.name);
19134
19123
  }
19135
19124
  const rootNodeIds = new Set(parsed.roots.map((r) => r.id));
19136
- const colorOff = parsed.options?.color === "off";
19125
+ const colorOff = parsed.options?.["color"] === "off";
19137
19126
  for (const c of layout.containers) {
19138
19127
  const cG = contentG.append("g").attr("transform", `translate(${c.x}, ${c.y})`).attr("class", "org-container").attr("data-line-number", String(c.lineNumber));
19139
19128
  if (activeTagGroup) {
@@ -22234,7 +22223,7 @@ function renderERDiagram(container, parsed, layout, palette, isDark, onClickItem
22234
22223
  const seriesColors2 = getSeriesColors(palette);
22235
22224
  const semanticRoles = useSemanticColors ? classifyEREntities(parsed.tables, parsed.relationships) : null;
22236
22225
  const semanticActive = semanticRoles !== null && (semanticColorsActive ?? true);
22237
- const useLabels = parsed.options.notation === "labels";
22226
+ const useLabels = parsed.options["notation"] === "labels";
22238
22227
  for (const edge of layout.edges) {
22239
22228
  if (edge.points.length < 2) continue;
22240
22229
  const edgeG = contentG.append("g").attr("class", "er-edge-group").attr("data-line-number", String(edge.lineNumber));
@@ -22447,495 +22436,6 @@ var init_renderer5 = __esm({
22447
22436
  }
22448
22437
  });
22449
22438
 
22450
- // src/boxes-and-lines/layout.ts
22451
- var layout_exports5 = {};
22452
- __export(layout_exports5, {
22453
- layoutBoxesAndLines: () => layoutBoxesAndLines
22454
- });
22455
- import dagre4 from "@dagrejs/dagre";
22456
- function clipToRectBorder2(cx, cy, w, h, tx, ty) {
22457
- const dx = tx - cx;
22458
- const dy = ty - cy;
22459
- if (dx === 0 && dy === 0) return { x: cx, y: cy };
22460
- const hw = w / 2;
22461
- const hh = h / 2;
22462
- const sx = dx !== 0 ? hw / Math.abs(dx) : Infinity;
22463
- const sy = dy !== 0 ? hh / Math.abs(dy) : Infinity;
22464
- const s = Math.min(sx, sy);
22465
- return { x: cx + dx * s, y: cy + dy * s };
22466
- }
22467
- function splitCamelCase(word) {
22468
- const parts = [];
22469
- let start = 0;
22470
- for (let i = 1; i < word.length; i++) {
22471
- const prev = word[i - 1];
22472
- const curr = word[i];
22473
- const next = i + 1 < word.length ? word[i + 1] : "";
22474
- const lowerToUpper = prev >= "a" && prev <= "z" && curr >= "A" && curr <= "Z";
22475
- const upperRunEnd = prev >= "A" && prev <= "Z" && curr >= "A" && curr <= "Z" && next >= "a" && next <= "z";
22476
- if (lowerToUpper || upperRunEnd) {
22477
- parts.push(word.slice(start, i));
22478
- start = i;
22479
- }
22480
- }
22481
- parts.push(word.slice(start));
22482
- return parts.length > 1 ? parts : [word];
22483
- }
22484
- function estimateLabelLines(label, nodeWidth2 = NODE_WIDTH) {
22485
- const rawParts = label.split(/[\s-]+/);
22486
- const words = [];
22487
- for (const part of rawParts) {
22488
- if (!part) continue;
22489
- words.push(...splitCamelCase(part));
22490
- }
22491
- for (let fontSize = 13; fontSize >= 9; fontSize--) {
22492
- const charWidth = fontSize * 0.6;
22493
- const maxChars = Math.floor((nodeWidth2 - 24) / charWidth);
22494
- if (maxChars < 2) continue;
22495
- let lines = 1;
22496
- let current = "";
22497
- for (const word of words) {
22498
- const test = current ? `${current} ${word}` : word;
22499
- if (test.length <= maxChars) {
22500
- current = test;
22501
- } else {
22502
- lines++;
22503
- current = word;
22504
- }
22505
- }
22506
- if (lines <= MAX_LABEL_LINES) return Math.min(lines, MAX_LABEL_LINES);
22507
- }
22508
- return MAX_LABEL_LINES;
22509
- }
22510
- function computeNodeSize(node) {
22511
- if (!node.description || node.description.length === 0) {
22512
- return { width: NODE_WIDTH, height: NODE_HEIGHT };
22513
- }
22514
- const w = DESC_NODE_WIDTH;
22515
- const labelLines = estimateLabelLines(node.label, w);
22516
- const labelHeight = labelLines * 13 * LABEL_LINE_HEIGHT + LABEL_PAD;
22517
- const charsPerLine = Math.floor((w - 24) / (DESC_FONT_SIZE * 0.6));
22518
- let totalRenderedLines = 0;
22519
- for (const line12 of node.description) {
22520
- if (line12.length <= charsPerLine) {
22521
- totalRenderedLines += 1;
22522
- } else {
22523
- const words = line12.split(/\s+/);
22524
- let current = "";
22525
- let lineCount = 0;
22526
- for (const word of words) {
22527
- const fitted = word.length > charsPerLine ? word.slice(0, charsPerLine) : word;
22528
- const test = current ? `${current} ${fitted}` : fitted;
22529
- if (test.length <= charsPerLine) {
22530
- current = test;
22531
- } else {
22532
- if (current) lineCount++;
22533
- current = fitted;
22534
- }
22535
- }
22536
- if (current) lineCount++;
22537
- totalRenderedLines += lineCount;
22538
- }
22539
- }
22540
- totalRenderedLines = Math.min(totalRenderedLines, MAX_DESC_LINES);
22541
- const descriptionHeight = totalRenderedLines * DESC_FONT_SIZE * DESC_LINE_HEIGHT;
22542
- const totalHeight = labelHeight + SEPARATOR_GAP5 + DESC_PADDING + descriptionHeight + DESC_PADDING;
22543
- return { width: w, height: Math.max(NODE_HEIGHT, totalHeight) };
22544
- }
22545
- function layoutBoxesAndLines(parsed, collapseInfo, layoutOptions) {
22546
- const hideDescriptions = layoutOptions?.hideDescriptions ?? false;
22547
- const g = new dagre4.graphlib.Graph({ compound: true, multigraph: true });
22548
- g.setGraph({
22549
- rankdir: parsed.direction,
22550
- nodesep: NODESEP,
22551
- ranksep: RANKSEP,
22552
- marginx: MARGIN3,
22553
- marginy: MARGIN3
22554
- });
22555
- g.setDefaultEdgeLabel(() => ({}));
22556
- const collapsedGroupLabels = /* @__PURE__ */ new Set();
22557
- if (collapseInfo) {
22558
- const missingGroups = /* @__PURE__ */ new Set();
22559
- for (const og of collapseInfo.originalGroups) {
22560
- if (!parsed.groups.some((g2) => g2.label === og.label)) {
22561
- missingGroups.add(og.label);
22562
- }
22563
- }
22564
- for (const label of missingGroups) {
22565
- const og = collapseInfo.originalGroups.find((g2) => g2.label === label);
22566
- const parentLabel = og?.parentGroup;
22567
- if (!parentLabel || !missingGroups.has(parentLabel)) {
22568
- collapsedGroupLabels.add(label);
22569
- }
22570
- }
22571
- }
22572
- for (const label of collapsedGroupLabels) {
22573
- const gid = `__group_${label}`;
22574
- g.setNode(gid, { label, width: NODE_WIDTH, height: NODE_HEIGHT });
22575
- }
22576
- for (const group of parsed.groups) {
22577
- const gid = `__group_${group.label}`;
22578
- g.setNode(gid, {
22579
- label: group.label,
22580
- paddingLeft: CONTAINER_PAD_X3,
22581
- paddingRight: CONTAINER_PAD_X3,
22582
- paddingTop: CONTAINER_PAD_TOP2,
22583
- paddingBottom: CONTAINER_PAD_BOTTOM3
22584
- });
22585
- }
22586
- const originalGroupByLabel = /* @__PURE__ */ new Map();
22587
- if (collapseInfo) {
22588
- for (const og of collapseInfo.originalGroups) {
22589
- originalGroupByLabel.set(og.label, og);
22590
- }
22591
- }
22592
- for (const label of collapsedGroupLabels) {
22593
- const og = originalGroupByLabel.get(label);
22594
- if (og?.parentGroup && !collapsedGroupLabels.has(og.parentGroup)) {
22595
- const gid = `__group_${label}`;
22596
- const parentGid = `__group_${og.parentGroup}`;
22597
- if (g.hasNode(parentGid)) {
22598
- g.setParent(gid, parentGid);
22599
- }
22600
- }
22601
- }
22602
- const nodeSizes = /* @__PURE__ */ new Map();
22603
- let maxDescHeight = 0;
22604
- for (const node of parsed.nodes) {
22605
- const size = hideDescriptions ? { width: NODE_WIDTH, height: NODE_HEIGHT } : computeNodeSize(node);
22606
- nodeSizes.set(node.label, size);
22607
- if (!hideDescriptions && node.description && node.description.length > 0) {
22608
- maxDescHeight = Math.max(maxDescHeight, size.height);
22609
- }
22610
- }
22611
- if (maxDescHeight > 0) {
22612
- for (const node of parsed.nodes) {
22613
- if (node.description && node.description.length > 0) {
22614
- const size = nodeSizes.get(node.label);
22615
- nodeSizes.set(node.label, { width: size.width, height: maxDescHeight });
22616
- }
22617
- }
22618
- }
22619
- for (const node of parsed.nodes) {
22620
- const size = nodeSizes.get(node.label);
22621
- g.setNode(node.label, {
22622
- label: node.label,
22623
- width: size.width,
22624
- height: size.height
22625
- });
22626
- }
22627
- for (const group of parsed.groups) {
22628
- if (group.parentGroup) {
22629
- const childGid = `__group_${group.label}`;
22630
- const parentGid = `__group_${group.parentGroup}`;
22631
- if (g.hasNode(childGid) && g.hasNode(parentGid)) {
22632
- g.setParent(childGid, parentGid);
22633
- }
22634
- }
22635
- }
22636
- const groupLabelSet = new Set(parsed.groups.map((gr) => gr.label));
22637
- for (const group of parsed.groups) {
22638
- const gid = `__group_${group.label}`;
22639
- for (const child of group.children) {
22640
- if (groupLabelSet.has(child)) continue;
22641
- if (g.hasNode(child)) {
22642
- g.setParent(child, gid);
22643
- }
22644
- }
22645
- }
22646
- const expandedGroupIds = /* @__PURE__ */ new Set();
22647
- for (const group of parsed.groups) {
22648
- expandedGroupIds.add(`__group_${group.label}`);
22649
- }
22650
- const groupFirstChild = /* @__PURE__ */ new Map();
22651
- for (const group of parsed.groups) {
22652
- const gid = `__group_${group.label}`;
22653
- const firstChild = group.children.find(
22654
- (c) => !groupLabelSet.has(c) && g.hasNode(c)
22655
- );
22656
- if (firstChild) {
22657
- groupFirstChild.set(gid, firstChild);
22658
- }
22659
- }
22660
- const deferredEdgeIndices = [];
22661
- let proxyIdx = 0;
22662
- for (let i = 0; i < parsed.edges.length; i++) {
22663
- const edge = parsed.edges[i];
22664
- const src = edge.source;
22665
- const tgt = edge.target;
22666
- if (!g.hasNode(src) || !g.hasNode(tgt)) continue;
22667
- if (expandedGroupIds.has(src) || expandedGroupIds.has(tgt)) {
22668
- deferredEdgeIndices.push(i);
22669
- const proxySrc = expandedGroupIds.has(src) ? groupFirstChild.get(src) : src;
22670
- const proxyTgt = expandedGroupIds.has(tgt) ? groupFirstChild.get(tgt) : tgt;
22671
- if (proxySrc && proxyTgt && proxySrc !== proxyTgt) {
22672
- g.setEdge(
22673
- proxySrc,
22674
- proxyTgt,
22675
- { label: "", minlen: 1 },
22676
- `proxy${proxyIdx++}`
22677
- );
22678
- }
22679
- continue;
22680
- }
22681
- g.setEdge(src, tgt, { label: edge.label ?? "", minlen: 1 }, `e${i}`);
22682
- }
22683
- dagre4.layout(g);
22684
- const layoutNodes = [];
22685
- for (const node of parsed.nodes) {
22686
- const dagreNode = g.node(node.label);
22687
- if (!dagreNode) continue;
22688
- layoutNodes.push({
22689
- label: node.label,
22690
- x: dagreNode.x,
22691
- y: dagreNode.y,
22692
- width: dagreNode.width,
22693
- height: dagreNode.height
22694
- });
22695
- }
22696
- const layoutGroups = [];
22697
- for (const group of parsed.groups) {
22698
- const gid = `__group_${group.label}`;
22699
- const dagreNode = g.node(gid);
22700
- if (!dagreNode) continue;
22701
- layoutGroups.push({
22702
- label: group.label,
22703
- lineNumber: group.lineNumber,
22704
- x: dagreNode.x,
22705
- y: dagreNode.y,
22706
- width: dagreNode.width,
22707
- height: dagreNode.height,
22708
- collapsed: false
22709
- });
22710
- }
22711
- for (const label of collapsedGroupLabels) {
22712
- const gid = `__group_${label}`;
22713
- const dagreNode = g.node(gid);
22714
- if (!dagreNode) continue;
22715
- const og = collapseInfo?.originalGroups.find((g2) => g2.label === label);
22716
- layoutGroups.push({
22717
- label,
22718
- lineNumber: og?.lineNumber ?? 0,
22719
- x: dagreNode.x,
22720
- y: dagreNode.y,
22721
- width: dagreNode.width,
22722
- height: dagreNode.height,
22723
- collapsed: true,
22724
- childCount: collapseInfo?.collapsedChildCounts.get(label) ?? 0
22725
- });
22726
- }
22727
- const groupAlignShifts = /* @__PURE__ */ new Map();
22728
- {
22729
- const groupEdges = [];
22730
- for (const edge of parsed.edges) {
22731
- if (edge.source.startsWith("__group_") && edge.target.startsWith("__group_")) {
22732
- groupEdges.push(edge);
22733
- }
22734
- }
22735
- if (groupEdges.length > 0) {
22736
- const groupParent = /* @__PURE__ */ new Map();
22737
- const find = (x) => {
22738
- while (groupParent.has(x) && groupParent.get(x) !== x) {
22739
- groupParent.set(x, groupParent.get(groupParent.get(x)));
22740
- x = groupParent.get(x);
22741
- }
22742
- return x;
22743
- };
22744
- const union = (a, b) => {
22745
- const ra = find(a), rb = find(b);
22746
- if (ra !== rb) groupParent.set(ra, rb);
22747
- };
22748
- for (const edge of groupEdges) {
22749
- if (!groupParent.has(edge.source))
22750
- groupParent.set(edge.source, edge.source);
22751
- if (!groupParent.has(edge.target))
22752
- groupParent.set(edge.target, edge.target);
22753
- union(edge.source, edge.target);
22754
- }
22755
- const components = /* @__PURE__ */ new Map();
22756
- for (const lg of layoutGroups) {
22757
- const gid = `__group_${lg.label}`;
22758
- if (!groupParent.has(gid)) continue;
22759
- const root = find(gid);
22760
- if (!components.has(root)) components.set(root, []);
22761
- components.get(root).push(lg);
22762
- }
22763
- const axis = parsed.direction === "TB" ? "x" : "y";
22764
- for (const groups of components.values()) {
22765
- if (groups.length < 2) continue;
22766
- const dim = axis === "x" ? "width" : "height";
22767
- let widest = groups[0];
22768
- for (const g2 of groups) {
22769
- if (g2[dim] > widest[dim]) widest = g2;
22770
- }
22771
- const targetCenter = widest[axis];
22772
- for (const grp of groups) {
22773
- const dx = targetCenter - grp[axis];
22774
- if (dx === 0) continue;
22775
- grp[axis] += dx;
22776
- groupAlignShifts.set(`__group_${grp.label}`, dx);
22777
- const parsedGroup = parsed.groups.find(
22778
- (pg) => pg.label === grp.label
22779
- );
22780
- if (parsedGroup) {
22781
- for (const childLabel of parsedGroup.children) {
22782
- const childNode = layoutNodes.find((n) => n.label === childLabel);
22783
- if (childNode) childNode[axis] += dx;
22784
- }
22785
- }
22786
- }
22787
- }
22788
- }
22789
- }
22790
- const edgeYOffsets = new Array(parsed.edges.length).fill(0);
22791
- const edgeParallelCounts = new Array(parsed.edges.length).fill(1);
22792
- const parallelGroups = /* @__PURE__ */ new Map();
22793
- for (let i = 0; i < parsed.edges.length; i++) {
22794
- const edge = parsed.edges[i];
22795
- const [a, b] = edge.source < edge.target ? [edge.source, edge.target] : [edge.target, edge.source];
22796
- const key = `${a}\0${b}`;
22797
- if (!parallelGroups.has(key)) parallelGroups.set(key, []);
22798
- parallelGroups.get(key).push(i);
22799
- }
22800
- for (const group of parallelGroups.values()) {
22801
- const capped = group.slice(0, MAX_PARALLEL_EDGES);
22802
- for (const idx of group.slice(MAX_PARALLEL_EDGES)) {
22803
- edgeParallelCounts[idx] = 0;
22804
- }
22805
- if (capped.length < 2) continue;
22806
- const effectiveSpacing = PARALLEL_SPACING;
22807
- for (let j = 0; j < capped.length; j++) {
22808
- edgeYOffsets[capped[j]] = (j - (capped.length - 1) / 2) * effectiveSpacing;
22809
- edgeParallelCounts[capped[j]] = capped.length;
22810
- }
22811
- }
22812
- const deferredSet = new Set(deferredEdgeIndices);
22813
- const layoutEdges = [];
22814
- for (let i = 0; i < parsed.edges.length; i++) {
22815
- const edge = parsed.edges[i];
22816
- if (edgeParallelCounts[i] === 0) continue;
22817
- let points;
22818
- if (deferredSet.has(i)) {
22819
- const srcLayout = layoutGroups.find(
22820
- (lg) => `__group_${lg.label}` === edge.source
22821
- );
22822
- const tgtLayout = layoutGroups.find(
22823
- (lg) => `__group_${lg.label}` === edge.target
22824
- );
22825
- if (!srcLayout || !tgtLayout) {
22826
- const srcNode = g.node(edge.source);
22827
- const tgtNode = g.node(edge.target);
22828
- if (!srcNode || !tgtNode) continue;
22829
- const srcPt = clipToRectBorder2(
22830
- srcNode.x,
22831
- srcNode.y,
22832
- srcNode.width,
22833
- srcNode.height,
22834
- tgtNode.x,
22835
- tgtNode.y
22836
- );
22837
- const tgtPt = clipToRectBorder2(
22838
- tgtNode.x,
22839
- tgtNode.y,
22840
- tgtNode.width,
22841
- tgtNode.height,
22842
- srcNode.x,
22843
- srcNode.y
22844
- );
22845
- const midX = (srcPt.x + tgtPt.x) / 2;
22846
- const midY = (srcPt.y + tgtPt.y) / 2;
22847
- points = [srcPt, { x: midX, y: midY }, tgtPt];
22848
- } else if (parsed.direction === "TB") {
22849
- const cx = (srcLayout.x + tgtLayout.x) / 2;
22850
- const srcPt = { x: cx, y: srcLayout.y + srcLayout.height / 2 };
22851
- const tgtPt = { x: cx, y: tgtLayout.y - tgtLayout.height / 2 };
22852
- const midY = (srcPt.y + tgtPt.y) / 2;
22853
- points = [srcPt, { x: cx, y: midY }, tgtPt];
22854
- } else {
22855
- const cy = (srcLayout.y + tgtLayout.y) / 2;
22856
- const srcPt = { x: srcLayout.x + srcLayout.width / 2, y: cy };
22857
- const tgtPt = { x: tgtLayout.x - tgtLayout.width / 2, y: cy };
22858
- const midX = (srcPt.x + tgtPt.x) / 2;
22859
- points = [srcPt, { x: midX, y: cy }, tgtPt];
22860
- }
22861
- } else {
22862
- const dagreEdge = g.edge(edge.source, edge.target, `e${i}`);
22863
- points = dagreEdge?.points ?? [];
22864
- const srcShift = groupAlignShifts.get(edge.source) ?? 0;
22865
- const tgtShift = groupAlignShifts.get(edge.target) ?? 0;
22866
- if (srcShift !== 0 || tgtShift !== 0) {
22867
- const avgShift = (srcShift + tgtShift) / 2;
22868
- const prop = parsed.direction === "TB" ? "x" : "y";
22869
- points = points.map((p) => ({ ...p, [prop]: p[prop] + avgShift }));
22870
- }
22871
- }
22872
- let labelX;
22873
- let labelY;
22874
- if (edge.label && points.length >= 2) {
22875
- const mid = Math.floor(points.length / 2);
22876
- labelX = points[mid].x;
22877
- labelY = points[mid].y - 10;
22878
- }
22879
- layoutEdges.push({
22880
- source: edge.source,
22881
- target: edge.target,
22882
- label: edge.label,
22883
- bidirectional: edge.bidirectional,
22884
- lineNumber: edge.lineNumber,
22885
- points,
22886
- labelX,
22887
- labelY,
22888
- yOffset: edgeYOffsets[i],
22889
- parallelCount: edgeParallelCounts[i],
22890
- metadata: edge.metadata,
22891
- deferred: deferredSet.has(i) || void 0
22892
- });
22893
- }
22894
- let maxX = 0;
22895
- let maxY = 0;
22896
- for (const node of layoutNodes) {
22897
- maxX = Math.max(maxX, node.x + node.width / 2);
22898
- maxY = Math.max(maxY, node.y + node.height / 2);
22899
- }
22900
- for (const group of layoutGroups) {
22901
- maxX = Math.max(maxX, group.x + group.width / 2);
22902
- maxY = Math.max(maxY, group.y + group.height / 2);
22903
- }
22904
- return {
22905
- nodes: layoutNodes,
22906
- edges: layoutEdges,
22907
- groups: layoutGroups,
22908
- width: maxX + MARGIN3,
22909
- height: maxY + MARGIN3
22910
- };
22911
- }
22912
- 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;
22913
- var init_layout5 = __esm({
22914
- "src/boxes-and-lines/layout.ts"() {
22915
- "use strict";
22916
- NODESEP = 60;
22917
- RANKSEP = 100;
22918
- MARGIN3 = 40;
22919
- CONTAINER_PAD_X3 = 30;
22920
- CONTAINER_PAD_TOP2 = 40;
22921
- CONTAINER_PAD_BOTTOM3 = 24;
22922
- MAX_PARALLEL_EDGES = 5;
22923
- PARALLEL_SPACING = 22;
22924
- PHI = 1.618;
22925
- NODE_HEIGHT = 60;
22926
- NODE_WIDTH = Math.round(NODE_HEIGHT * PHI);
22927
- DESC_NODE_WIDTH = 140;
22928
- DESC_FONT_SIZE = 10;
22929
- DESC_LINE_HEIGHT = 1.4;
22930
- DESC_PADDING = 8;
22931
- SEPARATOR_GAP5 = 4;
22932
- MAX_DESC_LINES = 6;
22933
- MAX_LABEL_LINES = 3;
22934
- LABEL_LINE_HEIGHT = 1.3;
22935
- LABEL_PAD = 12;
22936
- }
22937
- });
22938
-
22939
22439
  // src/utils/wrapped-desc.ts
22940
22440
  function wrapDescriptionLines(lines, charsPerLine, lengthFn = (s) => s.length) {
22941
22441
  const result = [];
@@ -22987,7 +22487,7 @@ __export(renderer_exports6, {
22987
22487
  });
22988
22488
  import * as d3Selection6 from "d3-selection";
22989
22489
  import * as d3Shape4 from "d3-shape";
22990
- function splitCamelCase2(word) {
22490
+ function splitCamelCase(word) {
22991
22491
  const parts = [];
22992
22492
  let start = 0;
22993
22493
  for (let i = 1; i < word.length; i++) {
@@ -23010,7 +22510,7 @@ function fitLabelToHeader(label, nodeWidth2, maxLines) {
23010
22510
  const words = [];
23011
22511
  for (const part of rawParts) {
23012
22512
  if (!part || /^\s+$/.test(part) || part === "-") continue;
23013
- words.push(...splitCamelCase2(part));
22513
+ words.push(...splitCamelCase(part));
23014
22514
  }
23015
22515
  for (let fontSize = NODE_FONT_SIZE; fontSize >= MIN_NODE_FONT_SIZE; fontSize--) {
23016
22516
  const charWidth2 = fontSize * CHAR_WIDTH_RATIO2;
@@ -23386,12 +22886,12 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
23386
22886
  }
23387
22887
  const sepY = -ln.height / 2 + headerH;
23388
22888
  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);
23389
- const descStartY = sepY + 4 + DESC_FONT_SIZE2;
22889
+ const descStartY = sepY + 4 + DESC_FONT_SIZE;
23390
22890
  const maxTextWidth = ln.width - NODE_TEXT_PADDING * 2;
23391
22891
  const charsPerLine = Math.floor(
23392
- maxTextWidth / (DESC_FONT_SIZE2 * CHAR_WIDTH_RATIO2)
22892
+ maxTextWidth / (DESC_FONT_SIZE * CHAR_WIDTH_RATIO2)
23393
22893
  );
23394
- const descLineH = DESC_FONT_SIZE2 * DESC_LINE_HEIGHT2;
22894
+ const descLineH = DESC_FONT_SIZE * DESC_LINE_HEIGHT;
23395
22895
  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;
23396
22896
  const normalizedLines = [];
23397
22897
  for (const descLine of desc) {
@@ -23407,8 +22907,8 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
23407
22907
  charsPerLine,
23408
22908
  displayLen
23409
22909
  );
23410
- const truncated = wrappedLinesShared.length > MAX_DESC_LINES2;
23411
- const visibleLines = truncated ? wrappedLinesShared.slice(0, MAX_DESC_LINES2) : wrappedLinesShared;
22910
+ const truncated = wrappedLinesShared.length > MAX_DESC_LINES;
22911
+ const visibleLines = truncated ? wrappedLinesShared.slice(0, MAX_DESC_LINES) : wrappedLinesShared;
23412
22912
  const BULLET_GLYPH_X = -ln.width / 2 + 6;
23413
22913
  const BULLET_BODY_X = BULLET_GLYPH_X + 10;
23414
22914
  for (let li = 0; li < visibleLines.length; li++) {
@@ -23419,11 +22919,11 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
23419
22919
  }
23420
22920
  const y2 = descStartY + li * descLineH;
23421
22921
  if (line12.kind === "bullet-first") {
23422
- 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");
22922
+ 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");
23423
22923
  }
23424
22924
  const isBullet = line12.kind === "bullet-first" || line12.kind === "bullet-cont";
23425
- 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);
23426
- renderInlineText(textEl, lineText, palette, DESC_FONT_SIZE2);
22925
+ 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);
22926
+ renderInlineText(textEl, lineText, palette, DESC_FONT_SIZE);
23427
22927
  }
23428
22928
  if (truncated) {
23429
22929
  const fullText = desc.join(" ");
@@ -23501,7 +23001,7 @@ function renderBoxesAndLinesForExport(container, parsed, layout, palette, isDark
23501
23001
  hiddenTagValues: options?.hiddenTagValues
23502
23002
  });
23503
23003
  }
23504
- 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;
23004
+ 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;
23505
23005
  var init_renderer6 = __esm({
23506
23006
  "src/boxes-and-lines/renderer.ts"() {
23507
23007
  "use strict";
@@ -23523,9 +23023,9 @@ var init_renderer6 = __esm({
23523
23023
  COLLAPSE_BAR_HEIGHT3 = 4;
23524
23024
  ARROWHEAD_W2 = 5;
23525
23025
  ARROWHEAD_H2 = 4;
23526
- DESC_FONT_SIZE2 = 10;
23527
- DESC_LINE_HEIGHT2 = 1.4;
23528
- MAX_DESC_LINES2 = 6;
23026
+ DESC_FONT_SIZE = 10;
23027
+ DESC_LINE_HEIGHT = 1.4;
23028
+ MAX_DESC_LINES = 6;
23529
23029
  CHAR_WIDTH_RATIO2 = 0.6;
23530
23030
  NODE_TEXT_PADDING = 12;
23531
23031
  GROUP_RX = 8;
@@ -23536,6 +23036,523 @@ var init_renderer6 = __esm({
23536
23036
  }
23537
23037
  });
23538
23038
 
23039
+ // src/boxes-and-lines/layout.ts
23040
+ var layout_exports5 = {};
23041
+ __export(layout_exports5, {
23042
+ layoutBoxesAndLines: () => layoutBoxesAndLines
23043
+ });
23044
+ import ELK from "elkjs/lib/elk.bundled.js";
23045
+ function splitCamelCase2(word) {
23046
+ const parts = [];
23047
+ let start = 0;
23048
+ for (let i = 1; i < word.length; i++) {
23049
+ const prev = word[i - 1];
23050
+ const curr = word[i];
23051
+ const next = i + 1 < word.length ? word[i + 1] : "";
23052
+ const lowerToUpper = prev >= "a" && prev <= "z" && curr >= "A" && curr <= "Z";
23053
+ const upperRunEnd = prev >= "A" && prev <= "Z" && curr >= "A" && curr <= "Z" && next >= "a" && next <= "z";
23054
+ if (lowerToUpper || upperRunEnd) {
23055
+ parts.push(word.slice(start, i));
23056
+ start = i;
23057
+ }
23058
+ }
23059
+ parts.push(word.slice(start));
23060
+ return parts.length > 1 ? parts : [word];
23061
+ }
23062
+ function estimateLabelLines(label, nodeWidth2 = NODE_WIDTH) {
23063
+ const rawParts = label.split(/[\s-]+/);
23064
+ const words = [];
23065
+ for (const part of rawParts) {
23066
+ if (!part) continue;
23067
+ words.push(...splitCamelCase2(part));
23068
+ }
23069
+ for (let fontSize = 13; fontSize >= 9; fontSize--) {
23070
+ const charWidth = fontSize * 0.6;
23071
+ const maxChars = Math.floor((nodeWidth2 - 24) / charWidth);
23072
+ if (maxChars < 2) continue;
23073
+ let lines = 1;
23074
+ let current = "";
23075
+ for (const word of words) {
23076
+ const test = current ? `${current} ${word}` : word;
23077
+ if (test.length <= maxChars) {
23078
+ current = test;
23079
+ } else {
23080
+ lines++;
23081
+ current = word;
23082
+ }
23083
+ }
23084
+ if (lines <= MAX_LABEL_LINES) return Math.min(lines, MAX_LABEL_LINES);
23085
+ }
23086
+ return MAX_LABEL_LINES;
23087
+ }
23088
+ function computeNodeSize(node) {
23089
+ if (!node.description || node.description.length === 0) {
23090
+ return { width: NODE_WIDTH, height: NODE_HEIGHT };
23091
+ }
23092
+ const w = DESC_NODE_WIDTH;
23093
+ const labelLines = estimateLabelLines(node.label, w);
23094
+ const labelHeight = labelLines * 13 * LABEL_LINE_HEIGHT + LABEL_PAD;
23095
+ const charsPerLine = Math.floor((w - 24) / (DESC_FONT_SIZE2 * 0.6));
23096
+ let totalRenderedLines = 0;
23097
+ for (const line12 of node.description) {
23098
+ if (line12.length <= charsPerLine) {
23099
+ totalRenderedLines += 1;
23100
+ } else {
23101
+ const words = line12.split(/\s+/);
23102
+ let current = "";
23103
+ let lineCount = 0;
23104
+ for (const word of words) {
23105
+ const fitted = word.length > charsPerLine ? word.slice(0, charsPerLine) : word;
23106
+ const test = current ? `${current} ${fitted}` : fitted;
23107
+ if (test.length <= charsPerLine) {
23108
+ current = test;
23109
+ } else {
23110
+ if (current) lineCount++;
23111
+ current = fitted;
23112
+ }
23113
+ }
23114
+ if (current) lineCount++;
23115
+ totalRenderedLines += lineCount;
23116
+ }
23117
+ }
23118
+ totalRenderedLines = Math.min(totalRenderedLines, MAX_DESC_LINES2);
23119
+ const descriptionHeight = totalRenderedLines * DESC_FONT_SIZE2 * DESC_LINE_HEIGHT2;
23120
+ const totalHeight = labelHeight + SEPARATOR_GAP5 + DESC_PADDING + descriptionHeight + DESC_PADDING;
23121
+ return { width: w, height: Math.max(NODE_HEIGHT, totalHeight) };
23122
+ }
23123
+ function getElk() {
23124
+ if (!elkInstance) elkInstance = new ELK();
23125
+ return elkInstance;
23126
+ }
23127
+ function baseOptions() {
23128
+ return {
23129
+ "elk.algorithm": "layered",
23130
+ // INCLUDE_CHILDREN lets ELK route edges across container boundaries.
23131
+ "elk.hierarchyHandling": "INCLUDE_CHILDREN",
23132
+ "elk.edgeRouting": "ORTHOGONAL",
23133
+ "elk.layered.unnecessaryBendpoints": "true",
23134
+ // Let edges leave from top/bottom of nodes (not just the flow-direction
23135
+ // sides) when it reduces crossings.
23136
+ "elk.layered.allowNonFlowPortsToSwitchSides": "true"
23137
+ };
23138
+ }
23139
+ function bkBaseline() {
23140
+ return {
23141
+ ...baseOptions(),
23142
+ "elk.layered.nodePlacement.strategy": "BRANDES_KOEPF",
23143
+ "elk.layered.nodePlacement.bk.fixedAlignment": "BALANCED",
23144
+ "elk.layered.nodePlacement.bk.edgeStraightening": "IMPROVE_STRAIGHTNESS",
23145
+ "elk.layered.compaction.connectedComponents": "true",
23146
+ "elk.layered.spacing.nodeNodeBetweenLayers": "90",
23147
+ "elk.spacing.nodeNode": "55",
23148
+ "elk.spacing.edgeNode": "55",
23149
+ "elk.spacing.edgeEdge": "18"
23150
+ };
23151
+ }
23152
+ function getVariants() {
23153
+ const bk = bkBaseline();
23154
+ return [
23155
+ {
23156
+ name: "bk-baseline",
23157
+ options: {
23158
+ ...bk,
23159
+ "elk.layered.crossingMinimization.greedySwitch.type": "ONE_SIDED"
23160
+ }
23161
+ },
23162
+ {
23163
+ name: "bk-aggressive",
23164
+ options: {
23165
+ ...bk,
23166
+ "elk.layered.crossingMinimization.greedySwitch.type": "TWO_SIDED",
23167
+ "elk.layered.thoroughness": "50"
23168
+ }
23169
+ },
23170
+ {
23171
+ name: "bk-wide",
23172
+ options: {
23173
+ ...bk,
23174
+ "elk.layered.crossingMinimization.greedySwitch.type": "TWO_SIDED",
23175
+ "elk.layered.thoroughness": "50",
23176
+ "elk.spacing.nodeNode": "70",
23177
+ "elk.spacing.edgeNode": "75",
23178
+ "elk.spacing.edgeEdge": "22",
23179
+ "elk.layered.spacing.nodeNodeBetweenLayers": "120"
23180
+ }
23181
+ },
23182
+ {
23183
+ name: "longest-path",
23184
+ options: {
23185
+ ...bk,
23186
+ "elk.layered.layering.strategy": "LONGEST_PATH",
23187
+ "elk.layered.crossingMinimization.greedySwitch.type": "TWO_SIDED",
23188
+ "elk.layered.thoroughness": "50"
23189
+ }
23190
+ },
23191
+ {
23192
+ name: "bounded-width",
23193
+ options: {
23194
+ ...bk,
23195
+ "elk.layered.layering.strategy": "COFFMAN_GRAHAM",
23196
+ "elk.layered.layering.coffmanGraham.layerBound": "3",
23197
+ "elk.layered.crossingMinimization.greedySwitch.type": "TWO_SIDED",
23198
+ "elk.layered.thoroughness": "50"
23199
+ }
23200
+ }
23201
+ ];
23202
+ }
23203
+ function countCrossings(edges) {
23204
+ let count = 0;
23205
+ for (let i = 0; i < edges.length; i++) {
23206
+ const a = edges[i].points;
23207
+ if (a.length < 2) continue;
23208
+ for (let j = i + 1; j < edges.length; j++) {
23209
+ const b = edges[j].points;
23210
+ if (b.length < 2) continue;
23211
+ if (edges[i].source === edges[j].source) continue;
23212
+ if (edges[i].source === edges[j].target) continue;
23213
+ if (edges[i].target === edges[j].source) continue;
23214
+ if (edges[i].target === edges[j].target) continue;
23215
+ for (let ai = 0; ai < a.length - 1; ai++) {
23216
+ for (let bi = 0; bi < b.length - 1; bi++) {
23217
+ if (segmentsCross(a[ai], a[ai + 1], b[bi], b[bi + 1])) count++;
23218
+ }
23219
+ }
23220
+ }
23221
+ }
23222
+ return count;
23223
+ }
23224
+ function segmentsCross(p1, p2, p3, p4) {
23225
+ const d1x = p2.x - p1.x;
23226
+ const d1y = p2.y - p1.y;
23227
+ const d2x = p4.x - p3.x;
23228
+ const d2y = p4.y - p3.y;
23229
+ const denom = d1x * d2y - d1y * d2x;
23230
+ if (Math.abs(denom) < 1e-9) return false;
23231
+ const t = ((p3.x - p1.x) * d2y - (p3.y - p1.y) * d2x) / denom;
23232
+ const s = ((p3.x - p1.x) * d1y - (p3.y - p1.y) * d1x) / denom;
23233
+ const EPS = 1e-3;
23234
+ return t > EPS && t < 1 - EPS && s > EPS && s < 1 - EPS;
23235
+ }
23236
+ function countTotalBends(edges) {
23237
+ let bends = 0;
23238
+ for (const e of edges) bends += Math.max(0, e.points.length - 2);
23239
+ return bends;
23240
+ }
23241
+ function scoreLayout(layout) {
23242
+ return {
23243
+ crossings: countCrossings(layout.edges),
23244
+ bends: countTotalBends(layout.edges),
23245
+ area: layout.width * layout.height
23246
+ };
23247
+ }
23248
+ function cmpScore(a, b) {
23249
+ const aBucket = a.crossings <= CROSSINGS_FORGIVENESS ? 0 : a.crossings;
23250
+ const bBucket = b.crossings <= CROSSINGS_FORGIVENESS ? 0 : b.crossings;
23251
+ if (aBucket !== bBucket) return aBucket - bBucket;
23252
+ if (a.area !== b.area) return a.area - b.area;
23253
+ return a.bends - b.bends;
23254
+ }
23255
+ async function layoutBoxesAndLines(parsed, collapseInfo, layoutOptions) {
23256
+ const hideDescriptions = layoutOptions?.hideDescriptions ?? false;
23257
+ const direction = parsed.direction === "TB" ? "DOWN" : "RIGHT";
23258
+ const collapsedGroupLabels = /* @__PURE__ */ new Set();
23259
+ if (collapseInfo) {
23260
+ const missingGroups = /* @__PURE__ */ new Set();
23261
+ for (const og of collapseInfo.originalGroups) {
23262
+ if (!parsed.groups.some((g) => g.label === og.label)) {
23263
+ missingGroups.add(og.label);
23264
+ }
23265
+ }
23266
+ for (const label of missingGroups) {
23267
+ const og = collapseInfo.originalGroups.find((g) => g.label === label);
23268
+ const parentLabel = og?.parentGroup;
23269
+ if (!parentLabel || !missingGroups.has(parentLabel)) {
23270
+ collapsedGroupLabels.add(label);
23271
+ }
23272
+ }
23273
+ }
23274
+ const nodeSizes = /* @__PURE__ */ new Map();
23275
+ let maxDescHeight = 0;
23276
+ for (const node of parsed.nodes) {
23277
+ const size = hideDescriptions ? { width: NODE_WIDTH, height: NODE_HEIGHT } : computeNodeSize(node);
23278
+ nodeSizes.set(node.label, size);
23279
+ if (!hideDescriptions && node.description && node.description.length > 0) {
23280
+ maxDescHeight = Math.max(maxDescHeight, size.height);
23281
+ }
23282
+ }
23283
+ if (maxDescHeight > 0) {
23284
+ for (const node of parsed.nodes) {
23285
+ if (node.description && node.description.length > 0) {
23286
+ const size = nodeSizes.get(node.label);
23287
+ nodeSizes.set(node.label, { width: size.width, height: maxDescHeight });
23288
+ }
23289
+ }
23290
+ }
23291
+ const expandedGroupSet = new Set(parsed.groups.map((g) => g.label));
23292
+ const gid = (label) => `__group_${label}`;
23293
+ function buildGraph() {
23294
+ const nodeById = /* @__PURE__ */ new Map();
23295
+ const parentOf = /* @__PURE__ */ new Map();
23296
+ for (const node of parsed.nodes) {
23297
+ const size = nodeSizes.get(node.label);
23298
+ nodeById.set(node.label, {
23299
+ id: node.label,
23300
+ width: size.width,
23301
+ height: size.height,
23302
+ labels: [{ text: node.label }]
23303
+ });
23304
+ }
23305
+ for (const group of parsed.groups) {
23306
+ nodeById.set(gid(group.label), {
23307
+ id: gid(group.label),
23308
+ labels: [{ text: group.label }],
23309
+ layoutOptions: {
23310
+ "elk.padding": `[top=${CONTAINER_PAD_TOP2},left=${CONTAINER_PAD_X3},bottom=${CONTAINER_PAD_BOTTOM3},right=${CONTAINER_PAD_X3}]`,
23311
+ // Suggest square-ish containers — has limited effect with
23312
+ // INCLUDE_CHILDREN but doesn't hurt.
23313
+ "elk.aspectRatio": "1.4"
23314
+ },
23315
+ children: [],
23316
+ edges: []
23317
+ });
23318
+ }
23319
+ for (const label of collapsedGroupLabels) {
23320
+ nodeById.set(gid(label), {
23321
+ id: gid(label),
23322
+ width: NODE_WIDTH,
23323
+ height: NODE_HEIGHT,
23324
+ labels: [{ text: label }]
23325
+ });
23326
+ }
23327
+ for (const group of parsed.groups) {
23328
+ if (group.parentGroup && nodeById.has(gid(group.parentGroup))) {
23329
+ parentOf.set(gid(group.label), gid(group.parentGroup));
23330
+ }
23331
+ }
23332
+ if (collapseInfo) {
23333
+ for (const label of collapsedGroupLabels) {
23334
+ const og = collapseInfo.originalGroups.find((g) => g.label === label);
23335
+ if (og?.parentGroup && !collapsedGroupLabels.has(og.parentGroup) && nodeById.has(gid(og.parentGroup))) {
23336
+ parentOf.set(gid(label), gid(og.parentGroup));
23337
+ }
23338
+ }
23339
+ }
23340
+ for (const group of parsed.groups) {
23341
+ for (const child of group.children) {
23342
+ if (expandedGroupSet.has(child)) continue;
23343
+ if (nodeById.has(child)) {
23344
+ parentOf.set(child, gid(group.label));
23345
+ }
23346
+ }
23347
+ }
23348
+ const roots = [];
23349
+ for (const [id, node] of nodeById) {
23350
+ const parentId = parentOf.get(id);
23351
+ if (parentId) {
23352
+ const parent = nodeById.get(parentId);
23353
+ parent.children = parent.children ?? [];
23354
+ parent.children.push(node);
23355
+ } else {
23356
+ roots.push(node);
23357
+ }
23358
+ }
23359
+ const rootEdges = [];
23360
+ for (let i = 0; i < parsed.edges.length; i++) {
23361
+ const edge = parsed.edges[i];
23362
+ if (!nodeById.has(edge.source) || !nodeById.has(edge.target)) continue;
23363
+ rootEdges.push({
23364
+ id: `e${i}`,
23365
+ sources: [edge.source],
23366
+ targets: [edge.target]
23367
+ });
23368
+ }
23369
+ return { roots, rootEdges };
23370
+ }
23371
+ async function runVariant(variant) {
23372
+ const { roots, rootEdges } = buildGraph();
23373
+ const elkRoot = {
23374
+ id: "root",
23375
+ layoutOptions: {
23376
+ ...variant.options,
23377
+ "elk.direction": direction,
23378
+ "elk.padding": `[top=${MARGIN3},left=${MARGIN3},bottom=${MARGIN3},right=${MARGIN3}]`
23379
+ },
23380
+ children: roots,
23381
+ edges: rootEdges
23382
+ };
23383
+ const result = await getElk().layout(elkRoot);
23384
+ return extractLayout(result);
23385
+ }
23386
+ function extractLayout(result) {
23387
+ const layoutNodes = [];
23388
+ const layoutGroups = [];
23389
+ const allEdges = [];
23390
+ const containerAbs = /* @__PURE__ */ new Map();
23391
+ function walk(n, offsetX, offsetY, isRoot) {
23392
+ const nx = (n.x ?? 0) + offsetX;
23393
+ const ny = (n.y ?? 0) + offsetY;
23394
+ const nw = n.width ?? 0;
23395
+ const nh = n.height ?? 0;
23396
+ if (isRoot) {
23397
+ containerAbs.set("root", { x: nx, y: ny });
23398
+ } else {
23399
+ const isGroup = n.id.startsWith("__group_");
23400
+ if (isGroup) {
23401
+ const label = n.id.slice("__group_".length);
23402
+ const collapsed = collapsedGroupLabels.has(label);
23403
+ const og = collapseInfo?.originalGroups.find(
23404
+ (g) => g.label === label
23405
+ );
23406
+ const pg = parsed.groups.find((g) => g.label === label);
23407
+ layoutGroups.push({
23408
+ label,
23409
+ lineNumber: pg?.lineNumber ?? og?.lineNumber ?? 0,
23410
+ x: nx + nw / 2,
23411
+ y: ny + nh / 2,
23412
+ width: nw,
23413
+ height: nh,
23414
+ collapsed,
23415
+ childCount: collapsed ? collapseInfo?.collapsedChildCounts.get(label) ?? 0 : void 0
23416
+ });
23417
+ if (!collapsed) containerAbs.set(n.id, { x: nx, y: ny });
23418
+ } else {
23419
+ layoutNodes.push({
23420
+ label: n.id,
23421
+ x: nx + nw / 2,
23422
+ y: ny + nh / 2,
23423
+ width: nw,
23424
+ height: nh
23425
+ });
23426
+ }
23427
+ }
23428
+ if (n.edges) for (const e of n.edges) allEdges.push(e);
23429
+ if (n.children) for (const c of n.children) walk(c, nx, ny, false);
23430
+ }
23431
+ walk(result, 0, 0, true);
23432
+ const edgeYOffsets = new Array(parsed.edges.length).fill(0);
23433
+ const edgeParallelCounts = new Array(parsed.edges.length).fill(1);
23434
+ const parallelGroups = /* @__PURE__ */ new Map();
23435
+ for (let i = 0; i < parsed.edges.length; i++) {
23436
+ const edge = parsed.edges[i];
23437
+ const [a, b] = edge.source < edge.target ? [edge.source, edge.target] : [edge.target, edge.source];
23438
+ const key = `${a}\0${b}`;
23439
+ if (!parallelGroups.has(key)) parallelGroups.set(key, []);
23440
+ parallelGroups.get(key).push(i);
23441
+ }
23442
+ for (const group of parallelGroups.values()) {
23443
+ const capped = group.slice(0, MAX_PARALLEL_EDGES);
23444
+ for (const idx of group.slice(MAX_PARALLEL_EDGES)) {
23445
+ edgeParallelCounts[idx] = 0;
23446
+ }
23447
+ if (capped.length < 2) continue;
23448
+ for (let j = 0; j < capped.length; j++) {
23449
+ edgeYOffsets[capped[j]] = (j - (capped.length - 1) / 2) * PARALLEL_SPACING;
23450
+ edgeParallelCounts[capped[j]] = capped.length;
23451
+ }
23452
+ }
23453
+ const edgeById = /* @__PURE__ */ new Map();
23454
+ for (const e of allEdges) edgeById.set(e.id, e);
23455
+ const layoutEdges = [];
23456
+ for (let i = 0; i < parsed.edges.length; i++) {
23457
+ const edge = parsed.edges[i];
23458
+ if (edgeParallelCounts[i] === 0) continue;
23459
+ const elkEdge = edgeById.get(`e${i}`);
23460
+ if (!elkEdge || !elkEdge.sections || elkEdge.sections.length === 0)
23461
+ continue;
23462
+ const container = elkEdge.container ?? "root";
23463
+ const off = containerAbs.get(container) ?? { x: 0, y: 0 };
23464
+ const s = elkEdge.sections[0];
23465
+ const points = [
23466
+ { x: s.startPoint.x + off.x, y: s.startPoint.y + off.y },
23467
+ ...(s.bendPoints ?? []).map((p) => ({
23468
+ x: p.x + off.x,
23469
+ y: p.y + off.y
23470
+ })),
23471
+ { x: s.endPoint.x + off.x, y: s.endPoint.y + off.y }
23472
+ ];
23473
+ let labelX;
23474
+ let labelY;
23475
+ if (edge.label && points.length >= 2) {
23476
+ const mid = Math.floor(points.length / 2);
23477
+ labelX = points[mid].x;
23478
+ labelY = points[mid].y - 10;
23479
+ }
23480
+ layoutEdges.push({
23481
+ source: edge.source,
23482
+ target: edge.target,
23483
+ label: edge.label,
23484
+ bidirectional: edge.bidirectional,
23485
+ lineNumber: edge.lineNumber,
23486
+ points,
23487
+ labelX,
23488
+ labelY,
23489
+ yOffset: edgeYOffsets[i],
23490
+ parallelCount: edgeParallelCounts[i],
23491
+ metadata: edge.metadata,
23492
+ deferred: true
23493
+ });
23494
+ }
23495
+ let maxX = 0;
23496
+ let maxY = 0;
23497
+ for (const node of layoutNodes) {
23498
+ maxX = Math.max(maxX, node.x + node.width / 2);
23499
+ maxY = Math.max(maxY, node.y + node.height / 2);
23500
+ }
23501
+ for (const group of layoutGroups) {
23502
+ maxX = Math.max(maxX, group.x + group.width / 2);
23503
+ maxY = Math.max(maxY, group.y + group.height / 2);
23504
+ }
23505
+ return {
23506
+ nodes: layoutNodes,
23507
+ edges: layoutEdges,
23508
+ groups: layoutGroups,
23509
+ width: maxX + MARGIN3,
23510
+ height: maxY + MARGIN3
23511
+ };
23512
+ }
23513
+ const N = parsed.nodes.length + parsed.groups.length;
23514
+ const E = parsed.edges.length;
23515
+ const trivial = N < 8 && E < 10;
23516
+ const variants = trivial ? [getVariants()[1]] : getVariants();
23517
+ const results = await Promise.all(variants.map((v) => runVariant(v)));
23518
+ let best = results[0];
23519
+ let bestScore = scoreLayout(best);
23520
+ for (let i = 1; i < results.length; i++) {
23521
+ const s = scoreLayout(results[i]);
23522
+ if (cmpScore(s, bestScore) < 0) {
23523
+ best = results[i];
23524
+ bestScore = s;
23525
+ }
23526
+ }
23527
+ return best;
23528
+ }
23529
+ 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;
23530
+ var init_layout5 = __esm({
23531
+ "src/boxes-and-lines/layout.ts"() {
23532
+ "use strict";
23533
+ MARGIN3 = 40;
23534
+ CONTAINER_PAD_X3 = 30;
23535
+ CONTAINER_PAD_TOP2 = 40;
23536
+ CONTAINER_PAD_BOTTOM3 = 24;
23537
+ MAX_PARALLEL_EDGES = 5;
23538
+ PARALLEL_SPACING = 22;
23539
+ PHI = 1.618;
23540
+ NODE_HEIGHT = 60;
23541
+ NODE_WIDTH = Math.round(NODE_HEIGHT * PHI);
23542
+ DESC_NODE_WIDTH = 140;
23543
+ DESC_FONT_SIZE2 = 10;
23544
+ DESC_LINE_HEIGHT2 = 1.4;
23545
+ DESC_PADDING = 8;
23546
+ SEPARATOR_GAP5 = 4;
23547
+ MAX_DESC_LINES2 = 6;
23548
+ MAX_LABEL_LINES = 3;
23549
+ LABEL_LINE_HEIGHT = 1.3;
23550
+ LABEL_PAD = 12;
23551
+ elkInstance = null;
23552
+ CROSSINGS_FORGIVENESS = 1;
23553
+ }
23554
+ });
23555
+
23539
23556
  // src/mindmap/text-wrap.ts
23540
23557
  function tokenize(text) {
23541
23558
  const tokens = [];
@@ -23674,7 +23691,7 @@ var layout_exports6 = {};
23674
23691
  __export(layout_exports6, {
23675
23692
  layoutMindmap: () => layoutMindmap
23676
23693
  });
23677
- function layoutMindmap(parsed, palette, options) {
23694
+ function layoutMindmap(parsed, _palette, options) {
23678
23695
  const roots = parsed.roots;
23679
23696
  if (roots.length === 0) {
23680
23697
  return { nodes: [], edges: [], width: 0, height: 0 };
@@ -24570,7 +24587,7 @@ function layoutElement(el, x, y, width) {
24570
24587
  node.height = getElementHeight(el);
24571
24588
  return node;
24572
24589
  }
24573
- const isInlineRow = el.metadata._inlineRow === "true" || el.metadata._labelField === "true";
24590
+ const isInlineRow = el.metadata["_inlineRow"] === "true" || el.metadata["_labelField"] === "true";
24574
24591
  const padTop = isInlineRow ? 0 : GROUP_PADDING_TOP;
24575
24592
  const padBottom = isInlineRow ? 0 : GROUP_PADDING_BOTTOM;
24576
24593
  const padX = isInlineRow ? 0 : GROUP_PADDING_X;
@@ -24619,7 +24636,7 @@ function allocateEqualWidths(children, totalWidth) {
24619
24636
  }
24620
24637
  function getElementHeight(el) {
24621
24638
  if (el.type === "heading") {
24622
- return el.headingLevel === 2 ? ELEMENT_HEIGHTS.subheading ?? 36 : ELEMENT_HEIGHTS.heading ?? 48;
24639
+ return el.headingLevel === 2 ? ELEMENT_HEIGHTS["subheading"] ?? 36 : ELEMENT_HEIGHTS["heading"] ?? 48;
24623
24640
  }
24624
24641
  if (el.type === "textInput" && el.fieldVariant === "textarea") {
24625
24642
  return 80;
@@ -24633,16 +24650,16 @@ function getElementHeight(el) {
24633
24650
  if (el.type === "image") {
24634
24651
  if (el.imageHint === "round") return 80;
24635
24652
  if (el.imageHint === "wide") return 80;
24636
- return ELEMENT_HEIGHTS.image ?? 120;
24653
+ return ELEMENT_HEIGHTS["image"] ?? 120;
24637
24654
  }
24638
- if (el.metadata._labelField === "true") {
24655
+ if (el.metadata["_labelField"] === "true") {
24639
24656
  return 36;
24640
24657
  }
24641
24658
  return ELEMENT_HEIGHTS[el.type] ?? 24;
24642
24659
  }
24643
24660
  function getSpacingAfter(el) {
24644
24661
  if (el.type === "heading" && el.headingLevel === 2) {
24645
- return SPACING_AFTER.subheading ?? 12;
24662
+ return SPACING_AFTER["subheading"] ?? 12;
24646
24663
  }
24647
24664
  return SPACING_AFTER[el.type] ?? 8;
24648
24665
  }
@@ -24650,7 +24667,7 @@ function computeFieldAlignX(children) {
24650
24667
  let maxLabelWidth = 0;
24651
24668
  let labelFieldCount = 0;
24652
24669
  for (const child of children) {
24653
- if (child.metadata._labelField === "true" && child.children.length >= 2) {
24670
+ if (child.metadata["_labelField"] === "true" && child.children.length >= 2) {
24654
24671
  const labelEl = child.children[0];
24655
24672
  const labelWidth = labelEl.label.length * CHAR_WIDTH5;
24656
24673
  maxLabelWidth = Math.max(maxLabelWidth, labelWidth);
@@ -24862,7 +24879,7 @@ function renderNode(parent, node, ctx, depth) {
24862
24879
  function renderGroup(g, node, ctx, depth) {
24863
24880
  const { palette, isTransparent } = ctx;
24864
24881
  const el = node.element;
24865
- if (el.metadata._inlineRow === "true" || el.metadata._labelField === "true") {
24882
+ if (el.metadata["_inlineRow"] === "true" || el.metadata["_labelField"] === "true") {
24866
24883
  for (const child of node.children) {
24867
24884
  renderNode(g, child, ctx, depth);
24868
24885
  }
@@ -24990,7 +25007,7 @@ function renderDivider(g, node, ctx) {
24990
25007
  function renderText(g, node, ctx) {
24991
25008
  const { palette } = ctx;
24992
25009
  const el = node.element;
24993
- if (el.metadata._labelField === "true" && el.children.length >= 2) {
25010
+ if (el.metadata["_labelField"] === "true" && el.children.length >= 2) {
24994
25011
  for (const child of node.children) {
24995
25012
  renderNode(g, child, ctx, 0);
24996
25013
  }
@@ -25284,7 +25301,7 @@ __export(layout_exports8, {
25284
25301
  layoutC4Deployment: () => layoutC4Deployment,
25285
25302
  rollUpContextRelationships: () => rollUpContextRelationships
25286
25303
  });
25287
- import dagre5 from "@dagrejs/dagre";
25304
+ import dagre4 from "@dagrejs/dagre";
25288
25305
  function computeEdgePenalty(edgeList, nodePositions, degrees, nodeGeometry) {
25289
25306
  let penalty = 0;
25290
25307
  for (const edge of edgeList) {
@@ -25725,7 +25742,7 @@ function layoutC4Context(parsed, activeTagGroup) {
25725
25742
  }
25726
25743
  const contextRels = rollUpContextRelationships(parsed);
25727
25744
  const spacing = computeAdaptiveSpacing(contextRels);
25728
- const g = new dagre5.graphlib.Graph();
25745
+ const g = new dagre4.graphlib.Graph();
25729
25746
  g.setGraph({
25730
25747
  rankdir: "TB",
25731
25748
  nodesep: spacing.nodesep,
@@ -25746,7 +25763,7 @@ function layoutC4Context(parsed, activeTagGroup) {
25746
25763
  g.setEdge(rel.sourceName, rel.targetName, { label: rel.label ?? "" });
25747
25764
  }
25748
25765
  }
25749
- dagre5.layout(g);
25766
+ dagre4.layout(g);
25750
25767
  reduceCrossings(
25751
25768
  g,
25752
25769
  validRels.map((r) => ({ source: r.sourceName, target: r.targetName }))
@@ -25918,7 +25935,7 @@ function layoutC4Containers(parsed, systemName, activeTagGroup) {
25918
25935
  }
25919
25936
  }
25920
25937
  const hasGroups = elementToGroup.size > 0;
25921
- const g = hasGroups ? new dagre5.graphlib.Graph({ compound: true }) : new dagre5.graphlib.Graph();
25938
+ const g = hasGroups ? new dagre4.graphlib.Graph({ compound: true }) : new dagre4.graphlib.Graph();
25922
25939
  g.setDefaultEdgeLabel(() => ({}));
25923
25940
  if (hasGroups) {
25924
25941
  const seenGroups = /* @__PURE__ */ new Set();
@@ -25996,7 +26013,7 @@ function layoutC4Containers(parsed, systemName, activeTagGroup) {
25996
26013
  g.setEdge(rel.sourceName, rel.targetName, { label: rel.label ?? "" });
25997
26014
  }
25998
26015
  }
25999
- dagre5.layout(g);
26016
+ dagre4.layout(g);
26000
26017
  const nodeGroupMap = hasGroups ? new Map([...elementToGroup.entries()].map(([k, v]) => [k, v.name])) : void 0;
26001
26018
  reduceCrossings(
26002
26019
  g,
@@ -26322,7 +26339,7 @@ function layoutC4Components(parsed, systemName, containerName, activeTagGroup) {
26322
26339
  }
26323
26340
  }
26324
26341
  const hasGroups = elementToGroup.size > 0;
26325
- const g = hasGroups ? new dagre5.graphlib.Graph({ compound: true }) : new dagre5.graphlib.Graph();
26342
+ const g = hasGroups ? new dagre4.graphlib.Graph({ compound: true }) : new dagre4.graphlib.Graph();
26326
26343
  g.setDefaultEdgeLabel(() => ({}));
26327
26344
  if (hasGroups) {
26328
26345
  const seenGroups = /* @__PURE__ */ new Set();
@@ -26406,7 +26423,7 @@ function layoutC4Components(parsed, systemName, containerName, activeTagGroup) {
26406
26423
  g.setEdge(rel.sourceName, rel.targetName, { label: rel.label ?? "" });
26407
26424
  }
26408
26425
  }
26409
- dagre5.layout(g);
26426
+ dagre4.layout(g);
26410
26427
  const nodeGroupMap = hasGroups ? new Map([...elementToGroup.entries()].map(([k, v]) => [k, v.name])) : void 0;
26411
26428
  reduceCrossings(
26412
26429
  g,
@@ -26695,7 +26712,7 @@ function layoutC4Deployment(parsed, activeTagGroup) {
26695
26712
  for (const r of refEntries) {
26696
26713
  nameToElement.set(r.element.name, r.element);
26697
26714
  }
26698
- const g = new dagre5.graphlib.Graph({ compound: true });
26715
+ const g = new dagre4.graphlib.Graph({ compound: true });
26699
26716
  g.setDefaultEdgeLabel(() => ({}));
26700
26717
  for (const [infraId] of infraIds) {
26701
26718
  g.setNode(infraId, {});
@@ -26739,7 +26756,7 @@ function layoutC4Deployment(parsed, activeTagGroup) {
26739
26756
  g.setEdge(rel.sourceName, rel.targetName, { label: rel.label ?? "" });
26740
26757
  }
26741
26758
  }
26742
- dagre5.layout(g);
26759
+ dagre4.layout(g);
26743
26760
  const nodeInfraMap = /* @__PURE__ */ new Map();
26744
26761
  for (const r of refEntries) nodeInfraMap.set(r.element.name, r.infraId);
26745
26762
  reduceCrossings(
@@ -27971,7 +27988,7 @@ var layout_exports9 = {};
27971
27988
  __export(layout_exports9, {
27972
27989
  layoutGraph: () => layoutGraph
27973
27990
  });
27974
- import dagre6 from "@dagrejs/dagre";
27991
+ import dagre5 from "@dagrejs/dagre";
27975
27992
  function computeNodeWidth(label, shape) {
27976
27993
  if (shape === "pseudostate") return 24;
27977
27994
  const base = Math.max(120, label.length * 9 + 40);
@@ -28004,7 +28021,7 @@ function layoutGraph(graph, options) {
28004
28021
  if (allNodes.length === 0) {
28005
28022
  return { nodes: [], edges: [], groups: [], width: 0, height: 0 };
28006
28023
  }
28007
- const g = new dagre6.graphlib.Graph({ compound: true });
28024
+ const g = new dagre5.graphlib.Graph({ compound: true });
28008
28025
  g.setGraph({
28009
28026
  rankdir: graph.direction,
28010
28027
  nodesep: 50,
@@ -28040,7 +28057,7 @@ function layoutGraph(graph, options) {
28040
28057
  label: edge.label ?? ""
28041
28058
  });
28042
28059
  }
28043
- dagre6.layout(g);
28060
+ dagre5.layout(g);
28044
28061
  const collapsedGroupIds = collapsedChildCounts ? new Set(collapsedChildCounts.keys()) : /* @__PURE__ */ new Set();
28045
28062
  const layoutNodes = allNodes.map((node) => {
28046
28063
  const pos = g.node(node.id);
@@ -28474,7 +28491,7 @@ function renderFlowchart(container, graph, layout, palette, isDark, onClickItem,
28474
28491
  endTerminalIds.add(node.id);
28475
28492
  }
28476
28493
  }
28477
- const colorOff = graph.options?.color === "off";
28494
+ const colorOff = graph.options?.["color"] === "off";
28478
28495
  const solid = graph.options?.["solid-fill"] === "on";
28479
28496
  for (const node of layout.nodes) {
28480
28497
  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);
@@ -29403,7 +29420,7 @@ __export(layout_exports10, {
29403
29420
  layoutInfra: () => layoutInfra,
29404
29421
  separateGroups: () => separateGroups
29405
29422
  });
29406
- import dagre7 from "@dagrejs/dagre";
29423
+ import dagre6 from "@dagrejs/dagre";
29407
29424
  function countDisplayProps(node, expanded, options) {
29408
29425
  if (!expanded) return 0;
29409
29426
  let count = node.properties.filter((p) => DISPLAY_KEYS.has(p.key)).length;
@@ -29706,7 +29723,7 @@ function layoutInfra(computed, expandedNodeIds, collapsedNodes) {
29706
29723
  };
29707
29724
  }
29708
29725
  const isLR = computed.direction !== "TB";
29709
- const g = new dagre7.graphlib.Graph();
29726
+ const g = new dagre6.graphlib.Graph();
29710
29727
  g.setGraph({
29711
29728
  rankdir: computed.direction === "TB" ? "TB" : "LR",
29712
29729
  nodesep: isLR ? 70 : 60,
@@ -29757,7 +29774,7 @@ function layoutInfra(computed, expandedNodeIds, collapsedNodes) {
29757
29774
  g.setEdge(edge.sourceId, edge.targetId, { label: edge.label });
29758
29775
  }
29759
29776
  }
29760
- dagre7.layout(g);
29777
+ dagre6.layout(g);
29761
29778
  const layoutNodes = computed.nodes.map((node) => {
29762
29779
  const pos = g.node(node.id);
29763
29780
  return {
@@ -30666,7 +30683,7 @@ function renderGroups(svg, groups, palette, _isDark) {
30666
30683
  }
30667
30684
  }
30668
30685
  }
30669
- function renderEdgePaths(svg, edges, nodes, groups, palette, isDark, animate, direction, speedMultiplier = 1) {
30686
+ function renderEdgePaths(svg, edges, nodes, groups, palette, _isDark, animate, direction, speedMultiplier = 1) {
30670
30687
  const nodeMap = new Map(nodes.map((n) => [n.id, n]));
30671
30688
  const maxRps = Math.max(...edges.map((e) => e.computedRps), 1);
30672
30689
  const { srcPts, tgtPts } = computePortPts(edges, nodeMap, direction);
@@ -30707,7 +30724,7 @@ function renderEdgePaths(svg, edges, nodes, groups, palette, isDark, animate, di
30707
30724
  }
30708
30725
  }
30709
30726
  }
30710
- function renderEdgeLabels(svg, edges, nodes, groups, palette, isDark, animate, direction) {
30727
+ function renderEdgeLabels(svg, edges, nodes, groups, palette, _isDark, animate, direction) {
30711
30728
  const nodeMap = new Map(nodes.map((n) => [n.id, n]));
30712
30729
  const { srcPts, tgtPts } = computePortPts(edges, nodeMap, direction);
30713
30730
  for (const edge of edges) {
@@ -31446,7 +31463,7 @@ function sampleBetaPert(o, m, p, rng) {
31446
31463
  const beta = 1 + 4 * (p - m) / range;
31447
31464
  return o + sampleBeta(alpha, beta, rng) * range;
31448
31465
  }
31449
- function simulate(resolved, expanded, predecessors, successors, topo, terminals, poisoned, opts) {
31466
+ function simulate(resolved, expanded, _predecessors, _successors, topo, terminals, poisoned, opts) {
31450
31467
  const rng = mulberry32(opts.seed);
31451
31468
  const expById = /* @__PURE__ */ new Map();
31452
31469
  for (const e of expanded) expById.set(e.id, e);
@@ -32459,7 +32476,7 @@ __export(layout_exports11, {
32459
32476
  layoutPert: () => layoutPert,
32460
32477
  relayoutPert: () => relayoutPert
32461
32478
  });
32462
- import dagre8 from "@dagrejs/dagre";
32479
+ import dagre7 from "@dagrejs/dagre";
32463
32480
  function computeNodeSizing(resolved) {
32464
32481
  const unit = resolved.options.timeUnit;
32465
32482
  const sprintMode = resolved.options.sprintMode;
@@ -32567,7 +32584,7 @@ function relayoutPert(resolved, overrides, collapsedGroupIds = /* @__PURE__ */ n
32567
32584
  }
32568
32585
  }
32569
32586
  const dagreId = (id) => memberToGroup.get(id) ?? id;
32570
- const g = new dagre8.graphlib.Graph();
32587
+ const g = new dagre7.graphlib.Graph();
32571
32588
  g.setGraph({
32572
32589
  rankdir: resolved.options.direction,
32573
32590
  nodesep: 50,
@@ -32606,7 +32623,7 @@ function relayoutPert(resolved, overrides, collapsedGroupIds = /* @__PURE__ */ n
32606
32623
  seenEdges.add(k);
32607
32624
  g.setEdge(src, tgt, {});
32608
32625
  }
32609
- dagre8.layout(g);
32626
+ dagre7.layout(g);
32610
32627
  const swimApplied = applySwimLanes(
32611
32628
  g,
32612
32629
  resolved,
@@ -32726,7 +32743,7 @@ function relayoutPert(resolved, overrides, collapsedGroupIds = /* @__PURE__ */ n
32726
32743
  height: totalH + DIAGRAM_PADDING10
32727
32744
  };
32728
32745
  }
32729
- function applySwimLanes(g, resolved, memberToGroup, collapsedGroupIds) {
32746
+ function applySwimLanes(g, resolved, _memberToGroup, collapsedGroupIds) {
32730
32747
  const expanded = resolved.groups.filter(
32731
32748
  (rg) => !collapsedGroupIds.has(rg.group.id)
32732
32749
  );
@@ -32952,7 +32969,7 @@ function reduceCrossings2(g, direction) {
32952
32969
  buckets.get(key).push(id);
32953
32970
  }
32954
32971
  const edges = g.edges().map((e) => ({ v: e.v, w: e.w }));
32955
- const countCrossings = () => {
32972
+ const countCrossings2 = () => {
32956
32973
  let total = 0;
32957
32974
  for (let i = 0; i < edges.length; i++) {
32958
32975
  const a = edges[i];
@@ -32965,13 +32982,13 @@ function reduceCrossings2(g, direction) {
32965
32982
  const b1 = g.node(b.v);
32966
32983
  const b2 = g.node(b.w);
32967
32984
  if (!b1 || !b2) continue;
32968
- if (segmentsCross(a1, a2, b1, b2)) total++;
32985
+ if (segmentsCross2(a1, a2, b1, b2)) total++;
32969
32986
  }
32970
32987
  }
32971
32988
  return total;
32972
32989
  };
32973
32990
  const MAX_ITER = 8;
32974
- let baseline = countCrossings();
32991
+ let baseline = countCrossings2();
32975
32992
  if (baseline === 0) return;
32976
32993
  for (let iter = 0; iter < MAX_ITER; iter++) {
32977
32994
  let improved = false;
@@ -32989,7 +33006,7 @@ function reduceCrossings2(g, direction) {
32989
33006
  const bv = bn[slotAxis];
32990
33007
  an[slotAxis] = bv;
32991
33008
  bn[slotAxis] = av;
32992
- const after = countCrossings();
33009
+ const after = countCrossings2();
32993
33010
  if (after < baseline) {
32994
33011
  baseline = after;
32995
33012
  improved = true;
@@ -33010,7 +33027,7 @@ function reduceCrossings2(g, direction) {
33010
33027
  data.points = smoothEdge(src, tgt, direction);
33011
33028
  }
33012
33029
  }
33013
- function segmentsCross(a1, a2, b1, b2) {
33030
+ function segmentsCross2(a1, a2, b1, b2) {
33014
33031
  const ccw = (p, q, r) => (q.x - p.x) * (r.y - p.y) - (q.y - p.y) * (r.x - p.x);
33015
33032
  const d1 = ccw(b1, b2, a1);
33016
33033
  const d2 = ccw(b1, b2, a2);
@@ -35018,12 +35035,6 @@ function calculateSchedule(parsed) {
35018
35035
  const warn = (line12, message) => {
35019
35036
  diagnostics.push(makeDgmoError(line12, message, "warning"));
35020
35037
  };
35021
- const _fail = (line12, message) => {
35022
- const diag = makeDgmoError(line12, message);
35023
- diagnostics.push(diag);
35024
- result.error = formatDgmoError(diag);
35025
- return result;
35026
- };
35027
35038
  const holidaySet = buildHolidaySet(parsed.holidays);
35028
35039
  let projectStart;
35029
35040
  if (parsed.options.start) {
@@ -35048,7 +35059,6 @@ function calculateSchedule(parsed) {
35048
35059
  }
35049
35060
  buildImplicitDeps(parsed.nodes, taskMap);
35050
35061
  for (const task of allTasks2) {
35051
- const _node = taskMap.get(task.id);
35052
35062
  for (const dep of task.dependencies) {
35053
35063
  const resolved = resolveTaskName(dep.targetName, allTasks2);
35054
35064
  if (isResolverError(resolved)) {
@@ -36589,7 +36599,7 @@ function buildControlsToggles(hasCriticalPath, criticalPathActive, hasDependenci
36589
36599
  }
36590
36600
  return toggles;
36591
36601
  }
36592
- 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) {
36602
+ 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) {
36593
36603
  let visibleGroups;
36594
36604
  if (activeGroupName) {
36595
36605
  const activeGroup = tagGroups.filter(
@@ -37552,7 +37562,7 @@ function resolveTaskColor(rt, activeTagGroup, resolved, seriesColors2, palette)
37552
37562
  }
37553
37563
  return palette.accent || seriesColors2[0] || "#4a90d9";
37554
37564
  }
37555
- function renderTimeScaleHorizontal(g, scale, innerWidth, innerHeight, textColor) {
37565
+ function renderTimeScaleHorizontal(g, scale, _innerWidth, innerHeight, textColor) {
37556
37566
  const [domainMin, domainMax] = scale.domain();
37557
37567
  const ticks = computeTimeTicks(domainMin, domainMax, scale);
37558
37568
  if (ticks.length < 2) return;
@@ -37799,7 +37809,7 @@ function renderState(container, graph, layout, palette, isDark, onClickItem, exp
37799
37809
  for (const group of layout.groups) {
37800
37810
  if (group.collapsed) collapsedGroupIds.add(group.id);
37801
37811
  }
37802
- const colorOff = graph.options?.color === "off";
37812
+ const colorOff = graph.options?.["color"] === "off";
37803
37813
  const solid = graph.options?.["solid-fill"] === "on";
37804
37814
  for (const node of layout.nodes) {
37805
37815
  const isCollapsedGroup = collapsedGroupIds.has(node.id);
@@ -38198,7 +38208,7 @@ function renderQuadrantFocus(container, parsed, quadrantPosition, palette, isDar
38198
38208
  }
38199
38209
  }
38200
38210
  }
38201
- function renderQuarterCircle(svg, parsed, quadrant, qColor, palette, isDark, width, height, mutedColor, tooltip, rootContainer, onClickItem) {
38211
+ function renderQuarterCircle(svg, parsed, quadrant, qColor, palette, isDark, width, height, mutedColor, _tooltip, rootContainer, onClickItem) {
38202
38212
  const padding = 8;
38203
38213
  const size = Math.min(width - padding, height - padding);
38204
38214
  const maxRadius = size * 0.95;
@@ -39068,7 +39078,7 @@ function estimateListingHeight(parsed) {
39068
39078
  );
39069
39079
  return LISTING_LINE_HEIGHT * (maxBlipsInQuadrant + 1) + LISTING_LINE_HEIGHT + LISTING_TOP_MARGIN;
39070
39080
  }
39071
- function createBlipPopover(container, palette, isDark) {
39081
+ function createBlipPopover(container, _palette, isDark) {
39072
39082
  container.style.position = "relative";
39073
39083
  const existing = container.querySelector(
39074
39084
  "[data-blip-popover]"
@@ -40935,7 +40945,7 @@ function computeEdgeLabelPosition(midAngle, radius, cx, cy, lineCount, maxCharLe
40935
40945
  labelAngle: best.labelAngle
40936
40946
  };
40937
40947
  }
40938
- function fitToCanvas(nodes, edges, parsed, cx, cy, radius, width, height, _isClockwise) {
40948
+ function fitToCanvas(nodes, edges, parsed, _cx, _cy, radius, width, height, _isClockwise) {
40939
40949
  const PADDING3 = 30;
40940
40950
  let contentMinX = Infinity, contentMaxX = -Infinity;
40941
40951
  let contentMinY = Infinity, contentMaxY = -Infinity;
@@ -42445,7 +42455,7 @@ function renderPhaseBar(svg, phase, x, y, width, palette, collapsed, autoColor,
42445
42455
  });
42446
42456
  }
42447
42457
  }
42448
- function renderTaskRow(svg, task, parsed, x, y, labelW, roleX, roleColW, palette, surfaceBg, solid, taskDiagnostics, hasAnyDiagnostic, rowContent, onClickLine, _onMarkerDragStart) {
42458
+ function renderTaskRow(svg, task, parsed, x, y, labelW, roleX, roleColW, palette, surfaceBg, solid, taskDiagnostics, _hasAnyDiagnostic, rowContent, onClickLine, _onMarkerDragStart) {
42449
42459
  const rowG = svg.append("g").attr("class", "raci-task-row").attr("data-task-id", task.id).attr("data-line-number", String(task.lineNumber));
42450
42460
  const labelX = x + 8;
42451
42461
  const labelMaxW = labelW - 16;
@@ -43251,7 +43261,6 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
43251
43261
  const messages = collapsed ? collapsed.messages : parsed.messages;
43252
43262
  const elements = collapsed ? collapsed.elements : parsed.elements;
43253
43263
  const groups = collapsed ? collapsed.groups : parsed.groups;
43254
- const collapsedGroupIds = collapsed?.collapsedGroupIds ?? /* @__PURE__ */ new Map();
43255
43264
  const collapsedSections = options?.collapsedSections;
43256
43265
  const sourceParticipants = collapsed ? collapsed.participants : parsed.participants;
43257
43266
  const participants = applyPositionOverrides(
@@ -43279,7 +43288,7 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
43279
43288
  return Math.min(NOTE_MAX_W, laneMax);
43280
43289
  };
43281
43290
  const charsForWidth = (maxW) => Math.floor((maxW - NOTE_PAD_H * 2 - NOTE_FOLD) / NOTE_CHAR_W);
43282
- const activationsOff = parsedOptions.activations?.toLowerCase() === "off";
43291
+ const activationsOff = parsedOptions["activations"]?.toLowerCase() === "off";
43283
43292
  const activeTagGroup = resolveActiveTagGroup(
43284
43293
  parsed.tagGroups,
43285
43294
  parsedOptions["active-tag"],
@@ -46235,7 +46244,7 @@ function renderTimelineGroupLegend(g, groups, groupColorMap, textColor, palette,
46235
46244
  legendX += pillW + GAP;
46236
46245
  }
46237
46246
  }
46238
- function renderTimeline(container, parsed, palette, isDark, onClickItem, exportDims, activeTagGroup, swimlaneTagGroup, onTagStateChange, viewMode) {
46247
+ function setupTimeline(container, parsed, palette, isDark, exportDims, activeTagGroup, swimlaneTagGroup) {
46239
46248
  d3Selection22.select(container).selectAll(":not([data-d3-tooltip])").remove();
46240
46249
  const solid = parsed.solidFill === true;
46241
46250
  const {
@@ -46244,19 +46253,17 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
46244
46253
  timelineEras,
46245
46254
  timelineMarkers,
46246
46255
  timelineSort,
46247
- timelineScale,
46248
- timelineSwimlanes,
46249
46256
  orientation
46250
46257
  } = parsed;
46251
- const title = parsed.noTitle ? null : parsed.title;
46252
- if (timelineEvents.length === 0) return;
46253
- if (swimlaneTagGroup == null && timelineSort === "tag" && parsed.timelineDefaultSwimlaneTG) {
46254
- swimlaneTagGroup = parsed.timelineDefaultSwimlaneTG;
46258
+ if (timelineEvents.length === 0) return null;
46259
+ let resolvedSwimlaneTG = swimlaneTagGroup ?? null;
46260
+ if (resolvedSwimlaneTG == null && timelineSort === "tag" && parsed.timelineDefaultSwimlaneTG) {
46261
+ resolvedSwimlaneTG = parsed.timelineDefaultSwimlaneTG;
46255
46262
  }
46256
46263
  const tooltip = createTooltip2(container, palette, isDark);
46257
46264
  const width = exportDims?.width ?? container.clientWidth;
46258
46265
  const height = exportDims?.height ?? container.clientHeight;
46259
- if (width <= 0 || height <= 0) return;
46266
+ if (width <= 0 || height <= 0) return null;
46260
46267
  const isVertical = orientation === "vertical";
46261
46268
  const textColor = palette.text;
46262
46269
  const mutedColor = palette.border;
@@ -46268,8 +46275,8 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
46268
46275
  groupColorMap.set(grp.name, grp.color ?? colors[i % colors.length]);
46269
46276
  });
46270
46277
  let tagLanes = null;
46271
- if (swimlaneTagGroup) {
46272
- const tagKey = swimlaneTagGroup.toLowerCase();
46278
+ if (resolvedSwimlaneTG) {
46279
+ const tagKey = resolvedSwimlaneTG.toLowerCase();
46273
46280
  const tagGroup = parsed.timelineTagGroups.find(
46274
46281
  (g) => g.name.toLowerCase() === tagKey
46275
46282
  );
@@ -46300,7 +46307,7 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
46300
46307
  }
46301
46308
  }
46302
46309
  }
46303
- const effectiveColorTG = activeTagGroup ?? swimlaneTagGroup ?? null;
46310
+ const effectiveColorTG = activeTagGroup ?? resolvedSwimlaneTG ?? null;
46304
46311
  function eventColor(ev) {
46305
46312
  if (effectiveColorTG) {
46306
46313
  const tagColor = resolveTagColor(
@@ -46356,6 +46363,30 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
46356
46363
  }
46357
46364
  }
46358
46365
  const datePadding = (maxDate - minDate) * 0.05 || 0.5;
46366
+ const tagLegendReserve = parsed.timelineTagGroups.length > 0 ? 36 : 0;
46367
+ return {
46368
+ width,
46369
+ height,
46370
+ isVertical,
46371
+ tooltip,
46372
+ solid,
46373
+ textColor,
46374
+ mutedColor,
46375
+ bgColor,
46376
+ bg,
46377
+ swimlaneTagGroup: resolvedSwimlaneTG,
46378
+ groupColorMap,
46379
+ tagLanes,
46380
+ eventColor,
46381
+ minDate,
46382
+ maxDate,
46383
+ datePadding,
46384
+ earliestStartDateStr,
46385
+ latestEndDateStr,
46386
+ tagLegendReserve
46387
+ };
46388
+ }
46389
+ function makeTimelineHoverHelpers() {
46359
46390
  const FADE_OPACITY3 = 0.1;
46360
46391
  function fadeToGroup(g, groupName) {
46361
46392
  g.selectAll(".tl-event").each(function() {
@@ -46455,337 +46486,683 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
46455
46486
  evG.attr(`data-tag-${key}`, value.toLowerCase());
46456
46487
  }
46457
46488
  }
46458
- const tagLegendReserve = parsed.timelineTagGroups.length > 0 ? 36 : 0;
46459
- if (isVertical) {
46460
- const useGroupedVertical = tagLanes != null || timelineSort === "group" && timelineGroups.length > 0;
46461
- if (useGroupedVertical) {
46462
- let laneNames;
46463
- let laneEventsByName;
46464
- if (tagLanes) {
46465
- laneNames = tagLanes.map((l) => l.name);
46466
- laneEventsByName = new Map(tagLanes.map((l) => [l.name, l.events]));
46467
- } else {
46468
- const groupNames = timelineGroups.map((gr) => gr.name);
46469
- const ungroupedEvents = timelineEvents.filter(
46470
- (ev) => ev.group === null || !groupNames.includes(ev.group)
46471
- );
46472
- laneNames = ungroupedEvents.length > 0 ? [...groupNames, "(Other)"] : groupNames;
46473
- laneEventsByName = new Map(
46474
- laneNames.map((name) => [
46475
- name,
46476
- timelineEvents.filter(
46477
- (ev) => name === "(Other)" ? ev.group === null || !groupNames.includes(ev.group) : ev.group === name
46478
- )
46479
- ])
46480
- );
46489
+ return {
46490
+ FADE_OPACITY: FADE_OPACITY3,
46491
+ fadeToGroup,
46492
+ fadeToEra,
46493
+ fadeToMarker,
46494
+ fadeReset,
46495
+ fadeToTagValue,
46496
+ setTagAttrs
46497
+ };
46498
+ }
46499
+ function renderTimelineTagLegendOverlay(container, parsed, palette, isDark, setup, hovers, onClickItem, exportDims, swimlaneTagGroup, activeTagGroup, onTagStateChange, viewMode) {
46500
+ if (parsed.timelineTagGroups.length === 0) return;
46501
+ const { width, textColor, groupColorMap, solid } = setup;
46502
+ const { FADE_OPACITY: FADE_OPACITY3, fadeReset, fadeToTagValue } = hovers;
46503
+ const title = parsed.noTitle ? null : parsed.title;
46504
+ const { timelineEvents } = parsed;
46505
+ const LG_HEIGHT = LEGEND_HEIGHT;
46506
+ const LG_PILL_PAD = LEGEND_PILL_PAD;
46507
+ const LG_PILL_FONT_SIZE = LEGEND_PILL_FONT_SIZE;
46508
+ const LG_CAPSULE_PAD = LEGEND_CAPSULE_PAD;
46509
+ const LG_DOT_R = LEGEND_DOT_R;
46510
+ const LG_ENTRY_FONT_SIZE = LEGEND_ENTRY_FONT_SIZE;
46511
+ const LG_ENTRY_DOT_GAP = LEGEND_ENTRY_DOT_GAP;
46512
+ const LG_ENTRY_TRAIL = LEGEND_ENTRY_TRAIL;
46513
+ const LG_ICON_W = 20;
46514
+ const mainSvg = d3Selection22.select(container).select("svg");
46515
+ const mainG = mainSvg.select("g");
46516
+ if (!mainSvg.empty() && !mainG.empty()) {
46517
+ let drawSwimlaneIcon4 = function(parent, x, y, isSwimActive) {
46518
+ const iconG = parent.append("g").attr("class", "tl-swimlane-icon").attr("transform", `translate(${x}, ${y})`).style("cursor", "pointer");
46519
+ const barColor = isSwimActive ? palette.primary : palette.textMuted;
46520
+ const barOpacity = isSwimActive ? 1 : 0.35;
46521
+ const bars = [
46522
+ { y: 0, w: 8 },
46523
+ { y: 4, w: 12 },
46524
+ { y: 8, w: 6 }
46525
+ ];
46526
+ for (const bar of bars) {
46527
+ 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);
46481
46528
  }
46482
- const laneCount = laneNames.length;
46483
- const scaleMargin = timelineScale ? 40 : 0;
46484
- const markerMargin = timelineMarkers.length > 0 ? 30 : 0;
46485
- const margin = {
46486
- top: 104 + markerMargin + tagLegendReserve,
46487
- right: 40 + scaleMargin,
46488
- bottom: 40,
46489
- left: 60 + scaleMargin
46490
- };
46491
- const innerWidth = width - margin.left - margin.right;
46492
- const innerHeight = height - margin.top - margin.bottom;
46493
- const laneWidth = innerWidth / laneCount;
46494
- const yScale = d3Scale2.scaleLinear().domain([minDate - datePadding, maxDate + datePadding]).range([0, innerHeight]);
46495
- 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);
46496
- const g = svg.append("g").attr("transform", `translate(${margin.left},${margin.top})`);
46497
- renderChartTitle(
46498
- svg,
46499
- title,
46500
- parsed.titleLineNumber,
46501
- width,
46502
- textColor,
46503
- onClickItem
46504
- );
46505
- renderEras(
46506
- g,
46507
- timelineEras,
46508
- yScale,
46509
- true,
46510
- innerWidth,
46511
- innerHeight,
46512
- (s, e) => fadeToEra(g, s, e),
46513
- () => fadeReset(g),
46514
- timelineScale,
46515
- tooltip,
46516
- palette
46517
- );
46518
- renderMarkers(
46519
- g,
46520
- timelineMarkers,
46521
- yScale,
46522
- true,
46523
- innerWidth,
46524
- innerHeight,
46525
- (d) => fadeToMarker(g, d),
46526
- () => fadeReset(g),
46527
- timelineScale,
46528
- tooltip,
46529
- palette
46529
+ return iconG;
46530
+ }, relayout2 = function() {
46531
+ renderTimeline(
46532
+ container,
46533
+ parsed,
46534
+ palette,
46535
+ isDark,
46536
+ onClickItem,
46537
+ exportDims,
46538
+ currentActiveGroup,
46539
+ currentSwimlaneGroup,
46540
+ onTagStateChange,
46541
+ viewMode
46530
46542
  );
46531
- if (timelineScale) {
46532
- renderTimeScale(
46533
- g,
46534
- yScale,
46535
- true,
46536
- innerWidth,
46537
- innerHeight,
46538
- textColor,
46539
- minDate,
46540
- maxDate,
46541
- formatBoundaryLabel(earliestStartDateStr, latestEndDateStr),
46542
- formatBoundaryLabel(latestEndDateStr, earliestStartDateStr)
46543
+ }, drawLegend2 = function() {
46544
+ mainSvg.selectAll(".tl-tag-legend-group").remove();
46545
+ mainSvg.selectAll(".tl-tag-legend-container").remove();
46546
+ const effectiveColorKey = (currentActiveGroup ?? currentSwimlaneGroup)?.toLowerCase() ?? null;
46547
+ const visibleGroups = viewMode ? legendGroups.filter(
46548
+ (lg) => effectiveColorKey != null && lg.group.name.toLowerCase() === effectiveColorKey
46549
+ ) : legendGroups;
46550
+ if (visibleGroups.length === 0) return;
46551
+ const legendContainer = mainSvg.append("g").attr("class", "tl-tag-legend-container");
46552
+ if (currentActiveGroup) {
46553
+ legendContainer.attr(
46554
+ "data-legend-active",
46555
+ currentActiveGroup.toLowerCase()
46543
46556
  );
46544
46557
  }
46545
- if (timelineSwimlanes || tagLanes) {
46546
- laneNames.forEach((laneName, laneIdx) => {
46547
- const laneX = laneIdx * laneWidth;
46548
- const fillColor = laneIdx % 2 === 0 ? textColor : "transparent";
46549
- 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);
46550
- });
46551
- }
46552
- laneNames.forEach((laneName, laneIdx) => {
46553
- const laneX = laneIdx * laneWidth;
46554
- const laneColor = groupColorMap.get(laneName) ?? textColor;
46555
- const laneCenter = laneX + laneWidth / 2;
46556
- 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));
46557
- 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);
46558
- 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");
46559
- const laneEvents = laneEventsByName.get(laneName) ?? [];
46560
- for (const ev of laneEvents) {
46561
- const y = yScale(parseTimelineDate(ev.date));
46562
- 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(
46563
- "data-end-date",
46564
- ev.endDate ? String(parseTimelineDate(ev.endDate)) : null
46565
- ).style("cursor", "pointer").on("mouseenter", function(event) {
46566
- fadeToGroup(g, laneName);
46567
- showTooltip(tooltip, buildEventTooltipHtml(ev), event);
46568
- }).on("mouseleave", function() {
46569
- fadeReset(g);
46570
- hideTooltip(tooltip);
46571
- }).on("mousemove", function(event) {
46572
- showTooltip(tooltip, buildEventTooltipHtml(ev), event);
46573
- }).on("click", () => {
46574
- if (onClickItem && ev.lineNumber) onClickItem(ev.lineNumber);
46575
- });
46576
- setTagAttrs(evG, ev);
46577
- const evColor = eventColor(ev);
46578
- if (ev.endDate) {
46579
- const y2 = yScale(parseTimelineDate(ev.endDate));
46580
- const rectH = Math.max(y2 - y, 4);
46581
- let fill2 = shapeFill(palette, evColor, isDark, { solid });
46582
- let stroke2 = evColor;
46583
- if (ev.uncertain) {
46584
- const gradientId = `uncertain-vg-${ev.lineNumber}`;
46585
- const strokeGradientId = `uncertain-vg-s-${ev.lineNumber}`;
46586
- const defs = svg.select("defs").node() || svg.append("defs").node();
46587
- const defsEl = d3Selection22.select(defs);
46588
- defsEl.append("linearGradient").attr("id", gradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "0%").attr("y2", "100%").selectAll("stop").data([
46589
- { offset: "0%", opacity: 1 },
46590
- { offset: "80%", opacity: 1 },
46591
- { offset: "100%", opacity: 0 }
46592
- ]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", mix(laneColor, bg, 30)).attr("stop-opacity", (d) => d.opacity);
46593
- defsEl.append("linearGradient").attr("id", strokeGradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "0%").attr("y2", "100%").selectAll("stop").data([
46594
- { offset: "0%", opacity: 1 },
46595
- { offset: "80%", opacity: 1 },
46596
- { offset: "100%", opacity: 0 }
46597
- ]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", evColor).attr("stop-opacity", (d) => d.opacity);
46598
- fill2 = `url(#${gradientId})`;
46599
- stroke2 = `url(#${strokeGradientId})`;
46600
- }
46601
- 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);
46602
- 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);
46558
+ const iconAddon = viewMode ? 0 : LG_ICON_W;
46559
+ const centralGroups = visibleGroups.map((lg) => ({
46560
+ name: lg.group.name,
46561
+ entries: lg.group.entries.map((e) => ({
46562
+ value: e.value,
46563
+ color: e.color
46564
+ }))
46565
+ }));
46566
+ const centralActive = viewMode ? effectiveColorKey : currentActiveGroup;
46567
+ const centralConfig = {
46568
+ groups: centralGroups,
46569
+ position: { placement: "top-center", titleRelation: "below-title" },
46570
+ mode: "fixed",
46571
+ capsulePillAddonWidth: iconAddon
46572
+ };
46573
+ const centralState = { activeGroup: centralActive };
46574
+ const centralCallbacks = viewMode ? {} : {
46575
+ onGroupToggle: (groupName) => {
46576
+ currentActiveGroup = currentActiveGroup === groupName.toLowerCase() ? null : groupName.toLowerCase();
46577
+ drawLegend2();
46578
+ recolorEvents2();
46579
+ onTagStateChange?.(currentActiveGroup, currentSwimlaneGroup);
46580
+ },
46581
+ onEntryHover: (groupName, entryValue) => {
46582
+ const tagKey = groupName.toLowerCase();
46583
+ if (entryValue) {
46584
+ const tagVal = entryValue.toLowerCase();
46585
+ fadeToTagValue(mainG, tagKey, tagVal);
46586
+ mainSvg.selectAll("[data-legend-entry]").each(function() {
46587
+ const el = d3Selection22.select(this);
46588
+ const ev = el.attr("data-legend-entry");
46589
+ const eg = el.attr("data-tag-group") ?? el.node()?.closest?.("[data-tag-group]")?.getAttribute("data-tag-group");
46590
+ el.attr(
46591
+ "opacity",
46592
+ eg === tagKey && ev === tagVal ? 1 : FADE_OPACITY3
46593
+ );
46594
+ });
46603
46595
  } else {
46604
- 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);
46605
- evG.append("text").attr("x", laneCenter + 10).attr("y", y).attr("dy", "0.35em").attr("fill", textColor).attr("font-size", "10px").text(ev.label);
46596
+ fadeReset(mainG);
46597
+ mainSvg.selectAll("[data-legend-entry]").attr("opacity", 1);
46598
+ }
46599
+ },
46600
+ onGroupRendered: (groupName, groupEl, isActive) => {
46601
+ const groupKey = groupName.toLowerCase();
46602
+ groupEl.attr("data-tag-group", groupKey);
46603
+ if (isActive && !viewMode) {
46604
+ const isSwimActive = currentSwimlaneGroup != null && currentSwimlaneGroup.toLowerCase() === groupKey;
46605
+ const pillWidth3 = measureLegendText(groupName, LG_PILL_FONT_SIZE) + LG_PILL_PAD;
46606
+ const pillXOff = LG_CAPSULE_PAD;
46607
+ const iconX = pillXOff + pillWidth3 + 5;
46608
+ const iconY = (LG_HEIGHT - 10) / 2;
46609
+ const iconEl = drawSwimlaneIcon4(
46610
+ groupEl,
46611
+ iconX,
46612
+ iconY,
46613
+ isSwimActive
46614
+ );
46615
+ iconEl.attr("data-swimlane-toggle", groupKey).on("click", (event) => {
46616
+ event.stopPropagation();
46617
+ currentSwimlaneGroup = currentSwimlaneGroup === groupKey ? null : groupKey;
46618
+ onTagStateChange?.(
46619
+ currentActiveGroup,
46620
+ currentSwimlaneGroup
46621
+ );
46622
+ relayout2();
46623
+ });
46606
46624
  }
46607
46625
  }
46608
- });
46609
- } else {
46610
- const scaleMargin = timelineScale ? 40 : 0;
46611
- const markerMargin = timelineMarkers.length > 0 ? 30 : 0;
46612
- const margin = {
46613
- top: 104 + markerMargin + tagLegendReserve,
46614
- right: 200,
46615
- bottom: 40,
46616
- left: 60 + scaleMargin
46617
46626
  };
46618
- const innerWidth = width - margin.left - margin.right;
46619
- const innerHeight = height - margin.top - margin.bottom;
46620
- const axisX = 20;
46621
- const yScale = d3Scale2.scaleLinear().domain([minDate - datePadding, maxDate + datePadding]).range([0, innerHeight]);
46622
- const sorted = timelineEvents.slice().sort((a, b) => parseTimelineDate(a.date) - parseTimelineDate(b.date));
46623
- 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);
46624
- const g = svg.append("g").attr("transform", `translate(${margin.left},${margin.top})`);
46625
- renderChartTitle(
46626
- svg,
46627
- title,
46628
- parsed.titleLineNumber,
46629
- width,
46630
- textColor,
46631
- onClickItem
46632
- );
46633
- renderEras(
46634
- g,
46635
- timelineEras,
46636
- yScale,
46637
- true,
46638
- innerWidth,
46639
- innerHeight,
46640
- (s, e) => fadeToEra(g, s, e),
46641
- () => fadeReset(g),
46642
- timelineScale,
46643
- tooltip,
46644
- palette
46645
- );
46646
- renderMarkers(
46647
- g,
46648
- timelineMarkers,
46649
- yScale,
46650
- true,
46651
- innerWidth,
46652
- innerHeight,
46653
- (d) => fadeToMarker(g, d),
46654
- () => fadeReset(g),
46655
- timelineScale,
46656
- tooltip,
46657
- palette
46627
+ const legendInnerG = legendContainer.append("g").attr("transform", `translate(0, ${legendY})`);
46628
+ renderLegendD3(
46629
+ legendInnerG,
46630
+ centralConfig,
46631
+ centralState,
46632
+ palette,
46633
+ isDark,
46634
+ centralCallbacks,
46635
+ width
46658
46636
  );
46637
+ }, recolorEvents2 = function() {
46638
+ const colorTG = currentActiveGroup ?? swimlaneTagGroup ?? null;
46639
+ mainG.selectAll(".tl-event").each(function() {
46640
+ const el = d3Selection22.select(this);
46641
+ const lineNum = el.attr("data-line-number");
46642
+ const ev = lineNum ? eventByLine.get(lineNum) : void 0;
46643
+ if (!ev) return;
46644
+ let color;
46645
+ if (colorTG) {
46646
+ const tagColor = resolveTagColor(
46647
+ ev.metadata,
46648
+ parsed.timelineTagGroups,
46649
+ colorTG
46650
+ );
46651
+ color = tagColor ?? (ev.group && groupColorMap.has(ev.group) ? groupColorMap.get(ev.group) : textColor);
46652
+ } else {
46653
+ color = ev.group && groupColorMap.has(ev.group) ? groupColorMap.get(ev.group) : textColor;
46654
+ }
46655
+ el.selectAll("rect").attr("fill", shapeFill(palette, color, isDark, { solid })).attr("stroke", color);
46656
+ el.selectAll("circle:not(.tl-event-point-outline)").attr("fill", shapeFill(palette, color, isDark, { solid })).attr("stroke", color);
46657
+ });
46658
+ };
46659
+ var drawSwimlaneIcon3 = drawSwimlaneIcon4, relayout = relayout2, drawLegend = drawLegend2, recolorEvents = recolorEvents2;
46660
+ const legendY = title ? 50 : 10;
46661
+ const legendGroups = parsed.timelineTagGroups.map((g) => {
46662
+ const pillW = measureLegendText(g.name, LG_PILL_FONT_SIZE) + LG_PILL_PAD;
46663
+ const iconSpace = viewMode ? 8 : LG_ICON_W + 4;
46664
+ let entryX = LG_CAPSULE_PAD + pillW + iconSpace;
46665
+ for (const entry of g.entries) {
46666
+ const textX = entryX + LG_DOT_R * 2 + LG_ENTRY_DOT_GAP;
46667
+ entryX = textX + measureLegendText(entry.value, LG_ENTRY_FONT_SIZE) + LG_ENTRY_TRAIL;
46668
+ }
46669
+ return {
46670
+ group: g,
46671
+ minifiedWidth: pillW,
46672
+ expandedWidth: entryX + LG_CAPSULE_PAD
46673
+ };
46674
+ });
46675
+ let currentActiveGroup = activeTagGroup ?? null;
46676
+ let currentSwimlaneGroup = swimlaneTagGroup ?? null;
46677
+ const eventByLine = /* @__PURE__ */ new Map();
46678
+ for (const ev of timelineEvents) {
46679
+ eventByLine.set(String(ev.lineNumber), ev);
46680
+ }
46681
+ drawLegend2();
46682
+ }
46683
+ }
46684
+ function renderTimelineHorizontalTimeSort(container, parsed, palette, isDark, setup, hovers, onClickItem, _exportDims, _swimlaneTagGroup, _activeTagGroup, _onTagStateChange, _viewMode) {
46685
+ const {
46686
+ width,
46687
+ height,
46688
+ tooltip,
46689
+ solid,
46690
+ textColor,
46691
+ bgColor,
46692
+ bg,
46693
+ groupColorMap,
46694
+ eventColor,
46695
+ minDate,
46696
+ maxDate,
46697
+ datePadding,
46698
+ earliestStartDateStr,
46699
+ latestEndDateStr,
46700
+ tagLegendReserve
46701
+ } = setup;
46702
+ const { fadeToGroup, fadeToEra, fadeToMarker, fadeReset, setTagAttrs } = hovers;
46703
+ const {
46704
+ timelineEvents,
46705
+ timelineGroups,
46706
+ timelineEras,
46707
+ timelineMarkers,
46708
+ timelineScale
46709
+ } = parsed;
46710
+ const title = parsed.noTitle ? null : parsed.title;
46711
+ const BAR_H2 = 22;
46712
+ const sorted = timelineEvents.slice().sort((a, b) => parseTimelineDate(a.date) - parseTimelineDate(b.date));
46713
+ const scaleMargin = timelineScale ? 24 : 0;
46714
+ const ERA_ROW_H = 22;
46715
+ const MARKER_ROW_H = 22;
46716
+ const eraReserve = timelineEras.length > 0 ? ERA_ROW_H : 0;
46717
+ const markerReserve = timelineMarkers.length > 0 ? MARKER_ROW_H : 0;
46718
+ const topScaleH = timelineScale ? 40 : 0;
46719
+ const margin = {
46720
+ top: 104 + topScaleH + eraReserve + markerReserve + tagLegendReserve,
46721
+ right: 40,
46722
+ bottom: 40 + scaleMargin,
46723
+ left: 60
46724
+ };
46725
+ const markerLabelY = markerReserve ? -(topScaleH + MARKER_ROW_H / 2) : 0;
46726
+ const eraLabelY = eraReserve ? -(topScaleH + markerReserve + ERA_ROW_H / 2) : 0;
46727
+ const innerWidth = width - margin.left - margin.right;
46728
+ const innerHeight = height - margin.top - margin.bottom;
46729
+ const rowH = Math.min(28, innerHeight / sorted.length);
46730
+ const xScale = d3Scale2.scaleLinear().domain([minDate - datePadding, maxDate + datePadding]).range([0, innerWidth]);
46731
+ const svg = d3Selection22.select(container).append("svg").attr("width", width).attr("height", height).style("background", bgColor);
46732
+ const g = svg.append("g").attr("transform", `translate(${margin.left},${margin.top})`);
46733
+ renderChartTitle(
46734
+ svg,
46735
+ title,
46736
+ parsed.titleLineNumber,
46737
+ width,
46738
+ textColor,
46739
+ onClickItem
46740
+ );
46741
+ renderEras(
46742
+ g,
46743
+ timelineEras,
46744
+ xScale,
46745
+ false,
46746
+ innerWidth,
46747
+ innerHeight,
46748
+ (s, e) => fadeToEra(g, s, e),
46749
+ () => fadeReset(g),
46750
+ timelineScale,
46751
+ tooltip,
46752
+ palette,
46753
+ eraReserve ? eraLabelY : void 0
46754
+ );
46755
+ renderMarkers(
46756
+ g,
46757
+ timelineMarkers,
46758
+ xScale,
46759
+ false,
46760
+ innerWidth,
46761
+ innerHeight,
46762
+ (d) => fadeToMarker(g, d),
46763
+ () => fadeReset(g),
46764
+ timelineScale,
46765
+ tooltip,
46766
+ palette,
46767
+ markerReserve ? markerLabelY : void 0
46768
+ );
46769
+ if (timelineScale) {
46770
+ renderTimeScale(
46771
+ g,
46772
+ xScale,
46773
+ false,
46774
+ innerWidth,
46775
+ innerHeight,
46776
+ textColor,
46777
+ minDate,
46778
+ maxDate,
46779
+ formatBoundaryLabel(earliestStartDateStr, latestEndDateStr),
46780
+ formatBoundaryLabel(latestEndDateStr, earliestStartDateStr)
46781
+ );
46782
+ }
46783
+ if (timelineGroups.length > 0) {
46784
+ const legendY = timelineScale ? -75 : -55;
46785
+ renderTimelineGroupLegend(
46786
+ g,
46787
+ timelineGroups,
46788
+ groupColorMap,
46789
+ textColor,
46790
+ palette,
46791
+ isDark,
46792
+ legendY,
46793
+ (name) => fadeToGroup(g, name),
46794
+ () => fadeReset(g)
46795
+ );
46796
+ }
46797
+ sorted.forEach((ev, i) => {
46798
+ const y = i * rowH + rowH / 2;
46799
+ const x = xScale(parseTimelineDate(ev.date));
46800
+ const color = eventColor(ev);
46801
+ 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(
46802
+ "data-end-date",
46803
+ ev.endDate ? String(parseTimelineDate(ev.endDate)) : null
46804
+ ).style("cursor", "pointer").on("mouseenter", function(event) {
46805
+ if (ev.group && timelineGroups.length > 0) fadeToGroup(g, ev.group);
46659
46806
  if (timelineScale) {
46660
- renderTimeScale(
46807
+ showEventDatesOnScale(
46661
46808
  g,
46662
- yScale,
46663
- true,
46664
- innerWidth,
46809
+ xScale,
46810
+ ev.date,
46811
+ ev.endDate,
46665
46812
  innerHeight,
46666
- textColor,
46667
- minDate,
46668
- maxDate,
46669
- formatBoundaryLabel(earliestStartDateStr, latestEndDateStr),
46670
- formatBoundaryLabel(latestEndDateStr, earliestStartDateStr)
46813
+ color
46671
46814
  );
46815
+ } else {
46816
+ showTooltip(tooltip, buildEventTooltipHtml(ev), event);
46672
46817
  }
46673
- if (timelineGroups.length > 0) {
46674
- renderTimelineGroupLegend(
46675
- g,
46676
- timelineGroups,
46677
- groupColorMap,
46678
- textColor,
46679
- palette,
46680
- isDark,
46681
- -55,
46682
- (name) => fadeToGroup(g, name),
46683
- () => fadeReset(g)
46684
- );
46818
+ }).on("mouseleave", function() {
46819
+ fadeReset(g);
46820
+ if (timelineScale) {
46821
+ hideEventDatesOnScale(g);
46822
+ } else {
46823
+ hideTooltip(tooltip);
46685
46824
  }
46686
- 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");
46687
- for (const ev of sorted) {
46688
- const y = yScale(parseTimelineDate(ev.date));
46689
- const color = eventColor(ev);
46690
- 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(
46691
- "data-end-date",
46692
- ev.endDate ? String(parseTimelineDate(ev.endDate)) : null
46693
- ).style("cursor", "pointer").on("mouseenter", function(event) {
46694
- if (ev.group && timelineGroups.length > 0) fadeToGroup(g, ev.group);
46825
+ }).on("mousemove", function(event) {
46826
+ if (!timelineScale) {
46827
+ showTooltip(tooltip, buildEventTooltipHtml(ev), event);
46828
+ }
46829
+ }).on("click", () => {
46830
+ if (onClickItem && ev.lineNumber) onClickItem(ev.lineNumber);
46831
+ });
46832
+ setTagAttrs(evG, ev);
46833
+ if (ev.endDate) {
46834
+ const x2 = xScale(parseTimelineDate(ev.endDate));
46835
+ const rectW = Math.max(x2 - x, 4);
46836
+ const estLabelWidth = ev.label.length * 7 + 16;
46837
+ const labelFitsInside = rectW >= estLabelWidth;
46838
+ let fill2 = shapeFill(palette, color, isDark, { solid });
46839
+ let stroke2 = color;
46840
+ if (ev.uncertain) {
46841
+ const gradientId = `uncertain-ts-${ev.lineNumber}`;
46842
+ const strokeGradientId = `uncertain-ts-s-${ev.lineNumber}`;
46843
+ const defs = svg.select("defs").node() || svg.append("defs").node();
46844
+ const defsEl = d3Selection22.select(defs);
46845
+ defsEl.append("linearGradient").attr("id", gradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "100%").attr("y2", "0%").selectAll("stop").data([
46846
+ { offset: "0%", opacity: 1 },
46847
+ { offset: "80%", opacity: 1 },
46848
+ { offset: "100%", opacity: 0 }
46849
+ ]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", mix(color, bg, 30)).attr("stop-opacity", (d) => d.opacity);
46850
+ defsEl.append("linearGradient").attr("id", strokeGradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "100%").attr("y2", "0%").selectAll("stop").data([
46851
+ { offset: "0%", opacity: 1 },
46852
+ { offset: "80%", opacity: 1 },
46853
+ { offset: "100%", opacity: 0 }
46854
+ ]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", color).attr("stop-opacity", (d) => d.opacity);
46855
+ fill2 = `url(#${gradientId})`;
46856
+ stroke2 = `url(#${strokeGradientId})`;
46857
+ }
46858
+ 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);
46859
+ if (labelFitsInside) {
46860
+ 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);
46861
+ } else {
46862
+ const wouldFlipLeft = x + rectW > innerWidth * 0.6;
46863
+ const labelFitsLeft = x - 6 - estLabelWidth > 0;
46864
+ const flipLeft = wouldFlipLeft && labelFitsLeft;
46865
+ 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);
46866
+ }
46867
+ } else {
46868
+ const estLabelWidth = ev.label.length * 7;
46869
+ const wouldFlipLeft = x > innerWidth * 0.6;
46870
+ const labelFitsLeft = x - 10 - estLabelWidth > 0;
46871
+ const flipLeft = wouldFlipLeft && labelFitsLeft;
46872
+ 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);
46873
+ 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);
46874
+ }
46875
+ });
46876
+ }
46877
+ function renderTimelineHorizontalGrouped(container, parsed, palette, isDark, setup, hovers, onClickItem, _exportDims, _swimlaneTagGroup, _activeTagGroup, _onTagStateChange, _viewMode) {
46878
+ const {
46879
+ width,
46880
+ height,
46881
+ tooltip,
46882
+ solid,
46883
+ textColor,
46884
+ bgColor,
46885
+ bg,
46886
+ groupColorMap,
46887
+ tagLanes,
46888
+ eventColor,
46889
+ minDate,
46890
+ maxDate,
46891
+ datePadding,
46892
+ earliestStartDateStr,
46893
+ latestEndDateStr,
46894
+ tagLegendReserve
46895
+ } = setup;
46896
+ const { fadeToGroup, fadeToEra, fadeToMarker, fadeReset, setTagAttrs } = hovers;
46897
+ const {
46898
+ timelineEvents,
46899
+ timelineGroups,
46900
+ timelineEras,
46901
+ timelineMarkers,
46902
+ timelineScale,
46903
+ timelineSwimlanes
46904
+ } = parsed;
46905
+ const title = parsed.noTitle ? null : parsed.title;
46906
+ const BAR_H2 = 22;
46907
+ const GROUP_GAP3 = 12;
46908
+ let lanes;
46909
+ if (tagLanes) {
46910
+ lanes = tagLanes;
46911
+ } else {
46912
+ const groupNames = timelineGroups.map((gr) => gr.name);
46913
+ const ungroupedEvents = timelineEvents.filter(
46914
+ (ev) => ev.group === null || !groupNames.includes(ev.group)
46915
+ );
46916
+ const laneNames = ungroupedEvents.length > 0 ? [...groupNames, "(Other)"] : groupNames;
46917
+ lanes = laneNames.map((name) => ({
46918
+ name,
46919
+ events: timelineEvents.filter(
46920
+ (ev) => name === "(Other)" ? ev.group === null || !groupNames.includes(ev.group) : ev.group === name
46921
+ )
46922
+ }));
46923
+ }
46924
+ const totalEventRows = lanes.reduce((s, l) => s + l.events.length, 0);
46925
+ const scaleMargin = timelineScale ? 24 : 0;
46926
+ const ERA_ROW_H = 22;
46927
+ const MARKER_ROW_H = 22;
46928
+ const eraReserve = timelineEras.length > 0 ? ERA_ROW_H : 0;
46929
+ const markerReserve = timelineMarkers.length > 0 ? MARKER_ROW_H : 0;
46930
+ const topScaleH = timelineScale ? 40 : 0;
46931
+ const maxGroupNameLen = Math.max(...lanes.map((l) => l.name.length));
46932
+ const dynamicLeftMargin = Math.max(120, maxGroupNameLen * 7 + 30);
46933
+ const baseTopMargin = title ? 50 : 20;
46934
+ const margin = {
46935
+ top: baseTopMargin + topScaleH + eraReserve + markerReserve + tagLegendReserve,
46936
+ right: 40,
46937
+ bottom: 40 + scaleMargin,
46938
+ left: dynamicLeftMargin
46939
+ };
46940
+ const markerLabelY = markerReserve ? -(topScaleH + MARKER_ROW_H / 2) : 0;
46941
+ const eraLabelY = eraReserve ? -(topScaleH + markerReserve + ERA_ROW_H / 2) : 0;
46942
+ const innerWidth = width - margin.left - margin.right;
46943
+ const innerHeight = height - margin.top - margin.bottom;
46944
+ const totalGaps = (lanes.length - 1) * GROUP_GAP3;
46945
+ const rowH = Math.min(28, (innerHeight - totalGaps) / totalEventRows);
46946
+ const xScale = d3Scale2.scaleLinear().domain([minDate - datePadding, maxDate + datePadding]).range([0, innerWidth]);
46947
+ const svg = d3Selection22.select(container).append("svg").attr("width", width).attr("height", height).style("background", bgColor);
46948
+ const g = svg.append("g").attr("transform", `translate(${margin.left},${margin.top})`);
46949
+ renderChartTitle(
46950
+ svg,
46951
+ title,
46952
+ parsed.titleLineNumber,
46953
+ width,
46954
+ textColor,
46955
+ onClickItem
46956
+ );
46957
+ renderEras(
46958
+ g,
46959
+ timelineEras,
46960
+ xScale,
46961
+ false,
46962
+ innerWidth,
46963
+ innerHeight,
46964
+ (s, e) => fadeToEra(g, s, e),
46965
+ () => fadeReset(g),
46966
+ timelineScale,
46967
+ tooltip,
46968
+ palette,
46969
+ eraReserve ? eraLabelY : void 0
46970
+ );
46971
+ renderMarkers(
46972
+ g,
46973
+ timelineMarkers,
46974
+ xScale,
46975
+ false,
46976
+ innerWidth,
46977
+ innerHeight,
46978
+ (d) => fadeToMarker(g, d),
46979
+ () => fadeReset(g),
46980
+ timelineScale,
46981
+ tooltip,
46982
+ palette,
46983
+ markerReserve ? markerLabelY : void 0
46984
+ );
46985
+ if (timelineScale) {
46986
+ renderTimeScale(
46987
+ g,
46988
+ xScale,
46989
+ false,
46990
+ innerWidth,
46991
+ innerHeight,
46992
+ textColor,
46993
+ minDate,
46994
+ maxDate,
46995
+ formatBoundaryLabel(earliestStartDateStr, latestEndDateStr),
46996
+ formatBoundaryLabel(latestEndDateStr, earliestStartDateStr)
46997
+ );
46998
+ }
46999
+ let curY = 0;
47000
+ if (timelineSwimlanes || tagLanes) {
47001
+ let swimY = 0;
47002
+ lanes.forEach((lane, idx) => {
47003
+ const laneSpan = lane.events.length * rowH;
47004
+ const fillColor = idx % 2 === 0 ? textColor : "transparent";
47005
+ 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);
47006
+ swimY += laneSpan + GROUP_GAP3;
47007
+ });
47008
+ }
47009
+ for (const lane of lanes) {
47010
+ const laneColor = groupColorMap.get(lane.name) ?? textColor;
47011
+ const laneSpan = lane.events.length * rowH;
47012
+ const group = timelineGroups.find((grp) => grp.name === lane.name);
47013
+ 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", () => {
47014
+ if (onClickItem && group?.lineNumber) onClickItem(group.lineNumber);
47015
+ });
47016
+ 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);
47017
+ lane.events.forEach((ev, i) => {
47018
+ const y = curY + i * rowH + rowH / 2;
47019
+ const x = xScale(parseTimelineDate(ev.date));
47020
+ 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(
47021
+ "data-end-date",
47022
+ ev.endDate ? String(parseTimelineDate(ev.endDate)) : null
47023
+ ).style("cursor", "pointer").on("mouseenter", function(event) {
47024
+ fadeToGroup(g, lane.name);
47025
+ if (timelineScale) {
47026
+ showEventDatesOnScale(
47027
+ g,
47028
+ xScale,
47029
+ ev.date,
47030
+ ev.endDate,
47031
+ innerHeight,
47032
+ laneColor
47033
+ );
47034
+ } else {
46695
47035
  showTooltip(tooltip, buildEventTooltipHtml(ev), event);
46696
- }).on("mouseleave", function() {
46697
- fadeReset(g);
47036
+ }
47037
+ }).on("mouseleave", function() {
47038
+ fadeReset(g);
47039
+ if (timelineScale) {
47040
+ hideEventDatesOnScale(g);
47041
+ } else {
46698
47042
  hideTooltip(tooltip);
46699
- }).on("mousemove", function(event) {
47043
+ }
47044
+ }).on("mousemove", function(event) {
47045
+ if (!timelineScale) {
46700
47046
  showTooltip(tooltip, buildEventTooltipHtml(ev), event);
46701
- }).on("click", () => {
46702
- if (onClickItem && ev.lineNumber) onClickItem(ev.lineNumber);
46703
- });
46704
- setTagAttrs(evG, ev);
46705
- if (ev.endDate) {
46706
- const y2 = yScale(parseTimelineDate(ev.endDate));
46707
- const rectH = Math.max(y2 - y, 4);
46708
- let fill2 = shapeFill(palette, color, isDark, { solid });
46709
- let stroke2 = color;
46710
- if (ev.uncertain) {
46711
- const gradientId = `uncertain-v-${ev.lineNumber}`;
46712
- const strokeGradientId = `uncertain-v-s-${ev.lineNumber}`;
46713
- const defs = svg.select("defs").node() || svg.append("defs").node();
46714
- const defsEl = d3Selection22.select(defs);
46715
- defsEl.append("linearGradient").attr("id", gradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "0%").attr("y2", "100%").selectAll("stop").data([
46716
- { offset: "0%", opacity: 1 },
46717
- { offset: "80%", opacity: 1 },
46718
- { offset: "100%", opacity: 0 }
46719
- ]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", mix(color, bg, 30)).attr("stop-opacity", (d) => d.opacity);
46720
- defsEl.append("linearGradient").attr("id", strokeGradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "0%").attr("y2", "100%").selectAll("stop").data([
46721
- { offset: "0%", opacity: 1 },
46722
- { offset: "80%", opacity: 1 },
46723
- { offset: "100%", opacity: 0 }
46724
- ]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", color).attr("stop-opacity", (d) => d.opacity);
46725
- fill2 = `url(#${gradientId})`;
46726
- stroke2 = `url(#${strokeGradientId})`;
46727
- }
46728
- 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);
46729
- 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);
47047
+ }
47048
+ }).on("click", () => {
47049
+ if (onClickItem && ev.lineNumber) onClickItem(ev.lineNumber);
47050
+ });
47051
+ setTagAttrs(evG, ev);
47052
+ const evColor = eventColor(ev);
47053
+ if (ev.endDate) {
47054
+ const x2 = xScale(parseTimelineDate(ev.endDate));
47055
+ const rectW = Math.max(x2 - x, 4);
47056
+ const estLabelWidth = ev.label.length * 7 + 16;
47057
+ const labelFitsInside = rectW >= estLabelWidth;
47058
+ let fill2 = shapeFill(palette, evColor, isDark, { solid });
47059
+ let stroke2 = evColor;
47060
+ if (ev.uncertain) {
47061
+ const gradientId = `uncertain-${ev.lineNumber}`;
47062
+ const strokeGradientId = `uncertain-s-${ev.lineNumber}`;
47063
+ const defs = svg.select("defs").node() || svg.append("defs").node();
47064
+ const defsEl = d3Selection22.select(defs);
47065
+ defsEl.append("linearGradient").attr("id", gradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "100%").attr("y2", "0%").selectAll("stop").data([
47066
+ { offset: "0%", opacity: 1 },
47067
+ { offset: "80%", opacity: 1 },
47068
+ { offset: "100%", opacity: 0 }
47069
+ ]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", mix(evColor, bg, 30)).attr("stop-opacity", (d) => d.opacity);
47070
+ defsEl.append("linearGradient").attr("id", strokeGradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "100%").attr("y2", "0%").selectAll("stop").data([
47071
+ { offset: "0%", opacity: 1 },
47072
+ { offset: "80%", opacity: 1 },
47073
+ { offset: "100%", opacity: 0 }
47074
+ ]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", evColor).attr("stop-opacity", (d) => d.opacity);
47075
+ fill2 = `url(#${gradientId})`;
47076
+ stroke2 = `url(#${strokeGradientId})`;
47077
+ }
47078
+ 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);
47079
+ if (labelFitsInside) {
47080
+ 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);
46730
47081
  } else {
46731
- 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);
46732
- evG.append("text").attr("x", axisX + 16).attr("y", y).attr("dy", "0.35em").attr("fill", textColor).attr("font-size", "11px").text(ev.label);
47082
+ const wouldFlipLeft = x + rectW > innerWidth * 0.6;
47083
+ const labelFitsLeft = x - 6 - estLabelWidth > 0;
47084
+ const flipLeft = wouldFlipLeft && labelFitsLeft;
47085
+ 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);
46733
47086
  }
46734
- evG.append("text").attr("x", axisX - 14).attr(
46735
- "y",
46736
- ev.endDate ? yScale(parseTimelineDate(ev.date)) + Math.max(
46737
- yScale(parseTimelineDate(ev.endDate)) - yScale(parseTimelineDate(ev.date)),
46738
- 4
46739
- ) / 2 : y
46740
- ).attr("dy", "0.35em").attr("text-anchor", "end").attr("fill", mutedColor).attr("font-size", "10px").text(ev.date + (ev.endDate ? `\u2192${ev.endDate}` : ""));
47087
+ } else {
47088
+ const estLabelWidth = ev.label.length * 7;
47089
+ const wouldFlipLeft = x > innerWidth * 0.6;
47090
+ const labelFitsLeft = x - 10 - estLabelWidth > 0;
47091
+ const flipLeft = wouldFlipLeft && labelFitsLeft;
47092
+ 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);
47093
+ 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);
46741
47094
  }
46742
- }
46743
- return;
47095
+ });
47096
+ curY += laneSpan + GROUP_GAP3;
46744
47097
  }
46745
- const BAR_H2 = 22;
46746
- const GROUP_GAP3 = 12;
46747
- const useGroupedHorizontal = tagLanes != null || timelineSort === "group" && timelineGroups.length > 0;
46748
- if (useGroupedHorizontal) {
46749
- let lanes;
47098
+ }
47099
+ function renderTimelineVertical(container, parsed, palette, isDark, setup, hovers, onClickItem, exportDims, _swimlaneTagGroup, _activeTagGroup, _onTagStateChange, _viewMode) {
47100
+ const {
47101
+ width,
47102
+ height,
47103
+ tooltip,
47104
+ solid,
47105
+ textColor,
47106
+ mutedColor,
47107
+ bgColor,
47108
+ bg,
47109
+ groupColorMap,
47110
+ tagLanes,
47111
+ eventColor,
47112
+ minDate,
47113
+ maxDate,
47114
+ datePadding,
47115
+ earliestStartDateStr,
47116
+ latestEndDateStr,
47117
+ tagLegendReserve
47118
+ } = setup;
47119
+ const { fadeToGroup, fadeToEra, fadeToMarker, fadeReset, setTagAttrs } = hovers;
47120
+ const {
47121
+ timelineEvents,
47122
+ timelineGroups,
47123
+ timelineEras,
47124
+ timelineMarkers,
47125
+ timelineSort,
47126
+ timelineScale,
47127
+ timelineSwimlanes
47128
+ } = parsed;
47129
+ const title = parsed.noTitle ? null : parsed.title;
47130
+ const useGroupedVertical = tagLanes != null || timelineSort === "group" && timelineGroups.length > 0;
47131
+ if (useGroupedVertical) {
47132
+ let laneNames;
47133
+ let laneEventsByName;
46750
47134
  if (tagLanes) {
46751
- lanes = tagLanes;
47135
+ laneNames = tagLanes.map((l) => l.name);
47136
+ laneEventsByName = new Map(tagLanes.map((l) => [l.name, l.events]));
46752
47137
  } else {
46753
47138
  const groupNames = timelineGroups.map((gr) => gr.name);
46754
47139
  const ungroupedEvents = timelineEvents.filter(
46755
47140
  (ev) => ev.group === null || !groupNames.includes(ev.group)
46756
47141
  );
46757
- const laneNames = ungroupedEvents.length > 0 ? [...groupNames, "(Other)"] : groupNames;
46758
- lanes = laneNames.map((name) => ({
46759
- name,
46760
- events: timelineEvents.filter(
46761
- (ev) => name === "(Other)" ? ev.group === null || !groupNames.includes(ev.group) : ev.group === name
46762
- )
46763
- }));
47142
+ laneNames = ungroupedEvents.length > 0 ? [...groupNames, "(Other)"] : groupNames;
47143
+ laneEventsByName = new Map(
47144
+ laneNames.map((name) => [
47145
+ name,
47146
+ timelineEvents.filter(
47147
+ (ev) => name === "(Other)" ? ev.group === null || !groupNames.includes(ev.group) : ev.group === name
47148
+ )
47149
+ ])
47150
+ );
46764
47151
  }
46765
- const totalEventRows = lanes.reduce((s, l) => s + l.events.length, 0);
46766
- const scaleMargin = timelineScale ? 24 : 0;
46767
- const ERA_ROW_H = 22;
46768
- const MARKER_ROW_H = 22;
46769
- const eraReserve = timelineEras.length > 0 ? ERA_ROW_H : 0;
46770
- const markerReserve = timelineMarkers.length > 0 ? MARKER_ROW_H : 0;
46771
- const topScaleH = timelineScale ? 40 : 0;
46772
- const maxGroupNameLen = Math.max(...lanes.map((l) => l.name.length));
46773
- const dynamicLeftMargin = Math.max(120, maxGroupNameLen * 7 + 30);
46774
- const baseTopMargin = title ? 50 : 20;
47152
+ const laneCount = laneNames.length;
47153
+ const scaleMargin = timelineScale ? 40 : 0;
47154
+ const markerMargin = timelineMarkers.length > 0 ? 30 : 0;
46775
47155
  const margin = {
46776
- top: baseTopMargin + topScaleH + eraReserve + markerReserve + tagLegendReserve,
46777
- right: 40,
46778
- bottom: 40 + scaleMargin,
46779
- left: dynamicLeftMargin
47156
+ top: 104 + markerMargin + tagLegendReserve,
47157
+ right: 40 + scaleMargin,
47158
+ bottom: 40,
47159
+ left: 60 + scaleMargin
46780
47160
  };
46781
- const markerLabelY = markerReserve ? -(topScaleH + MARKER_ROW_H / 2) : 0;
46782
- const eraLabelY = eraReserve ? -(topScaleH + markerReserve + ERA_ROW_H / 2) : 0;
46783
47161
  const innerWidth = width - margin.left - margin.right;
46784
47162
  const innerHeight = height - margin.top - margin.bottom;
46785
- const totalGaps = (lanes.length - 1) * GROUP_GAP3;
46786
- const rowH = Math.min(28, (innerHeight - totalGaps) / totalEventRows);
46787
- const xScale = d3Scale2.scaleLinear().domain([minDate - datePadding, maxDate + datePadding]).range([0, innerWidth]);
46788
- const svg = d3Selection22.select(container).append("svg").attr("width", width).attr("height", height).style("background", bgColor);
47163
+ const laneWidth = innerWidth / laneCount;
47164
+ const yScale = d3Scale2.scaleLinear().domain([minDate - datePadding, maxDate + datePadding]).range([0, innerHeight]);
47165
+ 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);
46789
47166
  const g = svg.append("g").attr("transform", `translate(${margin.left},${margin.top})`);
46790
47167
  renderChartTitle(
46791
47168
  svg,
@@ -46798,36 +47175,34 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
46798
47175
  renderEras(
46799
47176
  g,
46800
47177
  timelineEras,
46801
- xScale,
46802
- false,
47178
+ yScale,
47179
+ true,
46803
47180
  innerWidth,
46804
47181
  innerHeight,
46805
47182
  (s, e) => fadeToEra(g, s, e),
46806
47183
  () => fadeReset(g),
46807
47184
  timelineScale,
46808
47185
  tooltip,
46809
- palette,
46810
- eraReserve ? eraLabelY : void 0
47186
+ palette
46811
47187
  );
46812
47188
  renderMarkers(
46813
47189
  g,
46814
47190
  timelineMarkers,
46815
- xScale,
46816
- false,
47191
+ yScale,
47192
+ true,
46817
47193
  innerWidth,
46818
47194
  innerHeight,
46819
47195
  (d) => fadeToMarker(g, d),
46820
47196
  () => fadeReset(g),
46821
47197
  timelineScale,
46822
47198
  tooltip,
46823
- palette,
46824
- markerReserve ? markerLabelY : void 0
47199
+ palette
46825
47200
  );
46826
47201
  if (timelineScale) {
46827
47202
  renderTimeScale(
46828
47203
  g,
46829
- xScale,
46830
- false,
47204
+ yScale,
47205
+ true,
46831
47206
  innerWidth,
46832
47207
  innerHeight,
46833
47208
  textColor,
@@ -46837,78 +47212,55 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
46837
47212
  formatBoundaryLabel(latestEndDateStr, earliestStartDateStr)
46838
47213
  );
46839
47214
  }
46840
- let curY = 0;
46841
47215
  if (timelineSwimlanes || tagLanes) {
46842
- let swimY = 0;
46843
- lanes.forEach((lane, idx) => {
46844
- const laneSpan = lane.events.length * rowH;
46845
- const fillColor = idx % 2 === 0 ? textColor : "transparent";
46846
- 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);
46847
- swimY += laneSpan + GROUP_GAP3;
47216
+ laneNames.forEach((laneName, laneIdx) => {
47217
+ const laneX = laneIdx * laneWidth;
47218
+ const fillColor = laneIdx % 2 === 0 ? textColor : "transparent";
47219
+ 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);
46848
47220
  });
46849
47221
  }
46850
- for (const lane of lanes) {
46851
- const laneColor = groupColorMap.get(lane.name) ?? textColor;
46852
- const laneSpan = lane.events.length * rowH;
46853
- const group = timelineGroups.find((grp) => grp.name === lane.name);
46854
- 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", () => {
46855
- if (onClickItem && group?.lineNumber) onClickItem(group.lineNumber);
46856
- });
46857
- 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);
46858
- lane.events.forEach((ev, i) => {
46859
- const y = curY + i * rowH + rowH / 2;
46860
- const x = xScale(parseTimelineDate(ev.date));
46861
- 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(
47222
+ laneNames.forEach((laneName, laneIdx) => {
47223
+ const laneX = laneIdx * laneWidth;
47224
+ const laneColor = groupColorMap.get(laneName) ?? textColor;
47225
+ const laneCenter = laneX + laneWidth / 2;
47226
+ 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));
47227
+ 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);
47228
+ 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");
47229
+ const laneEvents = laneEventsByName.get(laneName) ?? [];
47230
+ for (const ev of laneEvents) {
47231
+ const y = yScale(parseTimelineDate(ev.date));
47232
+ 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(
46862
47233
  "data-end-date",
46863
47234
  ev.endDate ? String(parseTimelineDate(ev.endDate)) : null
46864
47235
  ).style("cursor", "pointer").on("mouseenter", function(event) {
46865
- fadeToGroup(g, lane.name);
46866
- if (timelineScale) {
46867
- showEventDatesOnScale(
46868
- g,
46869
- xScale,
46870
- ev.date,
46871
- ev.endDate,
46872
- innerHeight,
46873
- laneColor
46874
- );
46875
- } else {
46876
- showTooltip(tooltip, buildEventTooltipHtml(ev), event);
46877
- }
47236
+ fadeToGroup(g, laneName);
47237
+ showTooltip(tooltip, buildEventTooltipHtml(ev), event);
46878
47238
  }).on("mouseleave", function() {
46879
47239
  fadeReset(g);
46880
- if (timelineScale) {
46881
- hideEventDatesOnScale(g);
46882
- } else {
46883
- hideTooltip(tooltip);
46884
- }
47240
+ hideTooltip(tooltip);
46885
47241
  }).on("mousemove", function(event) {
46886
- if (!timelineScale) {
46887
- showTooltip(tooltip, buildEventTooltipHtml(ev), event);
46888
- }
47242
+ showTooltip(tooltip, buildEventTooltipHtml(ev), event);
46889
47243
  }).on("click", () => {
46890
47244
  if (onClickItem && ev.lineNumber) onClickItem(ev.lineNumber);
46891
47245
  });
46892
47246
  setTagAttrs(evG, ev);
46893
47247
  const evColor = eventColor(ev);
46894
47248
  if (ev.endDate) {
46895
- const x2 = xScale(parseTimelineDate(ev.endDate));
46896
- const rectW = Math.max(x2 - x, 4);
46897
- const estLabelWidth = ev.label.length * 7 + 16;
46898
- const labelFitsInside = rectW >= estLabelWidth;
47249
+ const y2 = yScale(parseTimelineDate(ev.endDate));
47250
+ const rectH = Math.max(y2 - y, 4);
46899
47251
  let fill2 = shapeFill(palette, evColor, isDark, { solid });
46900
47252
  let stroke2 = evColor;
46901
47253
  if (ev.uncertain) {
46902
- const gradientId = `uncertain-${ev.lineNumber}`;
46903
- const strokeGradientId = `uncertain-s-${ev.lineNumber}`;
47254
+ const gradientId = `uncertain-vg-${ev.lineNumber}`;
47255
+ const strokeGradientId = `uncertain-vg-s-${ev.lineNumber}`;
46904
47256
  const defs = svg.select("defs").node() || svg.append("defs").node();
46905
47257
  const defsEl = d3Selection22.select(defs);
46906
- defsEl.append("linearGradient").attr("id", gradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "100%").attr("y2", "0%").selectAll("stop").data([
47258
+ defsEl.append("linearGradient").attr("id", gradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "0%").attr("y2", "100%").selectAll("stop").data([
46907
47259
  { offset: "0%", opacity: 1 },
46908
47260
  { offset: "80%", opacity: 1 },
46909
47261
  { offset: "100%", opacity: 0 }
46910
- ]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", mix(evColor, bg, 30)).attr("stop-opacity", (d) => d.opacity);
46911
- defsEl.append("linearGradient").attr("id", strokeGradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "100%").attr("y2", "0%").selectAll("stop").data([
47262
+ ]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", mix(laneColor, bg, 30)).attr("stop-opacity", (d) => d.opacity);
47263
+ defsEl.append("linearGradient").attr("id", strokeGradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "0%").attr("y2", "100%").selectAll("stop").data([
46912
47264
  { offset: "0%", opacity: 1 },
46913
47265
  { offset: "80%", opacity: 1 },
46914
47266
  { offset: "100%", opacity: 0 }
@@ -46916,47 +47268,29 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
46916
47268
  fill2 = `url(#${gradientId})`;
46917
47269
  stroke2 = `url(#${strokeGradientId})`;
46918
47270
  }
46919
- 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);
46920
- if (labelFitsInside) {
46921
- 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);
46922
- } else {
46923
- const wouldFlipLeft = x + rectW > innerWidth * 0.6;
46924
- const labelFitsLeft = x - 6 - estLabelWidth > 0;
46925
- const flipLeft = wouldFlipLeft && labelFitsLeft;
46926
- 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);
46927
- }
47271
+ 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);
47272
+ 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);
46928
47273
  } else {
46929
- const estLabelWidth = ev.label.length * 7;
46930
- const wouldFlipLeft = x > innerWidth * 0.6;
46931
- const labelFitsLeft = x - 10 - estLabelWidth > 0;
46932
- const flipLeft = wouldFlipLeft && labelFitsLeft;
46933
- 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);
46934
- 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);
47274
+ 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);
47275
+ evG.append("text").attr("x", laneCenter + 10).attr("y", y).attr("dy", "0.35em").attr("fill", textColor).attr("font-size", "10px").text(ev.label);
46935
47276
  }
46936
- });
46937
- curY += laneSpan + GROUP_GAP3;
46938
- }
47277
+ }
47278
+ });
46939
47279
  } else {
46940
- const sorted = timelineEvents.slice().sort((a, b) => parseTimelineDate(a.date) - parseTimelineDate(b.date));
46941
- const scaleMargin = timelineScale ? 24 : 0;
46942
- const ERA_ROW_H = 22;
46943
- const MARKER_ROW_H = 22;
46944
- const eraReserve = timelineEras.length > 0 ? ERA_ROW_H : 0;
46945
- const markerReserve = timelineMarkers.length > 0 ? MARKER_ROW_H : 0;
46946
- const topScaleH = timelineScale ? 40 : 0;
47280
+ const scaleMargin = timelineScale ? 40 : 0;
47281
+ const markerMargin = timelineMarkers.length > 0 ? 30 : 0;
46947
47282
  const margin = {
46948
- top: 104 + topScaleH + eraReserve + markerReserve + tagLegendReserve,
46949
- right: 40,
46950
- bottom: 40 + scaleMargin,
46951
- left: 60
47283
+ top: 104 + markerMargin + tagLegendReserve,
47284
+ right: 200,
47285
+ bottom: 40,
47286
+ left: 60 + scaleMargin
46952
47287
  };
46953
- const markerLabelY = markerReserve ? -(topScaleH + MARKER_ROW_H / 2) : 0;
46954
- const eraLabelY = eraReserve ? -(topScaleH + markerReserve + ERA_ROW_H / 2) : 0;
46955
47288
  const innerWidth = width - margin.left - margin.right;
46956
47289
  const innerHeight = height - margin.top - margin.bottom;
46957
- const rowH = Math.min(28, innerHeight / sorted.length);
46958
- const xScale = d3Scale2.scaleLinear().domain([minDate - datePadding, maxDate + datePadding]).range([0, innerWidth]);
46959
- const svg = d3Selection22.select(container).append("svg").attr("width", width).attr("height", height).style("background", bgColor);
47290
+ const axisX = 20;
47291
+ const yScale = d3Scale2.scaleLinear().domain([minDate - datePadding, maxDate + datePadding]).range([0, innerHeight]);
47292
+ const sorted = timelineEvents.slice().sort((a, b) => parseTimelineDate(a.date) - parseTimelineDate(b.date));
47293
+ 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);
46960
47294
  const g = svg.append("g").attr("transform", `translate(${margin.left},${margin.top})`);
46961
47295
  renderChartTitle(
46962
47296
  svg,
@@ -46969,36 +47303,34 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
46969
47303
  renderEras(
46970
47304
  g,
46971
47305
  timelineEras,
46972
- xScale,
46973
- false,
47306
+ yScale,
47307
+ true,
46974
47308
  innerWidth,
46975
47309
  innerHeight,
46976
47310
  (s, e) => fadeToEra(g, s, e),
46977
47311
  () => fadeReset(g),
46978
47312
  timelineScale,
46979
47313
  tooltip,
46980
- palette,
46981
- eraReserve ? eraLabelY : void 0
47314
+ palette
46982
47315
  );
46983
47316
  renderMarkers(
46984
47317
  g,
46985
47318
  timelineMarkers,
46986
- xScale,
46987
- false,
47319
+ yScale,
47320
+ true,
46988
47321
  innerWidth,
46989
47322
  innerHeight,
46990
47323
  (d) => fadeToMarker(g, d),
46991
47324
  () => fadeReset(g),
46992
47325
  timelineScale,
46993
47326
  tooltip,
46994
- palette,
46995
- markerReserve ? markerLabelY : void 0
47327
+ palette
46996
47328
  );
46997
47329
  if (timelineScale) {
46998
47330
  renderTimeScale(
46999
47331
  g,
47000
- xScale,
47001
- false,
47332
+ yScale,
47333
+ true,
47002
47334
  innerWidth,
47003
47335
  innerHeight,
47004
47336
  textColor,
@@ -47009,7 +47341,6 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
47009
47341
  );
47010
47342
  }
47011
47343
  if (timelineGroups.length > 0) {
47012
- const legendY = timelineScale ? -75 : -55;
47013
47344
  renderTimelineGroupLegend(
47014
47345
  g,
47015
47346
  timelineGroups,
@@ -47017,65 +47348,46 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
47017
47348
  textColor,
47018
47349
  palette,
47019
47350
  isDark,
47020
- legendY,
47351
+ -55,
47021
47352
  (name) => fadeToGroup(g, name),
47022
47353
  () => fadeReset(g)
47023
47354
  );
47024
47355
  }
47025
- sorted.forEach((ev, i) => {
47026
- const y = i * rowH + rowH / 2;
47027
- const x = xScale(parseTimelineDate(ev.date));
47356
+ 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");
47357
+ for (const ev of sorted) {
47358
+ const y = yScale(parseTimelineDate(ev.date));
47028
47359
  const color = eventColor(ev);
47029
47360
  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(
47030
47361
  "data-end-date",
47031
47362
  ev.endDate ? String(parseTimelineDate(ev.endDate)) : null
47032
47363
  ).style("cursor", "pointer").on("mouseenter", function(event) {
47033
47364
  if (ev.group && timelineGroups.length > 0) fadeToGroup(g, ev.group);
47034
- if (timelineScale) {
47035
- showEventDatesOnScale(
47036
- g,
47037
- xScale,
47038
- ev.date,
47039
- ev.endDate,
47040
- innerHeight,
47041
- color
47042
- );
47043
- } else {
47044
- showTooltip(tooltip, buildEventTooltipHtml(ev), event);
47045
- }
47365
+ showTooltip(tooltip, buildEventTooltipHtml(ev), event);
47046
47366
  }).on("mouseleave", function() {
47047
47367
  fadeReset(g);
47048
- if (timelineScale) {
47049
- hideEventDatesOnScale(g);
47050
- } else {
47051
- hideTooltip(tooltip);
47052
- }
47368
+ hideTooltip(tooltip);
47053
47369
  }).on("mousemove", function(event) {
47054
- if (!timelineScale) {
47055
- showTooltip(tooltip, buildEventTooltipHtml(ev), event);
47056
- }
47370
+ showTooltip(tooltip, buildEventTooltipHtml(ev), event);
47057
47371
  }).on("click", () => {
47058
47372
  if (onClickItem && ev.lineNumber) onClickItem(ev.lineNumber);
47059
47373
  });
47060
47374
  setTagAttrs(evG, ev);
47061
47375
  if (ev.endDate) {
47062
- const x2 = xScale(parseTimelineDate(ev.endDate));
47063
- const rectW = Math.max(x2 - x, 4);
47064
- const estLabelWidth = ev.label.length * 7 + 16;
47065
- const labelFitsInside = rectW >= estLabelWidth;
47376
+ const y2 = yScale(parseTimelineDate(ev.endDate));
47377
+ const rectH = Math.max(y2 - y, 4);
47066
47378
  let fill2 = shapeFill(palette, color, isDark, { solid });
47067
47379
  let stroke2 = color;
47068
47380
  if (ev.uncertain) {
47069
- const gradientId = `uncertain-ts-${ev.lineNumber}`;
47070
- const strokeGradientId = `uncertain-ts-s-${ev.lineNumber}`;
47381
+ const gradientId = `uncertain-v-${ev.lineNumber}`;
47382
+ const strokeGradientId = `uncertain-v-s-${ev.lineNumber}`;
47071
47383
  const defs = svg.select("defs").node() || svg.append("defs").node();
47072
47384
  const defsEl = d3Selection22.select(defs);
47073
- defsEl.append("linearGradient").attr("id", gradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "100%").attr("y2", "0%").selectAll("stop").data([
47385
+ defsEl.append("linearGradient").attr("id", gradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "0%").attr("y2", "100%").selectAll("stop").data([
47074
47386
  { offset: "0%", opacity: 1 },
47075
47387
  { offset: "80%", opacity: 1 },
47076
47388
  { offset: "100%", opacity: 0 }
47077
47389
  ]).enter().append("stop").attr("offset", (d) => d.offset).attr("stop-color", mix(color, bg, 30)).attr("stop-opacity", (d) => d.opacity);
47078
- defsEl.append("linearGradient").attr("id", strokeGradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "100%").attr("y2", "0%").selectAll("stop").data([
47390
+ defsEl.append("linearGradient").attr("id", strokeGradientId).attr("x1", "0%").attr("y1", "0%").attr("x2", "0%").attr("y2", "100%").selectAll("stop").data([
47079
47391
  { offset: "0%", opacity: 1 },
47080
47392
  { offset: "80%", opacity: 1 },
47081
47393
  { offset: "100%", opacity: 0 }
@@ -47083,206 +47395,100 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
47083
47395
  fill2 = `url(#${gradientId})`;
47084
47396
  stroke2 = `url(#${strokeGradientId})`;
47085
47397
  }
47086
- 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);
47087
- if (labelFitsInside) {
47088
- 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);
47089
- } else {
47090
- const wouldFlipLeft = x + rectW > innerWidth * 0.6;
47091
- const labelFitsLeft = x - 6 - estLabelWidth > 0;
47092
- const flipLeft = wouldFlipLeft && labelFitsLeft;
47093
- 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);
47094
- }
47398
+ 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);
47399
+ 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);
47095
47400
  } else {
47096
- const estLabelWidth = ev.label.length * 7;
47097
- const wouldFlipLeft = x > innerWidth * 0.6;
47098
- const labelFitsLeft = x - 10 - estLabelWidth > 0;
47099
- const flipLeft = wouldFlipLeft && labelFitsLeft;
47100
- 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);
47101
- 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);
47401
+ 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);
47402
+ evG.append("text").attr("x", axisX + 16).attr("y", y).attr("dy", "0.35em").attr("fill", textColor).attr("font-size", "11px").text(ev.label);
47102
47403
  }
47103
- });
47104
- }
47105
- if (parsed.timelineTagGroups.length > 0) {
47106
- const LG_HEIGHT = LEGEND_HEIGHT;
47107
- const LG_PILL_PAD = LEGEND_PILL_PAD;
47108
- const LG_PILL_FONT_SIZE = LEGEND_PILL_FONT_SIZE;
47109
- const LG_CAPSULE_PAD = LEGEND_CAPSULE_PAD;
47110
- const LG_DOT_R = LEGEND_DOT_R;
47111
- const LG_ENTRY_FONT_SIZE = LEGEND_ENTRY_FONT_SIZE;
47112
- const LG_ENTRY_DOT_GAP = LEGEND_ENTRY_DOT_GAP;
47113
- const LG_ENTRY_TRAIL = LEGEND_ENTRY_TRAIL;
47114
- const LG_ICON_W = 20;
47115
- const mainSvg = d3Selection22.select(container).select("svg");
47116
- const mainG = mainSvg.select("g");
47117
- if (!mainSvg.empty() && !mainG.empty()) {
47118
- let drawSwimlaneIcon4 = function(parent, x, y, isSwimActive) {
47119
- const iconG = parent.append("g").attr("class", "tl-swimlane-icon").attr("transform", `translate(${x}, ${y})`).style("cursor", "pointer");
47120
- const barColor = isSwimActive ? palette.primary : palette.textMuted;
47121
- const barOpacity = isSwimActive ? 1 : 0.35;
47122
- const bars = [
47123
- { y: 0, w: 8 },
47124
- { y: 4, w: 12 },
47125
- { y: 8, w: 6 }
47126
- ];
47127
- for (const bar of bars) {
47128
- 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);
47129
- }
47130
- return iconG;
47131
- }, relayout2 = function() {
47132
- renderTimeline(
47133
- container,
47134
- parsed,
47135
- palette,
47136
- isDark,
47137
- onClickItem,
47138
- exportDims,
47139
- currentActiveGroup,
47140
- currentSwimlaneGroup,
47141
- onTagStateChange,
47142
- viewMode
47143
- );
47144
- }, drawLegend2 = function() {
47145
- mainSvg.selectAll(".tl-tag-legend-group").remove();
47146
- mainSvg.selectAll(".tl-tag-legend-container").remove();
47147
- const effectiveColorKey = (currentActiveGroup ?? currentSwimlaneGroup)?.toLowerCase() ?? null;
47148
- const visibleGroups = viewMode ? legendGroups.filter(
47149
- (lg) => effectiveColorKey != null && lg.group.name.toLowerCase() === effectiveColorKey
47150
- ) : legendGroups;
47151
- if (visibleGroups.length === 0) return;
47152
- const legendContainer = mainSvg.append("g").attr("class", "tl-tag-legend-container");
47153
- if (currentActiveGroup) {
47154
- legendContainer.attr(
47155
- "data-legend-active",
47156
- currentActiveGroup.toLowerCase()
47157
- );
47158
- }
47159
- const iconAddon = viewMode ? 0 : LG_ICON_W;
47160
- const centralGroups = visibleGroups.map((lg) => ({
47161
- name: lg.group.name,
47162
- entries: lg.group.entries.map((e) => ({
47163
- value: e.value,
47164
- color: e.color
47165
- }))
47166
- }));
47167
- const centralActive = viewMode ? effectiveColorKey : currentActiveGroup;
47168
- const centralConfig = {
47169
- groups: centralGroups,
47170
- position: { placement: "top-center", titleRelation: "below-title" },
47171
- mode: "fixed",
47172
- capsulePillAddonWidth: iconAddon
47173
- };
47174
- const centralState = { activeGroup: centralActive };
47175
- const centralCallbacks = viewMode ? {} : {
47176
- onGroupToggle: (groupName) => {
47177
- currentActiveGroup = currentActiveGroup === groupName.toLowerCase() ? null : groupName.toLowerCase();
47178
- drawLegend2();
47179
- recolorEvents2();
47180
- onTagStateChange?.(currentActiveGroup, currentSwimlaneGroup);
47181
- },
47182
- onEntryHover: (groupName, entryValue) => {
47183
- const tagKey = groupName.toLowerCase();
47184
- if (entryValue) {
47185
- const tagVal = entryValue.toLowerCase();
47186
- fadeToTagValue(mainG, tagKey, tagVal);
47187
- mainSvg.selectAll("[data-legend-entry]").each(function() {
47188
- const el = d3Selection22.select(this);
47189
- const ev = el.attr("data-legend-entry");
47190
- const eg = el.attr("data-tag-group") ?? el.node()?.closest?.("[data-tag-group]")?.getAttribute("data-tag-group");
47191
- el.attr(
47192
- "opacity",
47193
- eg === tagKey && ev === tagVal ? 1 : FADE_OPACITY3
47194
- );
47195
- });
47196
- } else {
47197
- fadeReset(mainG);
47198
- mainSvg.selectAll("[data-legend-entry]").attr("opacity", 1);
47199
- }
47200
- },
47201
- onGroupRendered: (groupName, groupEl, isActive) => {
47202
- const groupKey = groupName.toLowerCase();
47203
- groupEl.attr("data-tag-group", groupKey);
47204
- if (isActive && !viewMode) {
47205
- const isSwimActive = currentSwimlaneGroup != null && currentSwimlaneGroup.toLowerCase() === groupKey;
47206
- const pillWidth3 = measureLegendText(groupName, LG_PILL_FONT_SIZE) + LG_PILL_PAD;
47207
- const pillXOff = LG_CAPSULE_PAD;
47208
- const iconX = pillXOff + pillWidth3 + 5;
47209
- const iconY = (LG_HEIGHT - 10) / 2;
47210
- const iconEl = drawSwimlaneIcon4(
47211
- groupEl,
47212
- iconX,
47213
- iconY,
47214
- isSwimActive
47215
- );
47216
- iconEl.attr("data-swimlane-toggle", groupKey).on("click", (event) => {
47217
- event.stopPropagation();
47218
- currentSwimlaneGroup = currentSwimlaneGroup === groupKey ? null : groupKey;
47219
- onTagStateChange?.(
47220
- currentActiveGroup,
47221
- currentSwimlaneGroup
47222
- );
47223
- relayout2();
47224
- });
47225
- }
47226
- }
47227
- };
47228
- const legendInnerG = legendContainer.append("g").attr("transform", `translate(0, ${legendY})`);
47229
- renderLegendD3(
47230
- legendInnerG,
47231
- centralConfig,
47232
- centralState,
47233
- palette,
47234
- isDark,
47235
- centralCallbacks,
47236
- width
47237
- );
47238
- }, recolorEvents2 = function() {
47239
- const colorTG = currentActiveGroup ?? swimlaneTagGroup ?? null;
47240
- mainG.selectAll(".tl-event").each(function() {
47241
- const el = d3Selection22.select(this);
47242
- const lineNum = el.attr("data-line-number");
47243
- const ev = lineNum ? eventByLine.get(lineNum) : void 0;
47244
- if (!ev) return;
47245
- let color;
47246
- if (colorTG) {
47247
- const tagColor = resolveTagColor(
47248
- ev.metadata,
47249
- parsed.timelineTagGroups,
47250
- colorTG
47251
- );
47252
- color = tagColor ?? (ev.group && groupColorMap.has(ev.group) ? groupColorMap.get(ev.group) : textColor);
47253
- } else {
47254
- color = ev.group && groupColorMap.has(ev.group) ? groupColorMap.get(ev.group) : textColor;
47255
- }
47256
- el.selectAll("rect").attr("fill", shapeFill(palette, color, isDark, { solid })).attr("stroke", color);
47257
- el.selectAll("circle:not(.tl-event-point-outline)").attr("fill", shapeFill(palette, color, isDark, { solid })).attr("stroke", color);
47258
- });
47259
- };
47260
- var drawSwimlaneIcon3 = drawSwimlaneIcon4, relayout = relayout2, drawLegend = drawLegend2, recolorEvents = recolorEvents2;
47261
- const legendY = title ? 50 : 10;
47262
- const legendGroups = parsed.timelineTagGroups.map((g) => {
47263
- const pillW = measureLegendText(g.name, LG_PILL_FONT_SIZE) + LG_PILL_PAD;
47264
- const iconSpace = viewMode ? 8 : LG_ICON_W + 4;
47265
- let entryX = LG_CAPSULE_PAD + pillW + iconSpace;
47266
- for (const entry of g.entries) {
47267
- const textX = entryX + LG_DOT_R * 2 + LG_ENTRY_DOT_GAP;
47268
- entryX = textX + measureLegendText(entry.value, LG_ENTRY_FONT_SIZE) + LG_ENTRY_TRAIL;
47269
- }
47270
- return {
47271
- group: g,
47272
- minifiedWidth: pillW,
47273
- expandedWidth: entryX + LG_CAPSULE_PAD
47274
- };
47275
- });
47276
- let currentActiveGroup = activeTagGroup ?? null;
47277
- let currentSwimlaneGroup = swimlaneTagGroup ?? null;
47278
- const eventByLine = /* @__PURE__ */ new Map();
47279
- for (const ev of timelineEvents) {
47280
- eventByLine.set(String(ev.lineNumber), ev);
47281
- }
47282
- drawLegend2();
47404
+ evG.append("text").attr("x", axisX - 14).attr(
47405
+ "y",
47406
+ ev.endDate ? yScale(parseTimelineDate(ev.date)) + Math.max(
47407
+ yScale(parseTimelineDate(ev.endDate)) - yScale(parseTimelineDate(ev.date)),
47408
+ 4
47409
+ ) / 2 : y
47410
+ ).attr("dy", "0.35em").attr("text-anchor", "end").attr("fill", mutedColor).attr("font-size", "10px").text(ev.date + (ev.endDate ? `\u2192${ev.endDate}` : ""));
47283
47411
  }
47284
47412
  }
47285
47413
  }
47414
+ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportDims, activeTagGroup, swimlaneTagGroup, onTagStateChange, viewMode) {
47415
+ const setup = setupTimeline(
47416
+ container,
47417
+ parsed,
47418
+ palette,
47419
+ isDark,
47420
+ exportDims,
47421
+ activeTagGroup,
47422
+ swimlaneTagGroup
47423
+ );
47424
+ if (!setup) return;
47425
+ swimlaneTagGroup = setup.swimlaneTagGroup;
47426
+ const { isVertical, tagLanes } = setup;
47427
+ const hovers = makeTimelineHoverHelpers();
47428
+ if (isVertical) {
47429
+ renderTimelineVertical(
47430
+ container,
47431
+ parsed,
47432
+ palette,
47433
+ isDark,
47434
+ setup,
47435
+ hovers,
47436
+ onClickItem,
47437
+ exportDims,
47438
+ swimlaneTagGroup,
47439
+ activeTagGroup,
47440
+ onTagStateChange,
47441
+ viewMode
47442
+ );
47443
+ return;
47444
+ }
47445
+ const useGroupedHorizontal = tagLanes != null || parsed.timelineSort === "group" && parsed.timelineGroups.length > 0;
47446
+ if (useGroupedHorizontal) {
47447
+ renderTimelineHorizontalGrouped(
47448
+ container,
47449
+ parsed,
47450
+ palette,
47451
+ isDark,
47452
+ setup,
47453
+ hovers,
47454
+ onClickItem,
47455
+ exportDims,
47456
+ swimlaneTagGroup,
47457
+ activeTagGroup,
47458
+ onTagStateChange,
47459
+ viewMode
47460
+ );
47461
+ } else {
47462
+ renderTimelineHorizontalTimeSort(
47463
+ container,
47464
+ parsed,
47465
+ palette,
47466
+ isDark,
47467
+ setup,
47468
+ hovers,
47469
+ onClickItem,
47470
+ exportDims,
47471
+ swimlaneTagGroup,
47472
+ activeTagGroup,
47473
+ onTagStateChange,
47474
+ viewMode
47475
+ );
47476
+ }
47477
+ renderTimelineTagLegendOverlay(
47478
+ container,
47479
+ parsed,
47480
+ palette,
47481
+ isDark,
47482
+ setup,
47483
+ hovers,
47484
+ onClickItem,
47485
+ exportDims,
47486
+ swimlaneTagGroup,
47487
+ activeTagGroup,
47488
+ onTagStateChange,
47489
+ viewMode
47490
+ );
47491
+ }
47286
47492
  function getRotateFn(mode) {
47287
47493
  if (mode === "mixed") return () => Math.random() > 0.5 ? 0 : 90;
47288
47494
  if (mode === "angled") return () => Math.round(Math.random() * 30 - 15);
@@ -47406,7 +47612,7 @@ function regionCentroid(circles, inside) {
47406
47612
  }
47407
47613
  return { x: sx / count, y: sy / count };
47408
47614
  }
47409
- function renderVenn(container, parsed, palette, isDark, onClickItem, exportDims) {
47615
+ function renderVenn(container, parsed, palette, _isDark, onClickItem, exportDims) {
47410
47616
  const { vennSets, vennOverlaps } = parsed;
47411
47617
  const title = parsed.noTitle ? null : parsed.title;
47412
47618
  if (vennSets.length < 2 || vennSets.length > 3) return;
@@ -47640,7 +47846,7 @@ function renderVenn(container, parsed, palette, isDark, onClickItem, exportDims)
47640
47846
  };
47641
47847
  const gcx = circles.reduce((s, c) => s + c.x, 0) / n;
47642
47848
  const gcy = circles.reduce((s, c) => s + c.y, 0) / n;
47643
- function exclusiveHSpan(px, py, ci) {
47849
+ function exclusiveHSpan(_px, py, ci) {
47644
47850
  const dy = py - circles[ci].y;
47645
47851
  const halfChord = Math.sqrt(
47646
47852
  Math.max(0, circles[ci].r * circles[ci].r - dy * dy)
@@ -48553,9 +48759,9 @@ async function renderForExport(content, theme, palette, viewState, options) {
48553
48759
  blHiddenTagValues.set(k, new Set(v));
48554
48760
  }
48555
48761
  }
48556
- const { layoutBoxesAndLines: layoutBoxesAndLines2 } = await Promise.resolve().then(() => (init_layout5(), layout_exports5));
48557
48762
  const { renderBoxesAndLinesForExport: renderBoxesAndLinesForExport2 } = await Promise.resolve().then(() => (init_renderer6(), renderer_exports6));
48558
- const blLayout = layoutBoxesAndLines2(blParsed);
48763
+ const { layoutBoxesAndLines: layoutBoxesAndLines2 } = await Promise.resolve().then(() => (init_layout5(), layout_exports5));
48764
+ const blLayout = await layoutBoxesAndLines2(blParsed);
48559
48765
  const PADDING3 = 20;
48560
48766
  const titleOffset = blParsed.title ? 40 : 0;
48561
48767
  const exportWidth = blLayout.width + PADDING3 * 2;
@@ -49813,7 +50019,8 @@ async function render2(text, options) {
49813
50019
  const onError = options?.onError ?? "svg";
49814
50020
  const result = await render(text, {
49815
50021
  theme: options?.theme,
49816
- palette: palette.id
50022
+ palette: palette.id,
50023
+ viewState: options?.viewState
49817
50024
  });
49818
50025
  const errors = result.diagnostics.filter((d) => d.severity === "error");
49819
50026
  if (errors.length === 0) {
@@ -49853,7 +50060,8 @@ function encodeDiagramUrl2(text, options) {
49853
50060
  baseUrl: options?.baseUrl,
49854
50061
  palette: options?.palette?.id,
49855
50062
  theme: internalTheme,
49856
- filename: options?.filename
50063
+ filename: options?.filename,
50064
+ viewState: options?.viewState
49857
50065
  });
49858
50066
  return "error" in result && result.error ? null : result.url ?? null;
49859
50067
  }
@@ -49871,6 +50079,7 @@ export {
49871
50079
  decodeDiagramUrl2 as decodeDiagramUrl,
49872
50080
  encodeDiagramUrl2 as encodeDiagramUrl,
49873
50081
  formatDgmoError,
50082
+ getPalette,
49874
50083
  palettes,
49875
50084
  render2 as render,
49876
50085
  themes,