@diagrammo/dgmo 0.5.5 → 0.6.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.
package/dist/index.cjs CHANGED
@@ -1467,6 +1467,29 @@ var init_tag_groups = __esm({
1467
1467
  }
1468
1468
  });
1469
1469
 
1470
+ // src/utils/legend-constants.ts
1471
+ var LEGEND_HEIGHT, LEGEND_PILL_PAD, LEGEND_PILL_FONT_SIZE, LEGEND_PILL_FONT_W, LEGEND_CAPSULE_PAD, LEGEND_DOT_R, LEGEND_ENTRY_FONT_SIZE, LEGEND_ENTRY_FONT_W, LEGEND_ENTRY_DOT_GAP, LEGEND_ENTRY_TRAIL, LEGEND_GROUP_GAP, LEGEND_EYE_SIZE, LEGEND_EYE_GAP, EYE_OPEN_PATH, EYE_CLOSED_PATH;
1472
+ var init_legend_constants = __esm({
1473
+ "src/utils/legend-constants.ts"() {
1474
+ "use strict";
1475
+ LEGEND_HEIGHT = 28;
1476
+ LEGEND_PILL_PAD = 16;
1477
+ LEGEND_PILL_FONT_SIZE = 11;
1478
+ LEGEND_PILL_FONT_W = LEGEND_PILL_FONT_SIZE * 0.6;
1479
+ LEGEND_CAPSULE_PAD = 4;
1480
+ LEGEND_DOT_R = 4;
1481
+ LEGEND_ENTRY_FONT_SIZE = 10;
1482
+ LEGEND_ENTRY_FONT_W = LEGEND_ENTRY_FONT_SIZE * 0.6;
1483
+ LEGEND_ENTRY_DOT_GAP = 4;
1484
+ LEGEND_ENTRY_TRAIL = 8;
1485
+ LEGEND_GROUP_GAP = 12;
1486
+ LEGEND_EYE_SIZE = 14;
1487
+ LEGEND_EYE_GAP = 6;
1488
+ EYE_OPEN_PATH = "M1 7s2.5-5 6-5 6 5 6 5-2.5 5-6 5-6-5-6-5z M7 9.5a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5z";
1489
+ EYE_CLOSED_PATH = "M2.5 2.5l9 9 M1.5 7s2.2-4 5.5-4c1.2 0 2.2.5 3 1.1 M12.5 7s-2.2 4-5.5 4c-1.2 0-2.2-.5-3-1.1";
1490
+ }
1491
+ });
1492
+
1470
1493
  // src/sequence/participant-inference.ts
1471
1494
  function inferParticipantType(name) {
1472
1495
  for (const rule of PARTICIPANT_RULES) {
@@ -3662,9 +3685,11 @@ var init_parser3 = __esm({
3662
3685
  // src/chart.ts
3663
3686
  function parseChart(content, palette) {
3664
3687
  const lines = content.split("\n");
3688
+ const parsedEras = [];
3665
3689
  const result = {
3666
3690
  type: "bar",
3667
3691
  data: [],
3692
+ eras: parsedEras,
3668
3693
  diagnostics: [],
3669
3694
  error: null
3670
3695
  };
@@ -3683,6 +3708,16 @@ function parseChart(content, palette) {
3683
3708
  continue;
3684
3709
  }
3685
3710
  if (trimmed.startsWith("//")) continue;
3711
+ const eraMatch = trimmed.match(/^era\s+(.+?)\s*->\s*(.+?)\s*:\s*(.+?)(?:\s*\(([^)]+)\))?\s*$/);
3712
+ if (eraMatch) {
3713
+ parsedEras.push({
3714
+ start: eraMatch[1].trim(),
3715
+ end: eraMatch[2].trim(),
3716
+ label: eraMatch[3].trim(),
3717
+ color: eraMatch[4] ? resolveColor(eraMatch[4].trim(), palette) : null
3718
+ });
3719
+ continue;
3720
+ }
3686
3721
  const colonIndex = trimmed.indexOf(":");
3687
3722
  if (colonIndex === -1) continue;
3688
3723
  const key = trimmed.substring(0, colonIndex).trim().toLowerCase();
@@ -3761,6 +3796,9 @@ function parseChart(content, palette) {
3761
3796
  });
3762
3797
  }
3763
3798
  }
3799
+ if (result.type !== "line" && result.type !== "area") {
3800
+ result.eras = void 0;
3801
+ }
3764
3802
  const setChartError = (line10, message) => {
3765
3803
  const diag = makeDgmoError(line10, message);
3766
3804
  result.diagnostics.push(diag);
@@ -3814,7 +3852,7 @@ var init_chart = __esm({
3814
3852
  });
3815
3853
 
3816
3854
  // src/echarts.ts
3817
- function parseEChart(content, palette) {
3855
+ function parseExtendedChart(content, palette) {
3818
3856
  const lines = content.split("\n");
3819
3857
  const result = {
3820
3858
  type: "scatter",
@@ -4083,7 +4121,7 @@ function buildChartCommons(parsed, palette, isDark) {
4083
4121
  const tooltipTheme = { backgroundColor: palette.surface, borderColor: palette.border, textStyle: { color: palette.text } };
4084
4122
  return { textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme };
4085
4123
  }
4086
- function buildEChartsOption(parsed, palette, isDark) {
4124
+ function buildExtendedChartOption(parsed, palette, isDark) {
4087
4125
  if (parsed.error) {
4088
4126
  return {};
4089
4127
  }
@@ -4755,17 +4793,19 @@ function resolveAxisLabels(parsed) {
4755
4793
  yLabel: parsed.ylabel ?? (isHorizontal ? void 0 : parsed.label)
4756
4794
  };
4757
4795
  }
4758
- function makeGridAxis(type, textColor, axisLineColor, splitLineColor, gridOpacity, label, data, nameGapOverride, chartWidthHint) {
4796
+ function makeGridAxis(type, textColor, axisLineColor, splitLineColor, gridOpacity, label, data, nameGapOverride, chartWidthHint, intervalOverride) {
4759
4797
  const defaultGap = type === "value" ? 75 : 40;
4760
4798
  let catFontSize = 16;
4761
4799
  let catLabelExtras = {};
4762
4800
  if (type === "category" && data && data.length > 0) {
4763
4801
  const maxLabelLen = Math.max(...data.map((l) => l.length));
4764
4802
  const count = data.length;
4765
- if (count > 10 || maxLabelLen > 20) catFontSize = 10;
4766
- else if (count > 5 || maxLabelLen > 14) catFontSize = 11;
4803
+ const step = intervalOverride != null && intervalOverride > 0 ? intervalOverride + 1 : 1;
4804
+ const visibleCount = Math.ceil(count / step);
4805
+ if (visibleCount > 10 || maxLabelLen > 20) catFontSize = 10;
4806
+ else if (visibleCount > 5 || maxLabelLen > 14) catFontSize = 11;
4767
4807
  else if (maxLabelLen > 8) catFontSize = 12;
4768
- if (chartWidthHint && count > 0) {
4808
+ if ((intervalOverride == null || intervalOverride === 0) && chartWidthHint && count > 0) {
4769
4809
  const availPerLabel = Math.floor(chartWidthHint * 0.85 / count);
4770
4810
  catLabelExtras = {
4771
4811
  width: availPerLabel,
@@ -4782,7 +4822,10 @@ function makeGridAxis(type, textColor, axisLineColor, splitLineColor, gridOpacit
4782
4822
  fontSize: type === "category" && data ? catFontSize : 16,
4783
4823
  fontFamily: FONT_FAMILY,
4784
4824
  ...type === "category" && {
4785
- interval: 0,
4825
+ interval: intervalOverride ?? 0,
4826
+ // Prevent ECharts auto-rotation: it measures raw slot width (chartWidth/N),
4827
+ // which is too narrow when an interval skips most labels, and rotates to 90°.
4828
+ rotate: 0,
4786
4829
  formatter: (value) => value.replace(/([a-z])([A-Z])/g, "$1\n$2"),
4787
4830
  ...catLabelExtras
4788
4831
  }
@@ -4796,7 +4839,7 @@ function makeGridAxis(type, textColor, axisLineColor, splitLineColor, gridOpacit
4796
4839
  }
4797
4840
  };
4798
4841
  }
4799
- function buildEChartsOptionFromChart(parsed, palette, isDark, chartWidth) {
4842
+ function buildSimpleChartOption(parsed, palette, isDark, chartWidth) {
4800
4843
  if (parsed.error) return {};
4801
4844
  const { textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme } = buildChartCommons(parsed, palette, isDark);
4802
4845
  switch (parsed.type) {
@@ -4805,7 +4848,7 @@ function buildEChartsOptionFromChart(parsed, palette, isDark, chartWidth) {
4805
4848
  case "bar-stacked":
4806
4849
  return buildBarStackedOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme, chartWidth);
4807
4850
  case "line":
4808
- return parsed.seriesNames ? buildMultiLineOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme, chartWidth) : buildLineOption(parsed, palette, textColor, axisLineColor, splitLineColor, gridOpacity, titleConfig, tooltipTheme, chartWidth);
4851
+ return parsed.seriesNames ? buildMultiLineOption(parsed, palette, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme, chartWidth) : buildLineOption(parsed, palette, textColor, axisLineColor, splitLineColor, gridOpacity, titleConfig, tooltipTheme, chartWidth);
4809
4852
  case "area":
4810
4853
  return buildAreaOption(parsed, palette, textColor, axisLineColor, splitLineColor, gridOpacity, titleConfig, tooltipTheme, chartWidth);
4811
4854
  case "pie":
@@ -4858,11 +4901,49 @@ function buildBarOption(parsed, textColor, axisLineColor, splitLineColor, gridOp
4858
4901
  ]
4859
4902
  };
4860
4903
  }
4904
+ function buildIntervalStep(labels) {
4905
+ const count = labels.length;
4906
+ if (count <= 6) return 0;
4907
+ const snapSteps = [1, 2, 5, 10, 25, 50, 100];
4908
+ const raw = Math.ceil(count / 5);
4909
+ const N = [...snapSteps].reverse().find((s) => s <= raw) ?? 1;
4910
+ return N - 1;
4911
+ }
4912
+ function buildMarkArea(eras, labels, textColor, defaultColor) {
4913
+ if (eras.length === 0) return void 0;
4914
+ return {
4915
+ silent: false,
4916
+ tooltip: { show: true },
4917
+ data: eras.map((era) => {
4918
+ const startIdx = labels.indexOf(era.start);
4919
+ const endIdx = labels.indexOf(era.end);
4920
+ const bandSlots = startIdx >= 0 && endIdx >= 0 ? endIdx - startIdx : Infinity;
4921
+ const color = era.color ?? defaultColor;
4922
+ return [
4923
+ {
4924
+ name: era.label,
4925
+ xAxis: era.start,
4926
+ itemStyle: { color, opacity: 0.15 },
4927
+ label: {
4928
+ show: bandSlots >= 3,
4929
+ position: "insideTop",
4930
+ fontSize: 11,
4931
+ color: textColor
4932
+ }
4933
+ },
4934
+ { xAxis: era.end }
4935
+ ];
4936
+ })
4937
+ };
4938
+ }
4861
4939
  function buildLineOption(parsed, palette, textColor, axisLineColor, splitLineColor, gridOpacity, titleConfig, tooltipTheme, chartWidth) {
4862
4940
  const { xLabel, yLabel } = resolveAxisLabels(parsed);
4863
4941
  const lineColor = parsed.color ?? parsed.seriesNameColors?.[0] ?? palette.primary;
4864
4942
  const labels = parsed.data.map((d) => d.label);
4865
4943
  const values = parsed.data.map((d) => d.value);
4944
+ const eras = parsed.eras ?? [];
4945
+ const interval = buildIntervalStep(labels);
4946
+ const markArea = buildMarkArea(eras, labels, textColor, palette.colors.blue);
4866
4947
  return {
4867
4948
  ...CHART_BASE,
4868
4949
  title: titleConfig,
@@ -4872,7 +4953,7 @@ function buildLineOption(parsed, palette, textColor, axisLineColor, splitLineCol
4872
4953
  axisPointer: { type: "line" }
4873
4954
  },
4874
4955
  grid: makeChartGrid({ xLabel, yLabel, hasTitle: !!parsed.title }),
4875
- xAxis: makeGridAxis("category", textColor, axisLineColor, splitLineColor, gridOpacity, xLabel, labels, void 0, chartWidth),
4956
+ xAxis: makeGridAxis("category", textColor, axisLineColor, splitLineColor, gridOpacity, xLabel, labels, void 0, chartWidth, interval),
4876
4957
  yAxis: makeGridAxis("value", textColor, axisLineColor, splitLineColor, gridOpacity, yLabel),
4877
4958
  series: [
4878
4959
  {
@@ -4882,15 +4963,19 @@ function buildLineOption(parsed, palette, textColor, axisLineColor, splitLineCol
4882
4963
  symbolSize: 8,
4883
4964
  lineStyle: { color: lineColor, width: 3 },
4884
4965
  itemStyle: { color: lineColor },
4885
- emphasis: EMPHASIS_SELF
4966
+ emphasis: EMPHASIS_SELF,
4967
+ ...markArea && { markArea }
4886
4968
  }
4887
4969
  ]
4888
4970
  };
4889
4971
  }
4890
- function buildMultiLineOption(parsed, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme, chartWidth) {
4972
+ function buildMultiLineOption(parsed, palette, textColor, axisLineColor, splitLineColor, gridOpacity, colors, titleConfig, tooltipTheme, chartWidth) {
4891
4973
  const { xLabel, yLabel } = resolveAxisLabels(parsed);
4892
4974
  const seriesNames = parsed.seriesNames ?? [];
4893
4975
  const labels = parsed.data.map((d) => d.label);
4976
+ const eras = parsed.eras ?? [];
4977
+ const interval = buildIntervalStep(labels);
4978
+ const markArea = buildMarkArea(eras, labels, textColor, palette.colors.blue);
4894
4979
  const series = seriesNames.map((name, idx) => {
4895
4980
  const color = parsed.seriesNameColors?.[idx] ?? colors[idx % colors.length];
4896
4981
  const data = parsed.data.map(
@@ -4904,7 +4989,8 @@ function buildMultiLineOption(parsed, textColor, axisLineColor, splitLineColor,
4904
4989
  symbolSize: 8,
4905
4990
  lineStyle: { color, width: 3 },
4906
4991
  itemStyle: { color },
4907
- emphasis: EMPHASIS_SELF
4992
+ emphasis: EMPHASIS_SELF,
4993
+ ...idx === 0 && markArea && { markArea }
4908
4994
  };
4909
4995
  });
4910
4996
  return {
@@ -4921,7 +5007,7 @@ function buildMultiLineOption(parsed, textColor, axisLineColor, splitLineColor,
4921
5007
  textStyle: { color: textColor }
4922
5008
  },
4923
5009
  grid: makeChartGrid({ xLabel, yLabel, hasTitle: !!parsed.title, hasLegend: true }),
4924
- xAxis: makeGridAxis("category", textColor, axisLineColor, splitLineColor, gridOpacity, xLabel, labels, void 0, chartWidth),
5010
+ xAxis: makeGridAxis("category", textColor, axisLineColor, splitLineColor, gridOpacity, xLabel, labels, void 0, chartWidth, interval),
4925
5011
  yAxis: makeGridAxis("value", textColor, axisLineColor, splitLineColor, gridOpacity, yLabel),
4926
5012
  series
4927
5013
  };
@@ -4931,6 +5017,9 @@ function buildAreaOption(parsed, palette, textColor, axisLineColor, splitLineCol
4931
5017
  const lineColor = parsed.color ?? parsed.seriesNameColors?.[0] ?? palette.primary;
4932
5018
  const labels = parsed.data.map((d) => d.label);
4933
5019
  const values = parsed.data.map((d) => d.value);
5020
+ const eras = parsed.eras ?? [];
5021
+ const interval = buildIntervalStep(labels);
5022
+ const markArea = buildMarkArea(eras, labels, textColor, palette.colors.blue);
4934
5023
  return {
4935
5024
  ...CHART_BASE,
4936
5025
  title: titleConfig,
@@ -4940,7 +5029,7 @@ function buildAreaOption(parsed, palette, textColor, axisLineColor, splitLineCol
4940
5029
  axisPointer: { type: "line" }
4941
5030
  },
4942
5031
  grid: makeChartGrid({ xLabel, yLabel, hasTitle: !!parsed.title }),
4943
- xAxis: makeGridAxis("category", textColor, axisLineColor, splitLineColor, gridOpacity, xLabel, labels, void 0, chartWidth),
5032
+ xAxis: makeGridAxis("category", textColor, axisLineColor, splitLineColor, gridOpacity, xLabel, labels, void 0, chartWidth, interval),
4944
5033
  yAxis: makeGridAxis("value", textColor, axisLineColor, splitLineColor, gridOpacity, yLabel),
4945
5034
  series: [
4946
5035
  {
@@ -4951,7 +5040,8 @@ function buildAreaOption(parsed, palette, textColor, axisLineColor, splitLineCol
4951
5040
  lineStyle: { color: lineColor, width: 3 },
4952
5041
  itemStyle: { color: lineColor },
4953
5042
  areaStyle: { opacity: 0.25 },
4954
- emphasis: EMPHASIS_SELF
5043
+ emphasis: EMPHASIS_SELF,
5044
+ ...markArea && { markArea }
4955
5045
  }
4956
5046
  ]
4957
5047
  };
@@ -5136,7 +5226,7 @@ function buildBarStackedOption(parsed, textColor, axisLineColor, splitLineColor,
5136
5226
  series
5137
5227
  };
5138
5228
  }
5139
- async function renderEChartsForExport(content, theme, palette, options) {
5229
+ async function renderExtendedChartForExport(content, theme, palette, options) {
5140
5230
  const isDark = theme === "dark";
5141
5231
  const { getPalette: getPalette2 } = await Promise.resolve().then(() => (init_palettes(), palettes_exports));
5142
5232
  const effectivePalette = palette ?? (isDark ? getPalette2("nord").dark : getPalette2("nord").light);
@@ -5146,11 +5236,11 @@ async function renderEChartsForExport(content, theme, palette, options) {
5146
5236
  if (chartType && STANDARD_CHART_TYPES.has(chartType)) {
5147
5237
  const parsed = parseChart(content, effectivePalette);
5148
5238
  if (parsed.error) return "";
5149
- option = buildEChartsOptionFromChart(parsed, effectivePalette, isDark, ECHART_EXPORT_WIDTH);
5239
+ option = buildSimpleChartOption(parsed, effectivePalette, isDark, ECHART_EXPORT_WIDTH);
5150
5240
  } else {
5151
- const parsed = parseEChart(content, effectivePalette);
5241
+ const parsed = parseExtendedChart(content, effectivePalette);
5152
5242
  if (parsed.error) return "";
5153
- option = buildEChartsOption(parsed, effectivePalette, isDark);
5243
+ option = buildExtendedChartOption(parsed, effectivePalette, isDark);
5154
5244
  }
5155
5245
  if (!option || Object.keys(option).length === 0) return "";
5156
5246
  const chart = echarts.init(null, null, {
@@ -5177,7 +5267,7 @@ async function renderEChartsForExport(content, theme, palette, options) {
5177
5267
  chart.dispose();
5178
5268
  }
5179
5269
  }
5180
- var echarts, EMPHASIS_SELF, CHART_BASE, ECHART_EXPORT_WIDTH, ECHART_EXPORT_HEIGHT;
5270
+ var echarts, EMPHASIS_SELF, CHART_BASE, ECHART_EXPORT_WIDTH, ECHART_EXPORT_HEIGHT, STANDARD_CHART_TYPES;
5181
5271
  var init_echarts = __esm({
5182
5272
  "src/echarts.ts"() {
5183
5273
  "use strict";
@@ -5189,11 +5279,21 @@ var init_echarts = __esm({
5189
5279
  init_diagnostics();
5190
5280
  init_colors();
5191
5281
  init_parsing();
5192
- init_dgmo_router();
5193
5282
  EMPHASIS_SELF = { focus: "self", blurScope: "global" };
5194
5283
  CHART_BASE = { backgroundColor: "transparent", animation: false };
5195
5284
  ECHART_EXPORT_WIDTH = 1200;
5196
5285
  ECHART_EXPORT_HEIGHT = 800;
5286
+ STANDARD_CHART_TYPES = /* @__PURE__ */ new Set([
5287
+ "bar",
5288
+ "line",
5289
+ "multi-line",
5290
+ "area",
5291
+ "pie",
5292
+ "doughnut",
5293
+ "radar",
5294
+ "polar-area",
5295
+ "bar-stacked"
5296
+ ]);
5197
5297
  }
5198
5298
  });
5199
5299
 
@@ -6932,7 +7032,6 @@ function parseInfra(content) {
6932
7032
  edges: [],
6933
7033
  groups: [],
6934
7034
  tagGroups: [],
6935
- scenarios: [],
6936
7035
  options: {},
6937
7036
  diagnostics: [],
6938
7037
  error: null
@@ -7035,16 +7134,7 @@ function parseInfra(content) {
7035
7134
  continue;
7036
7135
  }
7037
7136
  if (/^scenario\s*:/i.test(trimmed)) {
7038
- finishCurrentNode();
7039
- finishCurrentTagGroup();
7040
- currentGroup = null;
7041
- const scenarioName = trimmed.replace(/^scenario\s*:\s*/i, "").trim();
7042
- const scenario = {
7043
- name: scenarioName,
7044
- overrides: {},
7045
- lineNumber
7046
- };
7047
- let scenarioNodeId = null;
7137
+ console.warn("[dgmo warn] scenario syntax is deprecated and will be ignored");
7048
7138
  let si = i + 1;
7049
7139
  while (si < lines.length) {
7050
7140
  const sLine = lines[si];
@@ -7055,23 +7145,9 @@ function parseInfra(content) {
7055
7145
  }
7056
7146
  const sIndent = sLine.length - sLine.trimStart().length;
7057
7147
  if (sIndent === 0) break;
7058
- if (sIndent <= 2) {
7059
- scenarioNodeId = nodeId2(sTrimmed.replace(/\|.*$/, "").trim());
7060
- if (!scenario.overrides[scenarioNodeId]) {
7061
- scenario.overrides[scenarioNodeId] = {};
7062
- }
7063
- } else if (scenarioNodeId) {
7064
- const pm = sTrimmed.match(PROPERTY_RE);
7065
- if (pm) {
7066
- const key = pm[1].toLowerCase();
7067
- const val = parsePropertyValue(pm[2].trim());
7068
- scenario.overrides[scenarioNodeId][key] = val;
7069
- }
7070
- }
7071
7148
  si++;
7072
7149
  }
7073
7150
  i = si - 1;
7074
- result.scenarios.push(scenario);
7075
7151
  continue;
7076
7152
  }
7077
7153
  const tagMatch = trimmed.match(TAG_GROUP_RE);
@@ -7351,15 +7427,12 @@ var init_parser9 = __esm({
7351
7427
  // src/dgmo-router.ts
7352
7428
  var dgmo_router_exports = {};
7353
7429
  __export(dgmo_router_exports, {
7354
- DGMO_CHART_TYPE_MAP: () => DGMO_CHART_TYPE_MAP,
7355
- STANDARD_CHART_TYPES: () => STANDARD_CHART_TYPES,
7356
- getDgmoFramework: () => getDgmoFramework,
7430
+ getAllChartTypes: () => getAllChartTypes,
7431
+ getRenderCategory: () => getRenderCategory,
7432
+ isExtendedChartType: () => isExtendedChartType,
7357
7433
  parseDgmo: () => parseDgmo,
7358
7434
  parseDgmoChartType: () => parseDgmoChartType
7359
7435
  });
7360
- function getDgmoFramework(chartType) {
7361
- return DGMO_CHART_TYPE_MAP[chartType.toLowerCase()] ?? null;
7362
- }
7363
7436
  function parseDgmoChartType(content) {
7364
7437
  const lines = content.split("\n");
7365
7438
  for (const line10 of lines) {
@@ -7379,22 +7452,39 @@ function parseDgmoChartType(content) {
7379
7452
  if (looksLikeOrg(content)) return "org";
7380
7453
  return null;
7381
7454
  }
7455
+ function getRenderCategory(chartType) {
7456
+ const type = chartType.toLowerCase();
7457
+ if (DATA_CHART_TYPES.has(type)) return "data-chart";
7458
+ if (VISUALIZATION_TYPES.has(type)) return "visualization";
7459
+ if (DIAGRAM_TYPES.has(type)) return "diagram";
7460
+ return null;
7461
+ }
7462
+ function isExtendedChartType(chartType) {
7463
+ return EXTENDED_CHART_TYPES.has(chartType.toLowerCase());
7464
+ }
7465
+ function getAllChartTypes() {
7466
+ return [
7467
+ ...DATA_CHART_TYPES,
7468
+ ...VISUALIZATION_TYPES,
7469
+ ...DIAGRAM_TYPES
7470
+ ];
7471
+ }
7382
7472
  function parseDgmo(content) {
7383
7473
  const chartType = parseDgmoChartType(content);
7384
7474
  if (!chartType) {
7385
- return { diagnostics: parseD3(content).diagnostics };
7475
+ return { diagnostics: parseVisualization(content).diagnostics };
7386
7476
  }
7387
7477
  const directParser = PARSE_DISPATCH.get(chartType);
7388
7478
  if (directParser) return { diagnostics: directParser(content).diagnostics };
7389
- if (STANDARD_CHART_TYPES.has(chartType)) {
7479
+ if (STANDARD_CHART_TYPES2.has(chartType)) {
7390
7480
  return { diagnostics: parseChart(content).diagnostics };
7391
7481
  }
7392
7482
  if (ECHART_TYPES.has(chartType)) {
7393
- return { diagnostics: parseEChart(content).diagnostics };
7483
+ return { diagnostics: parseExtendedChart(content).diagnostics };
7394
7484
  }
7395
- return { diagnostics: parseD3(content).diagnostics };
7485
+ return { diagnostics: parseVisualization(content).diagnostics };
7396
7486
  }
7397
- var DGMO_CHART_TYPE_MAP, STANDARD_CHART_TYPES, ECHART_TYPES, PARSE_DISPATCH;
7487
+ var DATA_CHART_TYPES, VISUALIZATION_TYPES, DIAGRAM_TYPES, EXTENDED_CHART_TYPES, STANDARD_CHART_TYPES2, ECHART_TYPES, PARSE_DISPATCH;
7398
7488
  var init_dgmo_router = __esm({
7399
7489
  "src/dgmo-router.ts"() {
7400
7490
  "use strict";
@@ -7412,44 +7502,53 @@ var init_dgmo_router = __esm({
7412
7502
  init_parser7();
7413
7503
  init_parser8();
7414
7504
  init_parser9();
7415
- DGMO_CHART_TYPE_MAP = {
7416
- // Standard charts (via ECharts)
7417
- bar: "echart",
7418
- line: "echart",
7419
- "multi-line": "echart",
7420
- area: "echart",
7421
- pie: "echart",
7422
- doughnut: "echart",
7423
- radar: "echart",
7424
- "polar-area": "echart",
7425
- "bar-stacked": "echart",
7426
- // ECharts
7427
- scatter: "echart",
7428
- sankey: "echart",
7429
- chord: "echart",
7430
- function: "echart",
7431
- heatmap: "echart",
7432
- funnel: "echart",
7433
- // D3
7434
- slope: "d3",
7435
- wordcloud: "d3",
7436
- arc: "d3",
7437
- timeline: "d3",
7438
- venn: "d3",
7439
- quadrant: "d3",
7440
- sequence: "d3",
7441
- flowchart: "d3",
7442
- class: "d3",
7443
- er: "d3",
7444
- org: "d3",
7445
- kanban: "d3",
7446
- c4: "d3",
7447
- "initiative-status": "d3",
7448
- state: "d3",
7449
- sitemap: "d3",
7450
- infra: "d3"
7451
- };
7452
- STANDARD_CHART_TYPES = /* @__PURE__ */ new Set([
7505
+ DATA_CHART_TYPES = /* @__PURE__ */ new Set([
7506
+ "bar",
7507
+ "line",
7508
+ "pie",
7509
+ "doughnut",
7510
+ "area",
7511
+ "polar-area",
7512
+ "radar",
7513
+ "bar-stacked",
7514
+ "multi-line",
7515
+ "scatter",
7516
+ "sankey",
7517
+ "chord",
7518
+ "function",
7519
+ "heatmap",
7520
+ "funnel"
7521
+ ]);
7522
+ VISUALIZATION_TYPES = /* @__PURE__ */ new Set([
7523
+ "slope",
7524
+ "wordcloud",
7525
+ "arc",
7526
+ "timeline",
7527
+ "venn",
7528
+ "quadrant"
7529
+ ]);
7530
+ DIAGRAM_TYPES = /* @__PURE__ */ new Set([
7531
+ "sequence",
7532
+ "flowchart",
7533
+ "class",
7534
+ "er",
7535
+ "org",
7536
+ "kanban",
7537
+ "c4",
7538
+ "initiative-status",
7539
+ "state",
7540
+ "sitemap",
7541
+ "infra"
7542
+ ]);
7543
+ EXTENDED_CHART_TYPES = /* @__PURE__ */ new Set([
7544
+ "scatter",
7545
+ "sankey",
7546
+ "chord",
7547
+ "function",
7548
+ "heatmap",
7549
+ "funnel"
7550
+ ]);
7551
+ STANDARD_CHART_TYPES2 = /* @__PURE__ */ new Set([
7453
7552
  "bar",
7454
7553
  "line",
7455
7554
  "multi-line",
@@ -7580,14 +7679,14 @@ function computeLegendGroups(tagGroups, showEyeIcons, usedValuesByGroup) {
7580
7679
  const usedValues = usedValuesByGroup?.get(group.name.toLowerCase());
7581
7680
  const visibleEntries = usedValues ? group.entries.filter((e) => usedValues.has(e.value.toLowerCase())) : group.entries;
7582
7681
  if (visibleEntries.length === 0) continue;
7583
- const pillWidth = group.name.length * LEGEND_PILL_FONT_W + LEGEND_PILL_PAD;
7682
+ const pillWidth = group.name.length * LEGEND_PILL_FONT_W2 + LEGEND_PILL_PAD2;
7584
7683
  const minPillWidth = pillWidth;
7585
7684
  let entriesWidth = 0;
7586
7685
  for (const entry of visibleEntries) {
7587
- entriesWidth += LEGEND_DOT_R * 2 + LEGEND_ENTRY_DOT_GAP + entry.value.length * LEGEND_ENTRY_FONT_W + LEGEND_ENTRY_TRAIL;
7686
+ entriesWidth += LEGEND_DOT_R2 * 2 + LEGEND_ENTRY_DOT_GAP2 + entry.value.length * LEGEND_ENTRY_FONT_W2 + LEGEND_ENTRY_TRAIL2;
7588
7687
  }
7589
- const eyeSpace = showEyeIcons ? LEGEND_EYE_SIZE + LEGEND_EYE_GAP : 0;
7590
- const capsuleWidth = LEGEND_CAPSULE_PAD * 2 + pillWidth + 4 + eyeSpace + entriesWidth;
7688
+ const eyeSpace = showEyeIcons ? LEGEND_EYE_SIZE2 + LEGEND_EYE_GAP2 : 0;
7689
+ const capsuleWidth = LEGEND_CAPSULE_PAD2 * 2 + pillWidth + 4 + eyeSpace + entriesWidth;
7591
7690
  groups.push({
7592
7691
  name: group.name,
7593
7692
  alias: group.alias,
@@ -7598,9 +7697,9 @@ function computeLegendGroups(tagGroups, showEyeIcons, usedValuesByGroup) {
7598
7697
  x: 0,
7599
7698
  y: 0,
7600
7699
  width: capsuleWidth,
7601
- height: LEGEND_HEIGHT,
7700
+ height: LEGEND_HEIGHT2,
7602
7701
  minifiedWidth: minPillWidth,
7603
- minifiedHeight: LEGEND_HEIGHT
7702
+ minifiedHeight: LEGEND_HEIGHT2
7604
7703
  });
7605
7704
  }
7606
7705
  return groups;
@@ -7630,7 +7729,7 @@ function layoutOrg(parsed, hiddenCounts, activeTagGroup, hiddenAttributes, expan
7630
7729
  for (const g of legendGroups2) {
7631
7730
  g.x = MARGIN;
7632
7731
  g.y = cy;
7633
- cy += LEGEND_HEIGHT + LEGEND_GROUP_GAP;
7732
+ cy += LEGEND_HEIGHT2 + LEGEND_GROUP_GAP2;
7634
7733
  if (g.width > maxWidth2) maxWidth2 = g.width;
7635
7734
  }
7636
7735
  return {
@@ -7639,7 +7738,7 @@ function layoutOrg(parsed, hiddenCounts, activeTagGroup, hiddenAttributes, expan
7639
7738
  containers: [],
7640
7739
  legend: legendGroups2,
7641
7740
  width: maxWidth2 + MARGIN * 2,
7642
- height: cy - LEGEND_GROUP_GAP + MARGIN
7741
+ height: cy - LEGEND_GROUP_GAP2 + MARGIN
7643
7742
  };
7644
7743
  }
7645
7744
  injectDefaultMetadata(parsed.roots, parsed.tagGroups);
@@ -8169,7 +8268,7 @@ function layoutOrg(parsed, hiddenCounts, activeTagGroup, hiddenAttributes, expan
8169
8268
  const effectiveH = (g) => activeTagGroup != null || allExpanded ? g.height : g.minifiedHeight;
8170
8269
  if (visibleGroups.length > 0) {
8171
8270
  if (legendPosition === "bottom") {
8172
- const totalGroupsWidth = visibleGroups.reduce((s, g) => s + effectiveW(g), 0) + (visibleGroups.length - 1) * LEGEND_GROUP_GAP;
8271
+ const totalGroupsWidth = visibleGroups.reduce((s, g) => s + effectiveW(g), 0) + (visibleGroups.length - 1) * LEGEND_GROUP_GAP2;
8173
8272
  const neededWidth = totalGroupsWidth + MARGIN * 2;
8174
8273
  if (neededWidth > totalWidth) {
8175
8274
  finalWidth = neededWidth;
@@ -8187,22 +8286,22 @@ function layoutOrg(parsed, hiddenCounts, activeTagGroup, hiddenAttributes, expan
8187
8286
  for (const g of visibleGroups) {
8188
8287
  g.x = cx;
8189
8288
  g.y = legendY;
8190
- cx += effectiveW(g) + LEGEND_GROUP_GAP;
8289
+ cx += effectiveW(g) + LEGEND_GROUP_GAP2;
8191
8290
  }
8192
- finalHeight = totalHeight + LEGEND_GAP + LEGEND_HEIGHT;
8291
+ finalHeight = totalHeight + LEGEND_GAP + LEGEND_HEIGHT2;
8193
8292
  } else {
8194
- const legendShift = LEGEND_HEIGHT + LEGEND_GROUP_GAP;
8293
+ const legendShift = LEGEND_HEIGHT2 + LEGEND_GROUP_GAP2;
8195
8294
  for (const n of layoutNodes) n.y += legendShift;
8196
8295
  for (const c of containers) c.y += legendShift;
8197
8296
  for (const e of layoutEdges) {
8198
8297
  for (const p of e.points) p.y += legendShift;
8199
8298
  }
8200
- const totalGroupsWidth = visibleGroups.reduce((s, g) => s + effectiveW(g), 0) + (visibleGroups.length - 1) * LEGEND_GROUP_GAP;
8299
+ const totalGroupsWidth = visibleGroups.reduce((s, g) => s + effectiveW(g), 0) + (visibleGroups.length - 1) * LEGEND_GROUP_GAP2;
8201
8300
  let cx = MARGIN;
8202
8301
  for (const g of visibleGroups) {
8203
8302
  g.x = cx;
8204
8303
  g.y = MARGIN;
8205
- cx += effectiveW(g) + LEGEND_GROUP_GAP;
8304
+ cx += effectiveW(g) + LEGEND_GROUP_GAP2;
8206
8305
  }
8207
8306
  finalHeight += legendShift;
8208
8307
  const neededWidth = totalGroupsWidth + MARGIN * 2;
@@ -8220,7 +8319,7 @@ function layoutOrg(parsed, hiddenCounts, activeTagGroup, hiddenAttributes, expan
8220
8319
  height: finalHeight
8221
8320
  };
8222
8321
  }
8223
- var import_d3_hierarchy, CHAR_WIDTH, META_LINE_HEIGHT, HEADER_HEIGHT, SEPARATOR_GAP, CARD_H_PAD, CARD_V_PAD, MIN_CARD_WIDTH, H_GAP, V_GAP, MARGIN, CONTAINER_PAD_X, CONTAINER_PAD_BOTTOM, CONTAINER_LABEL_HEIGHT, CONTAINER_META_LINE_HEIGHT, STACK_V_GAP, LEGEND_GAP, LEGEND_HEIGHT, LEGEND_PILL_PAD, LEGEND_PILL_FONT_W, LEGEND_CAPSULE_PAD, LEGEND_DOT_R, LEGEND_ENTRY_FONT_W, LEGEND_ENTRY_DOT_GAP, LEGEND_ENTRY_TRAIL, LEGEND_GROUP_GAP, LEGEND_EYE_SIZE, LEGEND_EYE_GAP;
8322
+ var import_d3_hierarchy, CHAR_WIDTH, META_LINE_HEIGHT, HEADER_HEIGHT, SEPARATOR_GAP, CARD_H_PAD, CARD_V_PAD, MIN_CARD_WIDTH, H_GAP, V_GAP, MARGIN, CONTAINER_PAD_X, CONTAINER_PAD_BOTTOM, CONTAINER_LABEL_HEIGHT, CONTAINER_META_LINE_HEIGHT, STACK_V_GAP, LEGEND_GAP, LEGEND_HEIGHT2, LEGEND_PILL_PAD2, LEGEND_PILL_FONT_W2, LEGEND_CAPSULE_PAD2, LEGEND_DOT_R2, LEGEND_ENTRY_FONT_W2, LEGEND_ENTRY_DOT_GAP2, LEGEND_ENTRY_TRAIL2, LEGEND_GROUP_GAP2, LEGEND_EYE_SIZE2, LEGEND_EYE_GAP2;
8224
8323
  var init_layout = __esm({
8225
8324
  "src/org/layout.ts"() {
8226
8325
  "use strict";
@@ -8242,17 +8341,17 @@ var init_layout = __esm({
8242
8341
  CONTAINER_META_LINE_HEIGHT = 16;
8243
8342
  STACK_V_GAP = 20;
8244
8343
  LEGEND_GAP = 30;
8245
- LEGEND_HEIGHT = 28;
8246
- LEGEND_PILL_PAD = 16;
8247
- LEGEND_PILL_FONT_W = 11 * 0.6;
8248
- LEGEND_CAPSULE_PAD = 4;
8249
- LEGEND_DOT_R = 4;
8250
- LEGEND_ENTRY_FONT_W = 10 * 0.6;
8251
- LEGEND_ENTRY_DOT_GAP = 4;
8252
- LEGEND_ENTRY_TRAIL = 8;
8253
- LEGEND_GROUP_GAP = 12;
8254
- LEGEND_EYE_SIZE = 14;
8255
- LEGEND_EYE_GAP = 6;
8344
+ LEGEND_HEIGHT2 = 28;
8345
+ LEGEND_PILL_PAD2 = 16;
8346
+ LEGEND_PILL_FONT_W2 = 11 * 0.6;
8347
+ LEGEND_CAPSULE_PAD2 = 4;
8348
+ LEGEND_DOT_R2 = 4;
8349
+ LEGEND_ENTRY_FONT_W2 = 10 * 0.6;
8350
+ LEGEND_ENTRY_DOT_GAP2 = 4;
8351
+ LEGEND_ENTRY_TRAIL2 = 8;
8352
+ LEGEND_GROUP_GAP2 = 12;
8353
+ LEGEND_EYE_SIZE2 = 14;
8354
+ LEGEND_EYE_GAP2 = 6;
8256
8355
  }
8257
8356
  });
8258
8357
 
@@ -8349,11 +8448,11 @@ function renderOrg(container, parsed, layout, palette, isDark, onClickItem, expo
8349
8448
  if (width <= 0 || height <= 0) return;
8350
8449
  const titleOffset = parsed.title ? TITLE_HEIGHT : 0;
8351
8450
  const legendOnly = layout.nodes.length === 0;
8352
- const legendPosition = parsed.options?.["legend-position"] ?? "top";
8451
+ const legendPosition = parsed.options?.["legend-position"] ?? "bottom";
8353
8452
  const hasLegend = layout.legend.length > 0;
8354
- const layoutLegendShift = LEGEND_HEIGHT2 + LEGEND_GROUP_GAP2;
8453
+ const layoutLegendShift = LEGEND_HEIGHT + LEGEND_GROUP_GAP;
8355
8454
  const fixedLegend = !exportDims && hasLegend && !legendOnly;
8356
- const legendReserve = fixedLegend ? LEGEND_HEIGHT2 + LEGEND_FIXED_GAP : 0;
8455
+ const legendReserve = fixedLegend ? LEGEND_HEIGHT + LEGEND_FIXED_GAP : 0;
8357
8456
  const fixedTitle = !exportDims && !!parsed.title;
8358
8457
  const titleReserve = fixedTitle ? TITLE_HEIGHT : 0;
8359
8458
  const diagramW = layout.width;
@@ -8508,56 +8607,60 @@ function renderOrg(container, parsed, layout, palette, isDark, onClickItem, expo
8508
8607
  if (fixedLegend && visibleGroups.length > 0) {
8509
8608
  fixedPositions = /* @__PURE__ */ new Map();
8510
8609
  const effectiveW = (g) => activeTagGroup != null ? g.width : g.minifiedWidth;
8511
- const totalW = visibleGroups.reduce((s, g) => s + effectiveW(g), 0) + (visibleGroups.length - 1) * LEGEND_GROUP_GAP2;
8610
+ const totalW = visibleGroups.reduce((s, g) => s + effectiveW(g), 0) + (visibleGroups.length - 1) * LEGEND_GROUP_GAP;
8512
8611
  let cx = (width - totalW) / 2;
8513
8612
  for (const g of visibleGroups) {
8514
8613
  fixedPositions.set(g.name, cx);
8515
- cx += effectiveW(g) + LEGEND_GROUP_GAP2;
8614
+ cx += effectiveW(g) + LEGEND_GROUP_GAP;
8516
8615
  }
8517
8616
  }
8518
- const legendParent = fixedLegend ? svg.append("g").attr("class", "org-legend-fixed").attr(
8617
+ const legendParentBase = fixedLegend ? svg.append("g").attr("class", "org-legend-fixed").attr(
8519
8618
  "transform",
8520
- legendPosition === "bottom" ? `translate(0, ${height - DIAGRAM_PADDING - LEGEND_HEIGHT2})` : `translate(0, ${DIAGRAM_PADDING + titleReserve})`
8619
+ legendPosition === "bottom" ? `translate(0, ${height - DIAGRAM_PADDING - LEGEND_HEIGHT})` : `translate(0, ${DIAGRAM_PADDING + titleReserve})`
8521
8620
  ) : contentG;
8621
+ const legendParent = legendParentBase;
8622
+ if (fixedLegend && activeTagGroup) {
8623
+ legendParentBase.attr("data-legend-active", activeTagGroup.toLowerCase());
8624
+ }
8522
8625
  for (const group of visibleGroups) {
8523
8626
  const isActive = legendOnly || activeTagGroup != null && group.name.toLowerCase() === activeTagGroup.toLowerCase();
8524
8627
  const groupBg = isDark ? mix(palette.surface, palette.bg, 50) : mix(palette.surface, palette.bg, 30);
8525
8628
  const pillLabel = group.name;
8526
- const pillWidth = pillLabel.length * LEGEND_PILL_FONT_W2 + LEGEND_PILL_PAD2;
8629
+ const pillWidth = pillLabel.length * LEGEND_PILL_FONT_W + LEGEND_PILL_PAD;
8527
8630
  const gX = fixedPositions?.get(group.name) ?? group.x;
8528
8631
  const gY = fixedPositions ? 0 : group.y;
8529
8632
  const gEl = legendParent.append("g").attr("transform", `translate(${gX}, ${gY})`).attr("class", "org-legend-group").attr("data-legend-group", group.name.toLowerCase()).style("cursor", legendOnly ? "default" : "pointer");
8530
8633
  if (isActive) {
8531
- gEl.append("rect").attr("width", group.width).attr("height", LEGEND_HEIGHT2).attr("rx", LEGEND_HEIGHT2 / 2).attr("fill", groupBg);
8634
+ gEl.append("rect").attr("width", group.width).attr("height", LEGEND_HEIGHT).attr("rx", LEGEND_HEIGHT / 2).attr("fill", groupBg);
8532
8635
  }
8533
- const pillXOff = isActive ? LEGEND_CAPSULE_PAD2 : 0;
8534
- const pillYOff = isActive ? LEGEND_CAPSULE_PAD2 : 0;
8535
- const pillH = LEGEND_HEIGHT2 - (isActive ? LEGEND_CAPSULE_PAD2 * 2 : 0);
8636
+ const pillXOff = isActive ? LEGEND_CAPSULE_PAD : 0;
8637
+ const pillYOff = isActive ? LEGEND_CAPSULE_PAD : 0;
8638
+ const pillH = LEGEND_HEIGHT - (isActive ? LEGEND_CAPSULE_PAD * 2 : 0);
8536
8639
  gEl.append("rect").attr("x", pillXOff).attr("y", pillYOff).attr("width", pillWidth).attr("height", pillH).attr("rx", pillH / 2).attr("fill", isActive ? palette.bg : groupBg);
8537
8640
  if (isActive) {
8538
8641
  gEl.append("rect").attr("x", pillXOff).attr("y", pillYOff).attr("width", pillWidth).attr("height", pillH).attr("rx", pillH / 2).attr("fill", "none").attr("stroke", mix(palette.textMuted, palette.bg, 50)).attr("stroke-width", 0.75);
8539
8642
  }
8540
- gEl.append("text").attr("x", pillXOff + pillWidth / 2).attr("y", LEGEND_HEIGHT2 / 2 + LEGEND_PILL_FONT_SIZE / 2 - 2).attr("font-size", LEGEND_PILL_FONT_SIZE).attr("font-weight", "500").attr("fill", isActive ? palette.text : palette.textMuted).attr("text-anchor", "middle").text(pillLabel);
8643
+ gEl.append("text").attr("x", pillXOff + pillWidth / 2).attr("y", LEGEND_HEIGHT / 2 + LEGEND_PILL_FONT_SIZE / 2 - 2).attr("font-size", LEGEND_PILL_FONT_SIZE).attr("font-weight", "500").attr("fill", isActive ? palette.text : palette.textMuted).attr("text-anchor", "middle").text(pillLabel);
8541
8644
  if (isActive && fixedLegend) {
8542
8645
  const groupKey = group.name.toLowerCase();
8543
8646
  const isHidden = hiddenAttributes?.has(groupKey) ?? false;
8544
- const eyeX = pillXOff + pillWidth + LEGEND_EYE_GAP2;
8545
- const eyeY = (LEGEND_HEIGHT2 - LEGEND_EYE_SIZE2) / 2;
8647
+ const eyeX = pillXOff + pillWidth + LEGEND_EYE_GAP;
8648
+ const eyeY = (LEGEND_HEIGHT - LEGEND_EYE_SIZE) / 2;
8546
8649
  const hitPad = 6;
8547
8650
  const eyeG = gEl.append("g").attr("class", "org-legend-eye").attr("data-legend-visibility", groupKey).style("cursor", "pointer").attr("opacity", isHidden ? 0.4 : 0.7);
8548
- eyeG.append("rect").attr("x", eyeX - hitPad).attr("y", eyeY - hitPad).attr("width", LEGEND_EYE_SIZE2 + hitPad * 2).attr("height", LEGEND_EYE_SIZE2 + hitPad * 2).attr("fill", "transparent").attr("pointer-events", "all");
8651
+ eyeG.append("rect").attr("x", eyeX - hitPad).attr("y", eyeY - hitPad).attr("width", LEGEND_EYE_SIZE + hitPad * 2).attr("height", LEGEND_EYE_SIZE + hitPad * 2).attr("fill", "transparent").attr("pointer-events", "all");
8549
8652
  eyeG.append("path").attr("d", isHidden ? EYE_CLOSED_PATH : EYE_OPEN_PATH).attr("transform", `translate(${eyeX}, ${eyeY})`).attr("fill", "none").attr("stroke", palette.textMuted).attr("stroke-width", 1.2).attr("stroke-linecap", "round").attr("stroke-linejoin", "round");
8550
8653
  }
8551
8654
  if (isActive) {
8552
- const eyeShift = fixedLegend ? LEGEND_EYE_SIZE2 + LEGEND_EYE_GAP2 : 0;
8655
+ const eyeShift = fixedLegend ? LEGEND_EYE_SIZE + LEGEND_EYE_GAP : 0;
8553
8656
  let entryX = pillXOff + pillWidth + 4 + eyeShift;
8554
8657
  for (const entry of group.entries) {
8555
8658
  const entryG = gEl.append("g").attr("data-legend-entry", entry.value.toLowerCase()).style("cursor", "pointer");
8556
- entryG.append("circle").attr("cx", entryX + LEGEND_DOT_R2).attr("cy", LEGEND_HEIGHT2 / 2).attr("r", LEGEND_DOT_R2).attr("fill", entry.color);
8557
- const textX = entryX + LEGEND_DOT_R2 * 2 + LEGEND_ENTRY_DOT_GAP2;
8659
+ entryG.append("circle").attr("cx", entryX + LEGEND_DOT_R).attr("cy", LEGEND_HEIGHT / 2).attr("r", LEGEND_DOT_R).attr("fill", entry.color);
8660
+ const textX = entryX + LEGEND_DOT_R * 2 + LEGEND_ENTRY_DOT_GAP;
8558
8661
  const entryLabel = entry.value;
8559
- entryG.append("text").attr("x", textX).attr("y", LEGEND_HEIGHT2 / 2 + LEGEND_ENTRY_FONT_SIZE / 2 - 1).attr("font-size", LEGEND_ENTRY_FONT_SIZE).attr("fill", palette.textMuted).text(entryLabel);
8560
- entryX = textX + entryLabel.length * LEGEND_ENTRY_FONT_W2 + LEGEND_ENTRY_TRAIL2;
8662
+ entryG.append("text").attr("x", textX).attr("y", LEGEND_HEIGHT / 2 + LEGEND_ENTRY_FONT_SIZE / 2 - 1).attr("font-size", LEGEND_ENTRY_FONT_SIZE).attr("fill", palette.textMuted).text(entryLabel);
8663
+ entryX = textX + entryLabel.length * LEGEND_ENTRY_FONT_W + LEGEND_ENTRY_TRAIL;
8561
8664
  }
8562
8665
  }
8563
8666
  }
@@ -8596,7 +8699,7 @@ function renderOrgForExport(content, theme, palette) {
8596
8699
  document.body.removeChild(container);
8597
8700
  }
8598
8701
  }
8599
- var d3Selection, DIAGRAM_PADDING, MAX_SCALE, TITLE_HEIGHT, TITLE_FONT_SIZE, LABEL_FONT_SIZE, META_FONT_SIZE, META_LINE_HEIGHT2, HEADER_HEIGHT2, SEPARATOR_GAP2, EDGE_STROKE_WIDTH, NODE_STROKE_WIDTH, CARD_RADIUS, CONTAINER_RADIUS, CONTAINER_LABEL_FONT_SIZE, CONTAINER_META_FONT_SIZE, CONTAINER_META_LINE_HEIGHT2, CONTAINER_HEADER_HEIGHT, COLLAPSE_BAR_HEIGHT, COLLAPSE_BAR_INSET, LEGEND_HEIGHT2, LEGEND_PILL_PAD2, LEGEND_PILL_FONT_SIZE, LEGEND_PILL_FONT_W2, LEGEND_CAPSULE_PAD2, LEGEND_DOT_R2, LEGEND_ENTRY_FONT_SIZE, LEGEND_ENTRY_FONT_W2, LEGEND_ENTRY_DOT_GAP2, LEGEND_ENTRY_TRAIL2, LEGEND_GROUP_GAP2, LEGEND_EYE_SIZE2, LEGEND_EYE_GAP2, LEGEND_FIXED_GAP, EYE_OPEN_PATH, EYE_CLOSED_PATH;
8702
+ var d3Selection, DIAGRAM_PADDING, MAX_SCALE, TITLE_HEIGHT, TITLE_FONT_SIZE, LABEL_FONT_SIZE, META_FONT_SIZE, META_LINE_HEIGHT2, HEADER_HEIGHT2, SEPARATOR_GAP2, EDGE_STROKE_WIDTH, NODE_STROKE_WIDTH, CARD_RADIUS, CONTAINER_RADIUS, CONTAINER_LABEL_FONT_SIZE, CONTAINER_META_FONT_SIZE, CONTAINER_META_LINE_HEIGHT2, CONTAINER_HEADER_HEIGHT, COLLAPSE_BAR_HEIGHT, COLLAPSE_BAR_INSET, LEGEND_FIXED_GAP;
8600
8703
  var init_renderer = __esm({
8601
8704
  "src/org/renderer.ts"() {
8602
8705
  "use strict";
@@ -8605,6 +8708,7 @@ var init_renderer = __esm({
8605
8708
  init_color_utils();
8606
8709
  init_parser4();
8607
8710
  init_layout();
8711
+ init_legend_constants();
8608
8712
  DIAGRAM_PADDING = 20;
8609
8713
  MAX_SCALE = 3;
8610
8714
  TITLE_HEIGHT = 30;
@@ -8624,22 +8728,7 @@ var init_renderer = __esm({
8624
8728
  CONTAINER_HEADER_HEIGHT = 28;
8625
8729
  COLLAPSE_BAR_HEIGHT = 6;
8626
8730
  COLLAPSE_BAR_INSET = 0;
8627
- LEGEND_HEIGHT2 = 28;
8628
- LEGEND_PILL_PAD2 = 16;
8629
- LEGEND_PILL_FONT_SIZE = 11;
8630
- LEGEND_PILL_FONT_W2 = LEGEND_PILL_FONT_SIZE * 0.6;
8631
- LEGEND_CAPSULE_PAD2 = 4;
8632
- LEGEND_DOT_R2 = 4;
8633
- LEGEND_ENTRY_FONT_SIZE = 10;
8634
- LEGEND_ENTRY_FONT_W2 = LEGEND_ENTRY_FONT_SIZE * 0.6;
8635
- LEGEND_ENTRY_DOT_GAP2 = 4;
8636
- LEGEND_ENTRY_TRAIL2 = 8;
8637
- LEGEND_GROUP_GAP2 = 12;
8638
- LEGEND_EYE_SIZE2 = 14;
8639
- LEGEND_EYE_GAP2 = 6;
8640
8731
  LEGEND_FIXED_GAP = 8;
8641
- EYE_OPEN_PATH = "M1 7s2.5-5 6-5 6 5 6 5-2.5 5-6 5-6-5-6-5z M7 9.5a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5z";
8642
- EYE_CLOSED_PATH = "M2.5 2.5l9 9 M1.5 7s2.2-4 5.5-4c1.2 0 2.2.5 3 1.1 M12.5 7s-2.2 4-5.5 4c-1.2 0-2.2-.5-3-1.1";
8643
8732
  }
8644
8733
  });
8645
8734
 
@@ -9063,23 +9152,17 @@ function layoutSitemap(parsed, hiddenCounts, activeTagGroup, hiddenAttributes, e
9063
9152
  const effectiveW = (g2) => activeTagGroup != null || allExpanded ? g2.width : g2.minifiedWidth;
9064
9153
  if (visibleGroups.length > 0) {
9065
9154
  const legendShift = LEGEND_HEIGHT3 + LEGEND_GROUP_GAP3;
9066
- for (const n of layoutNodes) n.y += legendShift;
9067
- for (const c of layoutContainers) c.y += legendShift;
9068
- for (const e of layoutEdges) {
9069
- for (const p of e.points) p.y += legendShift;
9070
- }
9071
9155
  const totalGroupsWidth = visibleGroups.reduce((s, g2) => s + effectiveW(g2), 0) + (visibleGroups.length - 1) * LEGEND_GROUP_GAP3;
9072
- let cx = MARGIN2;
9156
+ const neededWidth = totalGroupsWidth + MARGIN2 * 2;
9157
+ if (neededWidth > totalWidth) totalWidth = neededWidth;
9158
+ let cx = (totalWidth - totalGroupsWidth) / 2;
9159
+ const legendY = totalHeight + LEGEND_GROUP_GAP3;
9073
9160
  for (const g2 of visibleGroups) {
9074
9161
  g2.x = cx;
9075
- g2.y = MARGIN2;
9162
+ g2.y = legendY;
9076
9163
  cx += effectiveW(g2) + LEGEND_GROUP_GAP3;
9077
9164
  }
9078
9165
  totalHeight += legendShift;
9079
- const neededWidth = totalGroupsWidth + MARGIN2 * 2;
9080
- if (neededWidth > totalWidth) {
9081
- totalWidth = neededWidth;
9082
- }
9083
9166
  }
9084
9167
  return {
9085
9168
  nodes: layoutNodes,
@@ -9273,25 +9356,26 @@ function renderSitemap(container, parsed, layout, palette, isDark, onClickItem,
9273
9356
  const height = exportDims?.height ?? container.clientHeight;
9274
9357
  if (width <= 0 || height <= 0) return;
9275
9358
  const hasLegend = layout.legend.length > 0;
9276
- const layoutLegendShift = LEGEND_HEIGHT4 + LEGEND_GROUP_GAP4;
9359
+ const layoutLegendShift = LEGEND_HEIGHT + LEGEND_GROUP_GAP;
9277
9360
  const fixedLegend = !exportDims && hasLegend;
9278
9361
  const fixedTitle = fixedLegend && !!parsed.title;
9279
9362
  const fixedTitleH = fixedTitle ? TITLE_HEIGHT2 : 0;
9280
- const legendReserveH = fixedLegend ? LEGEND_HEIGHT4 + LEGEND_FIXED_GAP2 : 0;
9281
- const fixedReserve = fixedTitleH + legendReserveH;
9363
+ const legendReserveH = fixedLegend ? LEGEND_HEIGHT + LEGEND_FIXED_GAP2 : 0;
9364
+ const fixedReserveTop = fixedTitleH;
9365
+ const fixedReserveBottom = legendReserveH;
9282
9366
  const titleOffset = !fixedTitle && parsed.title ? TITLE_HEIGHT2 : 0;
9283
9367
  const diagramW = layout.width;
9284
9368
  let diagramH = layout.height + titleOffset;
9285
9369
  if (fixedLegend) {
9286
9370
  diagramH -= layoutLegendShift;
9287
9371
  }
9288
- const availH = height - DIAGRAM_PADDING2 * 2 - fixedReserve;
9372
+ const availH = height - DIAGRAM_PADDING2 * 2 - fixedReserveTop - fixedReserveBottom;
9289
9373
  const scaleX = (width - DIAGRAM_PADDING2 * 2) / diagramW;
9290
9374
  const scaleY = availH / diagramH;
9291
9375
  const scale = Math.min(MAX_SCALE2, scaleX, scaleY);
9292
9376
  const scaledW = diagramW * scale;
9293
9377
  const offsetX = (width - scaledW) / 2;
9294
- const offsetY = DIAGRAM_PADDING2 + fixedReserve;
9378
+ const offsetY = DIAGRAM_PADDING2 + fixedReserveTop;
9295
9379
  const svg = d3Selection2.select(container).append("svg").attr("width", width).attr("height", height).style("font-family", FONT_FAMILY);
9296
9380
  const defs = svg.append("defs");
9297
9381
  defs.append("marker").attr("id", "sm-arrow").attr("viewBox", `0 0 ${ARROWHEAD_W} ${ARROWHEAD_H}`).attr("refX", ARROWHEAD_W).attr("refY", ARROWHEAD_H / 2).attr("markerWidth", ARROWHEAD_W).attr("markerHeight", ARROWHEAD_H).attr("orient", "auto").append("polygon").attr("points", `0,0 ${ARROWHEAD_W},${ARROWHEAD_H / 2} 0,${ARROWHEAD_H}`).attr("fill", palette.textMuted);
@@ -9432,7 +9516,10 @@ function renderSitemap(container, parsed, layout, palette, isDark, onClickItem,
9432
9516
  titleEl.text(parsed.title);
9433
9517
  }
9434
9518
  if (fixedLegend) {
9435
- const legendParent = svg.append("g").attr("class", "sitemap-legend-fixed").attr("transform", `translate(0, ${DIAGRAM_PADDING2 + fixedTitleH})`);
9519
+ const legendParent = svg.append("g").attr("class", "sitemap-legend-fixed").attr("transform", `translate(0, ${height - DIAGRAM_PADDING2 - LEGEND_HEIGHT})`);
9520
+ if (activeTagGroup) {
9521
+ legendParent.attr("data-legend-active", activeTagGroup.toLowerCase());
9522
+ }
9436
9523
  renderLegend(legendParent, layout.legend, palette, isDark, activeTagGroup, width, hiddenAttributes);
9437
9524
  }
9438
9525
  }
@@ -9444,49 +9531,49 @@ function renderLegend(parent, legendGroups, palette, isDark, activeTagGroup, fix
9444
9531
  if (fixedWidth != null && visibleGroups.length > 0) {
9445
9532
  fixedPositions = /* @__PURE__ */ new Map();
9446
9533
  const effectiveW = (g) => activeTagGroup != null ? g.width : g.minifiedWidth;
9447
- const totalW = visibleGroups.reduce((s, g) => s + effectiveW(g), 0) + (visibleGroups.length - 1) * LEGEND_GROUP_GAP4;
9534
+ const totalW = visibleGroups.reduce((s, g) => s + effectiveW(g), 0) + (visibleGroups.length - 1) * LEGEND_GROUP_GAP;
9448
9535
  let cx = (fixedWidth - totalW) / 2;
9449
9536
  for (const g of visibleGroups) {
9450
9537
  fixedPositions.set(g.name, cx);
9451
- cx += effectiveW(g) + LEGEND_GROUP_GAP4;
9538
+ cx += effectiveW(g) + LEGEND_GROUP_GAP;
9452
9539
  }
9453
9540
  }
9454
9541
  for (const group of visibleGroups) {
9455
9542
  const isActive = activeTagGroup != null;
9456
- const pillW = group.name.length * LEGEND_PILL_FONT_W4 + LEGEND_PILL_PAD4;
9543
+ const pillW = group.name.length * LEGEND_PILL_FONT_W + LEGEND_PILL_PAD;
9457
9544
  const gX = fixedPositions?.get(group.name) ?? group.x;
9458
9545
  const gY = fixedPositions ? 0 : group.y;
9459
9546
  const legendG = parent.append("g").attr("transform", `translate(${gX}, ${gY})`).attr("class", "sitemap-legend-group").attr("data-legend-group", group.name.toLowerCase()).style("cursor", "pointer");
9460
9547
  if (isActive) {
9461
- legendG.append("rect").attr("width", group.width).attr("height", LEGEND_HEIGHT4).attr("rx", LEGEND_HEIGHT4 / 2).attr("fill", groupBg);
9548
+ legendG.append("rect").attr("width", group.width).attr("height", LEGEND_HEIGHT).attr("rx", LEGEND_HEIGHT / 2).attr("fill", groupBg);
9462
9549
  }
9463
- const pillXOff = isActive ? LEGEND_CAPSULE_PAD4 : 0;
9464
- const pillYOff = isActive ? LEGEND_CAPSULE_PAD4 : 0;
9465
- const pillH = LEGEND_HEIGHT4 - (isActive ? LEGEND_CAPSULE_PAD4 * 2 : 0);
9550
+ const pillXOff = isActive ? LEGEND_CAPSULE_PAD : 0;
9551
+ const pillYOff = isActive ? LEGEND_CAPSULE_PAD : 0;
9552
+ const pillH = LEGEND_HEIGHT - (isActive ? LEGEND_CAPSULE_PAD * 2 : 0);
9466
9553
  legendG.append("rect").attr("x", pillXOff).attr("y", pillYOff).attr("width", pillW).attr("height", pillH).attr("rx", pillH / 2).attr("fill", isActive ? palette.bg : groupBg);
9467
9554
  if (isActive) {
9468
9555
  legendG.append("rect").attr("x", pillXOff).attr("y", pillYOff).attr("width", pillW).attr("height", pillH).attr("rx", pillH / 2).attr("fill", "none").attr("stroke", mix(palette.textMuted, palette.bg, 50)).attr("stroke-width", 0.75);
9469
9556
  }
9470
- legendG.append("text").attr("x", pillXOff + pillW / 2).attr("y", LEGEND_HEIGHT4 / 2 + LEGEND_PILL_FONT_SIZE2 / 2 - 2).attr("font-size", LEGEND_PILL_FONT_SIZE2).attr("font-weight", "500").attr("fill", isActive ? palette.text : palette.textMuted).attr("text-anchor", "middle").text(group.name);
9557
+ legendG.append("text").attr("x", pillXOff + pillW / 2).attr("y", LEGEND_HEIGHT / 2 + LEGEND_PILL_FONT_SIZE / 2 - 2).attr("font-size", LEGEND_PILL_FONT_SIZE).attr("font-weight", "500").attr("fill", isActive ? palette.text : palette.textMuted).attr("text-anchor", "middle").text(group.name);
9471
9558
  if (isActive && fixedWidth != null) {
9472
9559
  const groupKey = group.name.toLowerCase();
9473
9560
  const isHidden = hiddenAttributes?.has(groupKey) ?? false;
9474
- const eyeX = pillXOff + pillW + LEGEND_EYE_GAP4;
9475
- const eyeY = (LEGEND_HEIGHT4 - LEGEND_EYE_SIZE4) / 2;
9561
+ const eyeX = pillXOff + pillW + LEGEND_EYE_GAP;
9562
+ const eyeY = (LEGEND_HEIGHT - LEGEND_EYE_SIZE) / 2;
9476
9563
  const hitPad = 6;
9477
9564
  const eyeG = legendG.append("g").attr("class", "sitemap-legend-eye").attr("data-legend-visibility", groupKey).style("cursor", "pointer").attr("opacity", isHidden ? 0.4 : 0.7);
9478
- eyeG.append("rect").attr("x", eyeX - hitPad).attr("y", eyeY - hitPad).attr("width", LEGEND_EYE_SIZE4 + hitPad * 2).attr("height", LEGEND_EYE_SIZE4 + hitPad * 2).attr("fill", "transparent").attr("pointer-events", "all");
9479
- eyeG.append("path").attr("d", isHidden ? EYE_CLOSED_PATH2 : EYE_OPEN_PATH2).attr("transform", `translate(${eyeX}, ${eyeY})`).attr("fill", "none").attr("stroke", palette.textMuted).attr("stroke-width", 1.2).attr("stroke-linecap", "round").attr("stroke-linejoin", "round");
9565
+ eyeG.append("rect").attr("x", eyeX - hitPad).attr("y", eyeY - hitPad).attr("width", LEGEND_EYE_SIZE + hitPad * 2).attr("height", LEGEND_EYE_SIZE + hitPad * 2).attr("fill", "transparent").attr("pointer-events", "all");
9566
+ eyeG.append("path").attr("d", isHidden ? EYE_CLOSED_PATH : EYE_OPEN_PATH).attr("transform", `translate(${eyeX}, ${eyeY})`).attr("fill", "none").attr("stroke", palette.textMuted).attr("stroke-width", 1.2).attr("stroke-linecap", "round").attr("stroke-linejoin", "round");
9480
9567
  }
9481
9568
  if (isActive) {
9482
- const eyeShift = fixedWidth != null ? LEGEND_EYE_SIZE4 + LEGEND_EYE_GAP4 : 0;
9569
+ const eyeShift = fixedWidth != null ? LEGEND_EYE_SIZE + LEGEND_EYE_GAP : 0;
9483
9570
  let entryX = pillXOff + pillW + 4 + eyeShift;
9484
9571
  for (const entry of group.entries) {
9485
9572
  const entryG = legendG.append("g").attr("data-legend-entry", entry.value.toLowerCase()).style("cursor", "pointer");
9486
- entryG.append("circle").attr("cx", entryX + LEGEND_DOT_R4).attr("cy", LEGEND_HEIGHT4 / 2).attr("r", LEGEND_DOT_R4).attr("fill", entry.color);
9487
- const textX = entryX + LEGEND_DOT_R4 * 2 + LEGEND_ENTRY_DOT_GAP4;
9488
- entryG.append("text").attr("x", textX).attr("y", LEGEND_HEIGHT4 / 2 + LEGEND_ENTRY_FONT_SIZE2 / 2 - 1).attr("font-size", LEGEND_ENTRY_FONT_SIZE2).attr("fill", palette.textMuted).text(entry.value);
9489
- entryX = textX + entry.value.length * LEGEND_ENTRY_FONT_W4 + LEGEND_ENTRY_TRAIL4;
9573
+ entryG.append("circle").attr("cx", entryX + LEGEND_DOT_R).attr("cy", LEGEND_HEIGHT / 2).attr("r", LEGEND_DOT_R).attr("fill", entry.color);
9574
+ const textX = entryX + LEGEND_DOT_R * 2 + LEGEND_ENTRY_DOT_GAP;
9575
+ entryG.append("text").attr("x", textX).attr("y", LEGEND_HEIGHT / 2 + LEGEND_ENTRY_FONT_SIZE / 2 - 1).attr("font-size", LEGEND_ENTRY_FONT_SIZE).attr("fill", palette.textMuted).text(entry.value);
9576
+ entryX = textX + entry.value.length * LEGEND_ENTRY_FONT_W + LEGEND_ENTRY_TRAIL;
9490
9577
  }
9491
9578
  }
9492
9579
  }
@@ -9532,7 +9619,7 @@ async function renderSitemapForExport(content, theme, palette) {
9532
9619
  const brandColor = theme === "transparent" ? "#888" : effectivePalette.textMuted;
9533
9620
  return injectBranding2(svgHtml, brandColor);
9534
9621
  }
9535
- var d3Selection2, d3Shape, DIAGRAM_PADDING2, MAX_SCALE2, TITLE_HEIGHT2, TITLE_FONT_SIZE2, LABEL_FONT_SIZE2, META_FONT_SIZE2, META_LINE_HEIGHT4, HEADER_HEIGHT4, SEPARATOR_GAP4, EDGE_STROKE_WIDTH2, NODE_STROKE_WIDTH2, CARD_RADIUS2, CONTAINER_RADIUS2, CONTAINER_LABEL_FONT_SIZE2, CONTAINER_META_FONT_SIZE2, CONTAINER_META_LINE_HEIGHT4, CONTAINER_HEADER_HEIGHT2, ARROWHEAD_W, ARROWHEAD_H, EDGE_LABEL_FONT_SIZE, COLLAPSE_BAR_HEIGHT2, LEGEND_HEIGHT4, LEGEND_FIXED_GAP2, LEGEND_PILL_PAD4, LEGEND_PILL_FONT_SIZE2, LEGEND_PILL_FONT_W4, LEGEND_CAPSULE_PAD4, LEGEND_DOT_R4, LEGEND_ENTRY_FONT_SIZE2, LEGEND_ENTRY_FONT_W4, LEGEND_ENTRY_DOT_GAP4, LEGEND_ENTRY_TRAIL4, LEGEND_GROUP_GAP4, LEGEND_EYE_SIZE4, LEGEND_EYE_GAP4, lineGenerator, EYE_OPEN_PATH2, EYE_CLOSED_PATH2;
9622
+ var d3Selection2, d3Shape, DIAGRAM_PADDING2, MAX_SCALE2, TITLE_HEIGHT2, TITLE_FONT_SIZE2, LABEL_FONT_SIZE2, META_FONT_SIZE2, META_LINE_HEIGHT4, HEADER_HEIGHT4, SEPARATOR_GAP4, EDGE_STROKE_WIDTH2, NODE_STROKE_WIDTH2, CARD_RADIUS2, CONTAINER_RADIUS2, CONTAINER_LABEL_FONT_SIZE2, CONTAINER_META_FONT_SIZE2, CONTAINER_META_LINE_HEIGHT4, CONTAINER_HEADER_HEIGHT2, ARROWHEAD_W, ARROWHEAD_H, EDGE_LABEL_FONT_SIZE, COLLAPSE_BAR_HEIGHT2, LEGEND_FIXED_GAP2, lineGenerator;
9536
9623
  var init_renderer2 = __esm({
9537
9624
  "src/sitemap/renderer.ts"() {
9538
9625
  "use strict";
@@ -9540,6 +9627,7 @@ var init_renderer2 = __esm({
9540
9627
  d3Shape = __toESM(require("d3-shape"), 1);
9541
9628
  init_fonts();
9542
9629
  init_color_utils();
9630
+ init_legend_constants();
9543
9631
  DIAGRAM_PADDING2 = 20;
9544
9632
  MAX_SCALE2 = 3;
9545
9633
  TITLE_HEIGHT2 = 30;
@@ -9561,23 +9649,8 @@ var init_renderer2 = __esm({
9561
9649
  ARROWHEAD_H = 7;
9562
9650
  EDGE_LABEL_FONT_SIZE = 11;
9563
9651
  COLLAPSE_BAR_HEIGHT2 = 6;
9564
- LEGEND_HEIGHT4 = 28;
9565
9652
  LEGEND_FIXED_GAP2 = 8;
9566
- LEGEND_PILL_PAD4 = 16;
9567
- LEGEND_PILL_FONT_SIZE2 = 11;
9568
- LEGEND_PILL_FONT_W4 = LEGEND_PILL_FONT_SIZE2 * 0.6;
9569
- LEGEND_CAPSULE_PAD4 = 4;
9570
- LEGEND_DOT_R4 = 4;
9571
- LEGEND_ENTRY_FONT_SIZE2 = 10;
9572
- LEGEND_ENTRY_FONT_W4 = LEGEND_ENTRY_FONT_SIZE2 * 0.6;
9573
- LEGEND_ENTRY_DOT_GAP4 = 4;
9574
- LEGEND_ENTRY_TRAIL4 = 8;
9575
- LEGEND_GROUP_GAP4 = 12;
9576
- LEGEND_EYE_SIZE4 = 14;
9577
- LEGEND_EYE_GAP4 = 6;
9578
9653
  lineGenerator = d3Shape.line().x((d) => d.x).y((d) => d.y).curve(d3Shape.curveBasis);
9579
- EYE_OPEN_PATH2 = "M1 7s2.5-5 6-5 6 5 6 5-2.5 5-6 5-6-5-6-5z M7 9.5a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5z";
9580
- EYE_CLOSED_PATH2 = "M2.5 2.5l9 9 M1.5 7s2.2-4 5.5-4c1.2 0 2.2.5 3 1.1 M12.5 7s-2.2 4-5.5 4c-1.2 0-2.2-.5-3-1.1";
9581
9654
  }
9582
9655
  });
9583
9656
 
@@ -9779,8 +9852,7 @@ function resolveCardTagColor(card, tagGroups, activeTagGroup) {
9779
9852
  return entry?.color;
9780
9853
  }
9781
9854
  function computeLayout(parsed, _palette) {
9782
- const hasHeader = !!parsed.title || parsed.tagGroups.length > 0;
9783
- const headerHeight = hasHeader ? Math.max(TITLE_HEIGHT3, LEGEND_HEIGHT5) + 8 : 0;
9855
+ const headerHeight = parsed.title ? TITLE_HEIGHT3 + 8 : 0;
9784
9856
  const startY = DIAGRAM_PADDING3 + headerHeight;
9785
9857
  const charWidth = CARD_TITLE_FONT_SIZE * 0.6;
9786
9858
  const columnLayouts = [];
@@ -9837,7 +9909,8 @@ function computeLayout(parsed, _palette) {
9837
9909
  currentX += cl.width + COLUMN_GAP;
9838
9910
  }
9839
9911
  const totalWidth = currentX - COLUMN_GAP + DIAGRAM_PADDING3;
9840
- const totalHeight = startY + maxColumnHeight + DIAGRAM_PADDING3;
9912
+ const legendSpace = parsed.tagGroups.length > 0 ? LEGEND_HEIGHT : 0;
9913
+ const totalHeight = startY + maxColumnHeight + DIAGRAM_PADDING3 + legendSpace;
9841
9914
  return { columns: columnLayouts, totalWidth, totalHeight };
9842
9915
  }
9843
9916
  function renderKanban(container, parsed, palette, isDark, _onNavigateToLine, exportDims, activeTagGroup) {
@@ -9850,42 +9923,45 @@ function renderKanban(container, parsed, palette, isDark, _onNavigateToLine, exp
9850
9923
  svg.append("text").attr("class", "chart-title").attr("data-line-number", parsed.titleLineNumber ?? 0).attr("x", DIAGRAM_PADDING3).attr("y", DIAGRAM_PADDING3 + TITLE_FONT_SIZE3).attr("font-size", TITLE_FONT_SIZE3).attr("font-weight", "bold").attr("fill", palette.text).text(parsed.title);
9851
9924
  }
9852
9925
  if (parsed.tagGroups.length > 0) {
9853
- const legendY = DIAGRAM_PADDING3;
9854
- const titleTextWidth = parsed.title ? parsed.title.length * TITLE_FONT_SIZE3 * 0.6 + 16 : 0;
9855
- let legendX = DIAGRAM_PADDING3 + titleTextWidth;
9926
+ const legendY = height - LEGEND_HEIGHT;
9927
+ let legendX = DIAGRAM_PADDING3;
9856
9928
  const groupBg = isDark ? mix(palette.surface, palette.bg, 50) : mix(palette.surface, palette.bg, 30);
9857
- const capsulePad = 4;
9929
+ const capsulePad = LEGEND_CAPSULE_PAD;
9930
+ const legendContainer = svg.append("g").attr("class", "kanban-legend");
9931
+ if (activeTagGroup) {
9932
+ legendContainer.attr("data-legend-active", activeTagGroup.toLowerCase());
9933
+ }
9858
9934
  for (const group of parsed.tagGroups) {
9859
9935
  const isActive = activeTagGroup?.toLowerCase() === group.name.toLowerCase();
9860
9936
  if (activeTagGroup != null && !isActive) continue;
9861
- const pillTextWidth = group.name.length * LEGEND_FONT_SIZE * 0.6;
9937
+ const pillTextWidth = group.name.length * LEGEND_PILL_FONT_SIZE * 0.6;
9862
9938
  const pillWidth = pillTextWidth + 16;
9863
9939
  let capsuleContentWidth = pillWidth;
9864
9940
  if (isActive) {
9865
9941
  capsuleContentWidth += 4;
9866
9942
  for (const entry of group.entries) {
9867
- capsuleContentWidth += LEGEND_DOT_R5 * 2 + 4 + entry.value.length * LEGEND_ENTRY_FONT_SIZE3 * 0.6 + 8;
9943
+ capsuleContentWidth += LEGEND_DOT_R * 2 + 4 + entry.value.length * LEGEND_ENTRY_FONT_SIZE * 0.6 + 8;
9868
9944
  }
9869
9945
  }
9870
9946
  const capsuleWidth = capsuleContentWidth + capsulePad * 2;
9871
9947
  if (isActive) {
9872
- svg.append("rect").attr("x", legendX).attr("y", legendY).attr("width", capsuleWidth).attr("height", LEGEND_HEIGHT5).attr("rx", LEGEND_HEIGHT5 / 2).attr("fill", groupBg);
9948
+ legendContainer.append("rect").attr("x", legendX).attr("y", legendY).attr("width", capsuleWidth).attr("height", LEGEND_HEIGHT).attr("rx", LEGEND_HEIGHT / 2).attr("fill", groupBg);
9873
9949
  }
9874
9950
  const pillX = legendX + (isActive ? capsulePad : 0);
9875
9951
  const pillBg = isActive ? palette.bg : groupBg;
9876
- svg.append("rect").attr("x", pillX).attr("y", legendY + (isActive ? capsulePad : 0)).attr("width", pillWidth).attr("height", LEGEND_HEIGHT5 - (isActive ? capsulePad * 2 : 0)).attr("rx", (LEGEND_HEIGHT5 - (isActive ? capsulePad * 2 : 0)) / 2).attr("fill", pillBg).attr("class", "kanban-legend-group").attr("data-legend-group", group.name.toLowerCase());
9952
+ legendContainer.append("rect").attr("x", pillX).attr("y", legendY + (isActive ? capsulePad : 0)).attr("width", pillWidth).attr("height", LEGEND_HEIGHT - (isActive ? capsulePad * 2 : 0)).attr("rx", (LEGEND_HEIGHT - (isActive ? capsulePad * 2 : 0)) / 2).attr("fill", pillBg).attr("class", "kanban-legend-group").attr("data-legend-group", group.name.toLowerCase());
9877
9953
  if (isActive) {
9878
- svg.append("rect").attr("x", pillX).attr("y", legendY + capsulePad).attr("width", pillWidth).attr("height", LEGEND_HEIGHT5 - capsulePad * 2).attr("rx", (LEGEND_HEIGHT5 - capsulePad * 2) / 2).attr("fill", "none").attr("stroke", mix(palette.textMuted, palette.bg, 50)).attr("stroke-width", 0.75);
9954
+ legendContainer.append("rect").attr("x", pillX).attr("y", legendY + capsulePad).attr("width", pillWidth).attr("height", LEGEND_HEIGHT - capsulePad * 2).attr("rx", (LEGEND_HEIGHT - capsulePad * 2) / 2).attr("fill", "none").attr("stroke", mix(palette.textMuted, palette.bg, 50)).attr("stroke-width", 0.75);
9879
9955
  }
9880
- svg.append("text").attr("x", pillX + pillWidth / 2).attr("y", legendY + LEGEND_HEIGHT5 / 2 + LEGEND_FONT_SIZE / 2 - 2).attr("font-size", LEGEND_FONT_SIZE).attr("font-weight", "500").attr("fill", isActive ? palette.text : palette.textMuted).attr("text-anchor", "middle").text(group.name);
9956
+ legendContainer.append("text").attr("x", pillX + pillWidth / 2).attr("y", legendY + LEGEND_HEIGHT / 2 + LEGEND_PILL_FONT_SIZE / 2 - 2).attr("font-size", LEGEND_PILL_FONT_SIZE).attr("font-weight", "500").attr("fill", isActive ? palette.text : palette.textMuted).attr("text-anchor", "middle").text(group.name);
9881
9957
  if (isActive) {
9882
9958
  let entryX = pillX + pillWidth + 4;
9883
9959
  for (const entry of group.entries) {
9884
- const entryG = svg.append("g").attr("data-legend-entry", entry.value.toLowerCase()).style("cursor", "pointer");
9885
- entryG.append("circle").attr("cx", entryX + LEGEND_DOT_R5).attr("cy", legendY + LEGEND_HEIGHT5 / 2).attr("r", LEGEND_DOT_R5).attr("fill", entry.color);
9886
- const entryTextX = entryX + LEGEND_DOT_R5 * 2 + 4;
9887
- entryG.append("text").attr("x", entryTextX).attr("y", legendY + LEGEND_HEIGHT5 / 2 + LEGEND_ENTRY_FONT_SIZE3 / 2 - 1).attr("font-size", LEGEND_ENTRY_FONT_SIZE3).attr("fill", palette.textMuted).text(entry.value);
9888
- entryX = entryTextX + entry.value.length * LEGEND_ENTRY_FONT_SIZE3 * 0.6 + 8;
9960
+ const entryG = legendContainer.append("g").attr("data-legend-entry", entry.value.toLowerCase()).style("cursor", "pointer");
9961
+ entryG.append("circle").attr("cx", entryX + LEGEND_DOT_R).attr("cy", legendY + LEGEND_HEIGHT / 2).attr("r", LEGEND_DOT_R).attr("fill", entry.color);
9962
+ const entryTextX = entryX + LEGEND_DOT_R * 2 + 4;
9963
+ entryG.append("text").attr("x", entryTextX).attr("y", legendY + LEGEND_HEIGHT / 2 + LEGEND_ENTRY_FONT_SIZE / 2 - 1).attr("font-size", LEGEND_ENTRY_FONT_SIZE).attr("fill", palette.textMuted).text(entry.value);
9964
+ entryX = entryTextX + entry.value.length * LEGEND_ENTRY_FONT_SIZE * 0.6 + 8;
9889
9965
  }
9890
9966
  legendX += capsuleWidth + 12;
9891
9967
  } else {
@@ -9972,7 +10048,7 @@ function renderKanbanForExport(content, theme, palette) {
9972
10048
  const svgEl = container.querySelector("svg");
9973
10049
  return svgEl?.outerHTML ?? "";
9974
10050
  }
9975
- var d3Selection3, DIAGRAM_PADDING3, COLUMN_GAP, COLUMN_HEADER_HEIGHT, COLUMN_PADDING, COLUMN_MIN_WIDTH, CARD_HEADER_HEIGHT, CARD_META_LINE_HEIGHT, CARD_SEPARATOR_GAP, CARD_GAP, CARD_RADIUS3, CARD_PADDING_X, CARD_PADDING_Y, CARD_STROKE_WIDTH, TITLE_HEIGHT3, TITLE_FONT_SIZE3, COLUMN_HEADER_FONT_SIZE, CARD_TITLE_FONT_SIZE, CARD_META_FONT_SIZE, WIP_FONT_SIZE, COLUMN_RADIUS, COLUMN_HEADER_RADIUS, LEGEND_HEIGHT5, LEGEND_FONT_SIZE, LEGEND_DOT_R5, LEGEND_ENTRY_FONT_SIZE3;
10051
+ var d3Selection3, DIAGRAM_PADDING3, COLUMN_GAP, COLUMN_HEADER_HEIGHT, COLUMN_PADDING, COLUMN_MIN_WIDTH, CARD_HEADER_HEIGHT, CARD_META_LINE_HEIGHT, CARD_SEPARATOR_GAP, CARD_GAP, CARD_RADIUS3, CARD_PADDING_X, CARD_PADDING_Y, CARD_STROKE_WIDTH, TITLE_HEIGHT3, TITLE_FONT_SIZE3, COLUMN_HEADER_FONT_SIZE, CARD_TITLE_FONT_SIZE, CARD_META_FONT_SIZE, WIP_FONT_SIZE, COLUMN_RADIUS, COLUMN_HEADER_RADIUS;
9976
10052
  var init_renderer3 = __esm({
9977
10053
  "src/kanban/renderer.ts"() {
9978
10054
  "use strict";
@@ -9982,6 +10058,7 @@ var init_renderer3 = __esm({
9982
10058
  init_inline_markdown();
9983
10059
  init_parser5();
9984
10060
  init_mutations();
10061
+ init_legend_constants();
9985
10062
  DIAGRAM_PADDING3 = 20;
9986
10063
  COLUMN_GAP = 16;
9987
10064
  COLUMN_HEADER_HEIGHT = 36;
@@ -10003,10 +10080,6 @@ var init_renderer3 = __esm({
10003
10080
  WIP_FONT_SIZE = 10;
10004
10081
  COLUMN_RADIUS = 8;
10005
10082
  COLUMN_HEADER_RADIUS = 8;
10006
- LEGEND_HEIGHT5 = 28;
10007
- LEGEND_FONT_SIZE = 11;
10008
- LEGEND_DOT_R5 = 4;
10009
- LEGEND_ENTRY_FONT_SIZE3 = 10;
10010
10083
  }
10011
10084
  });
10012
10085
 
@@ -10720,32 +10793,31 @@ function renderERDiagram(container, parsed, layout, palette, isDark, onClickItem
10720
10793
  }
10721
10794
  }
10722
10795
  if (parsed.tagGroups.length > 0) {
10723
- const LEGEND_Y_PAD = 16;
10724
- const LEGEND_PILL_H = 22;
10725
- const LEGEND_PILL_RX = 11;
10726
- const LEGEND_PILL_PAD9 = 10;
10796
+ const LEGEND_PILL_H = LEGEND_HEIGHT - 6;
10797
+ const LEGEND_PILL_RX = Math.floor(LEGEND_PILL_H / 2);
10727
10798
  const LEGEND_GAP2 = 8;
10728
- const LEGEND_FONT_SIZE2 = 11;
10729
- const LEGEND_GROUP_GAP7 = 16;
10730
10799
  const legendG = svg.append("g").attr("class", "er-tag-legend");
10800
+ if (activeTagGroup) {
10801
+ legendG.attr("data-legend-active", activeTagGroup.toLowerCase());
10802
+ }
10731
10803
  let legendX = DIAGRAM_PADDING5;
10732
10804
  let legendY = height - DIAGRAM_PADDING5;
10733
10805
  for (const group of parsed.tagGroups) {
10734
10806
  const groupG = legendG.append("g").attr("data-legend-group", group.name.toLowerCase());
10735
- const labelText = groupG.append("text").attr("x", legendX).attr("y", legendY + LEGEND_PILL_H / 2).attr("dominant-baseline", "central").attr("fill", palette.textMuted).attr("font-size", LEGEND_FONT_SIZE2).attr("font-family", FONT_FAMILY).text(`${group.name}:`);
10807
+ const labelText = groupG.append("text").attr("x", legendX).attr("y", legendY + LEGEND_PILL_H / 2).attr("dominant-baseline", "central").attr("fill", palette.textMuted).attr("font-size", LEGEND_PILL_FONT_SIZE).attr("font-family", FONT_FAMILY).text(`${group.name}:`);
10736
10808
  const labelWidth = (labelText.node()?.getComputedTextLength?.() ?? group.name.length * 7) + 6;
10737
10809
  legendX += labelWidth;
10738
10810
  for (const entry of group.entries) {
10739
10811
  const pillG = groupG.append("g").attr("data-legend-entry", entry.value.toLowerCase()).style("cursor", "pointer");
10740
- const tmpText = legendG.append("text").attr("font-size", LEGEND_FONT_SIZE2).attr("font-family", FONT_FAMILY).text(entry.value);
10812
+ const tmpText = legendG.append("text").attr("font-size", LEGEND_PILL_FONT_SIZE).attr("font-family", FONT_FAMILY).text(entry.value);
10741
10813
  const textW = tmpText.node()?.getComputedTextLength?.() ?? entry.value.length * 7;
10742
10814
  tmpText.remove();
10743
- const pillW = textW + LEGEND_PILL_PAD9 * 2;
10815
+ const pillW = textW + LEGEND_PILL_PAD * 2;
10744
10816
  pillG.append("rect").attr("x", legendX).attr("y", legendY).attr("width", pillW).attr("height", LEGEND_PILL_H).attr("rx", LEGEND_PILL_RX).attr("ry", LEGEND_PILL_RX).attr("fill", mix(entry.color, isDark ? palette.surface : palette.bg, 25)).attr("stroke", entry.color).attr("stroke-width", 1);
10745
- pillG.append("text").attr("x", legendX + pillW / 2).attr("y", legendY + LEGEND_PILL_H / 2).attr("text-anchor", "middle").attr("dominant-baseline", "central").attr("fill", palette.text).attr("font-size", LEGEND_FONT_SIZE2).attr("font-family", FONT_FAMILY).text(entry.value);
10817
+ pillG.append("text").attr("x", legendX + pillW / 2).attr("y", legendY + LEGEND_PILL_H / 2).attr("text-anchor", "middle").attr("dominant-baseline", "central").attr("fill", palette.text).attr("font-size", LEGEND_PILL_FONT_SIZE).attr("font-family", FONT_FAMILY).text(entry.value);
10746
10818
  legendX += pillW + LEGEND_GAP2;
10747
10819
  }
10748
- legendX += LEGEND_GROUP_GAP7;
10820
+ legendX += LEGEND_GROUP_GAP;
10749
10821
  }
10750
10822
  }
10751
10823
  }
@@ -10794,6 +10866,7 @@ var init_renderer5 = __esm({
10794
10866
  init_color_utils();
10795
10867
  init_palettes();
10796
10868
  init_tag_groups();
10869
+ init_legend_constants();
10797
10870
  init_parser3();
10798
10871
  init_layout4();
10799
10872
  DIAGRAM_PADDING5 = 20;
@@ -10952,12 +11025,14 @@ function layoutInitiativeStatus(parsed, collapseResult) {
10952
11025
  }
10953
11026
  } else if (isYDisplaced) {
10954
11027
  const exitY = tgt.y > src.y + NODESEP ? src.y + src.height / 2 : src.y - src.height / 2;
10955
- const midX = Math.max(src.x + 1, (src.x + enterX) / 2);
10956
- const midY = (exitY + tgt.y) / 2;
11028
+ const spreadExitX = src.x + yOffset;
11029
+ const spreadEntryY = tgt.y + yOffset;
11030
+ const midX = (spreadExitX + enterX) / 2;
11031
+ const midY = (exitY + spreadEntryY) / 2;
10957
11032
  points = [
10958
- { x: src.x, y: exitY },
11033
+ { x: spreadExitX, y: exitY },
10959
11034
  { x: midX, y: midY },
10960
- { x: enterX, y: tgt.y }
11035
+ { x: enterX, y: spreadEntryY }
10961
11036
  ];
10962
11037
  } else if (tgt.x > src.x && !hasIntermediateRank) {
10963
11038
  points = [
@@ -11892,31 +11967,27 @@ function computeC4NodeDimensions(el, options) {
11892
11967
  height += CARD_V_PAD3;
11893
11968
  return { width, height };
11894
11969
  }
11895
- function computeLegendGroups3(tagGroups, usedValuesByGroup) {
11970
+ function computeLegendGroups3(tagGroups) {
11896
11971
  const result = [];
11897
11972
  for (const group of tagGroups) {
11898
11973
  const entries = [];
11899
11974
  for (const entry of group.entries) {
11900
- if (usedValuesByGroup) {
11901
- const used = usedValuesByGroup.get(group.name.toLowerCase());
11902
- if (!used?.has(entry.value.toLowerCase())) continue;
11903
- }
11904
11975
  entries.push({ value: entry.value, color: entry.color });
11905
11976
  }
11906
11977
  if (entries.length === 0) continue;
11907
- const nameW = group.name.length * LEGEND_PILL_FONT_W5 + LEGEND_PILL_PAD5 * 2;
11908
- let capsuleW = LEGEND_CAPSULE_PAD5;
11978
+ const nameW = group.name.length * LEGEND_PILL_FONT_W4 + LEGEND_PILL_PAD4 * 2;
11979
+ let capsuleW = LEGEND_CAPSULE_PAD4;
11909
11980
  for (const e of entries) {
11910
- capsuleW += LEGEND_DOT_R6 * 2 + LEGEND_ENTRY_DOT_GAP5 + e.value.length * LEGEND_ENTRY_FONT_W5 + LEGEND_ENTRY_TRAIL5;
11981
+ capsuleW += LEGEND_DOT_R4 * 2 + LEGEND_ENTRY_DOT_GAP4 + e.value.length * LEGEND_ENTRY_FONT_W4 + LEGEND_ENTRY_TRAIL4;
11911
11982
  }
11912
- capsuleW += LEGEND_CAPSULE_PAD5;
11983
+ capsuleW += LEGEND_CAPSULE_PAD4;
11913
11984
  result.push({
11914
11985
  name: group.name,
11915
11986
  entries,
11916
11987
  x: 0,
11917
11988
  y: 0,
11918
11989
  width: nameW + capsuleW,
11919
- height: LEGEND_HEIGHT6
11990
+ height: LEGEND_HEIGHT4
11920
11991
  });
11921
11992
  }
11922
11993
  return result;
@@ -12036,18 +12107,7 @@ function layoutC4Context(parsed, activeTagGroup) {
12036
12107
  }
12037
12108
  let totalWidth = nodes.length > 0 ? maxX - minX + MARGIN3 * 2 : 0;
12038
12109
  let totalHeight = nodes.length > 0 ? maxY - minY + MARGIN3 * 2 : 0;
12039
- const usedValuesByGroup = /* @__PURE__ */ new Map();
12040
- for (const el of contextElements) {
12041
- for (const group of parsed.tagGroups) {
12042
- const key = group.name.toLowerCase();
12043
- const val = el.metadata[key];
12044
- if (val) {
12045
- if (!usedValuesByGroup.has(key)) usedValuesByGroup.set(key, /* @__PURE__ */ new Set());
12046
- usedValuesByGroup.get(key).add(val.toLowerCase());
12047
- }
12048
- }
12049
- }
12050
- const legendGroups = computeLegendGroups3(parsed.tagGroups, usedValuesByGroup);
12110
+ const legendGroups = computeLegendGroups3(parsed.tagGroups);
12051
12111
  if (legendGroups.length > 0) {
12052
12112
  const legendY = totalHeight + MARGIN3;
12053
12113
  let legendX = MARGIN3;
@@ -12057,7 +12117,7 @@ function layoutC4Context(parsed, activeTagGroup) {
12057
12117
  legendX += lg.width + 12;
12058
12118
  }
12059
12119
  const legendRight = legendX;
12060
- const legendBottom = legendY + LEGEND_HEIGHT6;
12120
+ const legendBottom = legendY + LEGEND_HEIGHT4;
12061
12121
  if (legendRight > totalWidth) totalWidth = legendRight;
12062
12122
  if (legendBottom > totalHeight) totalHeight = legendBottom;
12063
12123
  }
@@ -12363,18 +12423,7 @@ function layoutC4Containers(parsed, systemName, activeTagGroup) {
12363
12423
  }
12364
12424
  let totalWidth = maxX - minX + MARGIN3 * 2;
12365
12425
  let totalHeight = maxY - minY + MARGIN3 * 2;
12366
- const usedValuesByGroup = /* @__PURE__ */ new Map();
12367
- for (const el of [...containers, ...externals]) {
12368
- for (const group of parsed.tagGroups) {
12369
- const key = group.name.toLowerCase();
12370
- const val = el.metadata[key];
12371
- if (val) {
12372
- if (!usedValuesByGroup.has(key)) usedValuesByGroup.set(key, /* @__PURE__ */ new Set());
12373
- usedValuesByGroup.get(key).add(val.toLowerCase());
12374
- }
12375
- }
12376
- }
12377
- const legendGroups = computeLegendGroups3(parsed.tagGroups, usedValuesByGroup);
12426
+ const legendGroups = computeLegendGroups3(parsed.tagGroups);
12378
12427
  if (legendGroups.length > 0) {
12379
12428
  const legendY = totalHeight + MARGIN3;
12380
12429
  let legendX = MARGIN3;
@@ -12384,7 +12433,7 @@ function layoutC4Containers(parsed, systemName, activeTagGroup) {
12384
12433
  legendX += lg.width + 12;
12385
12434
  }
12386
12435
  const legendRight = legendX;
12387
- const legendBottom = legendY + LEGEND_HEIGHT6;
12436
+ const legendBottom = legendY + LEGEND_HEIGHT4;
12388
12437
  if (legendRight > totalWidth) totalWidth = legendRight;
12389
12438
  if (legendBottom > totalHeight) totalHeight = legendBottom;
12390
12439
  }
@@ -12739,21 +12788,7 @@ function layoutC4Components(parsed, systemName, containerName, activeTagGroup) {
12739
12788
  }
12740
12789
  let totalWidth = maxX - minX + MARGIN3 * 2;
12741
12790
  let totalHeight = maxY - minY + MARGIN3 * 2;
12742
- const usedValuesByGroup = /* @__PURE__ */ new Map();
12743
- for (const el of [...components, ...externals]) {
12744
- for (const group of parsed.tagGroups) {
12745
- const key = group.name.toLowerCase();
12746
- let val = el.metadata[key];
12747
- if (!val && components.includes(el)) {
12748
- val = targetContainer.metadata[key] ?? system.metadata[key];
12749
- }
12750
- if (val) {
12751
- if (!usedValuesByGroup.has(key)) usedValuesByGroup.set(key, /* @__PURE__ */ new Set());
12752
- usedValuesByGroup.get(key).add(val.toLowerCase());
12753
- }
12754
- }
12755
- }
12756
- const legendGroups = computeLegendGroups3(parsed.tagGroups, usedValuesByGroup);
12791
+ const legendGroups = computeLegendGroups3(parsed.tagGroups);
12757
12792
  if (legendGroups.length > 0) {
12758
12793
  const legendY = totalHeight + MARGIN3;
12759
12794
  let legendX = MARGIN3;
@@ -12763,7 +12798,7 @@ function layoutC4Components(parsed, systemName, containerName, activeTagGroup) {
12763
12798
  legendX += lg.width + 12;
12764
12799
  }
12765
12800
  const legendRight = legendX;
12766
- const legendBottom = legendY + LEGEND_HEIGHT6;
12801
+ const legendBottom = legendY + LEGEND_HEIGHT4;
12767
12802
  if (legendRight > totalWidth) totalWidth = legendRight;
12768
12803
  if (legendBottom > totalHeight) totalHeight = legendBottom;
12769
12804
  }
@@ -13008,18 +13043,7 @@ function layoutC4Deployment(parsed, activeTagGroup) {
13008
13043
  }
13009
13044
  let totalWidth = maxX - minX + MARGIN3 * 2;
13010
13045
  let totalHeight = maxY - minY + MARGIN3 * 2;
13011
- const usedValuesByGroup = /* @__PURE__ */ new Map();
13012
- for (const r of refEntries) {
13013
- for (const group of parsed.tagGroups) {
13014
- const key = group.name.toLowerCase();
13015
- const val = r.element.metadata[key];
13016
- if (val) {
13017
- if (!usedValuesByGroup.has(key)) usedValuesByGroup.set(key, /* @__PURE__ */ new Set());
13018
- usedValuesByGroup.get(key).add(val.toLowerCase());
13019
- }
13020
- }
13021
- }
13022
- const legendGroups = computeLegendGroups3(parsed.tagGroups, usedValuesByGroup);
13046
+ const legendGroups = computeLegendGroups3(parsed.tagGroups);
13023
13047
  if (legendGroups.length > 0) {
13024
13048
  const legendY = totalHeight + MARGIN3;
13025
13049
  let legendX = MARGIN3;
@@ -13029,13 +13053,13 @@ function layoutC4Deployment(parsed, activeTagGroup) {
13029
13053
  legendX += lg.width + 12;
13030
13054
  }
13031
13055
  const legendRight = legendX;
13032
- const legendBottom = legendY + LEGEND_HEIGHT6;
13056
+ const legendBottom = legendY + LEGEND_HEIGHT4;
13033
13057
  if (legendRight > totalWidth) totalWidth = legendRight;
13034
13058
  if (legendBottom > totalHeight) totalHeight = legendBottom;
13035
13059
  }
13036
13060
  return { nodes, edges, legend: legendGroups, groupBoundaries, width: totalWidth, height: totalHeight };
13037
13061
  }
13038
- var import_dagre5, CHAR_WIDTH5, MIN_NODE_WIDTH, MAX_NODE_WIDTH, TYPE_LABEL_HEIGHT, DIVIDER_GAP, NAME_HEIGHT, DESC_LINE_HEIGHT, DESC_CHAR_WIDTH, CARD_V_PAD3, CARD_H_PAD3, META_LINE_HEIGHT5, META_CHAR_WIDTH, MARGIN3, BOUNDARY_PAD, GROUP_BOUNDARY_PAD, LEGEND_HEIGHT6, LEGEND_PILL_FONT_SIZE3, LEGEND_PILL_FONT_W5, LEGEND_PILL_PAD5, LEGEND_DOT_R6, LEGEND_ENTRY_FONT_SIZE4, LEGEND_ENTRY_FONT_W5, LEGEND_ENTRY_DOT_GAP5, LEGEND_ENTRY_TRAIL5, LEGEND_CAPSULE_PAD5, META_EXCLUDE_KEYS;
13062
+ var import_dagre5, CHAR_WIDTH5, MIN_NODE_WIDTH, MAX_NODE_WIDTH, TYPE_LABEL_HEIGHT, DIVIDER_GAP, NAME_HEIGHT, DESC_LINE_HEIGHT, DESC_CHAR_WIDTH, CARD_V_PAD3, CARD_H_PAD3, META_LINE_HEIGHT5, META_CHAR_WIDTH, MARGIN3, BOUNDARY_PAD, GROUP_BOUNDARY_PAD, LEGEND_HEIGHT4, LEGEND_PILL_FONT_SIZE2, LEGEND_PILL_FONT_W4, LEGEND_PILL_PAD4, LEGEND_DOT_R4, LEGEND_ENTRY_FONT_SIZE2, LEGEND_ENTRY_FONT_W4, LEGEND_ENTRY_DOT_GAP4, LEGEND_ENTRY_TRAIL4, LEGEND_CAPSULE_PAD4, META_EXCLUDE_KEYS;
13039
13063
  var init_layout6 = __esm({
13040
13064
  "src/c4/layout.ts"() {
13041
13065
  "use strict";
@@ -13055,16 +13079,16 @@ var init_layout6 = __esm({
13055
13079
  MARGIN3 = 40;
13056
13080
  BOUNDARY_PAD = 40;
13057
13081
  GROUP_BOUNDARY_PAD = 24;
13058
- LEGEND_HEIGHT6 = 28;
13059
- LEGEND_PILL_FONT_SIZE3 = 11;
13060
- LEGEND_PILL_FONT_W5 = LEGEND_PILL_FONT_SIZE3 * 0.6;
13061
- LEGEND_PILL_PAD5 = 16;
13062
- LEGEND_DOT_R6 = 4;
13063
- LEGEND_ENTRY_FONT_SIZE4 = 10;
13064
- LEGEND_ENTRY_FONT_W5 = LEGEND_ENTRY_FONT_SIZE4 * 0.6;
13065
- LEGEND_ENTRY_DOT_GAP5 = 4;
13066
- LEGEND_ENTRY_TRAIL5 = 8;
13067
- LEGEND_CAPSULE_PAD5 = 4;
13082
+ LEGEND_HEIGHT4 = 28;
13083
+ LEGEND_PILL_FONT_SIZE2 = 11;
13084
+ LEGEND_PILL_FONT_W4 = LEGEND_PILL_FONT_SIZE2 * 0.6;
13085
+ LEGEND_PILL_PAD4 = 16;
13086
+ LEGEND_DOT_R4 = 4;
13087
+ LEGEND_ENTRY_FONT_SIZE2 = 10;
13088
+ LEGEND_ENTRY_FONT_W4 = LEGEND_ENTRY_FONT_SIZE2 * 0.6;
13089
+ LEGEND_ENTRY_DOT_GAP4 = 4;
13090
+ LEGEND_ENTRY_TRAIL4 = 8;
13091
+ LEGEND_CAPSULE_PAD4 = 4;
13068
13092
  META_EXCLUDE_KEYS = /* @__PURE__ */ new Set(["description", "tech", "technology", "is a"]);
13069
13093
  }
13070
13094
  });
@@ -13140,8 +13164,14 @@ function renderC4Context(container, parsed, layout, palette, isDark, onClickItem
13140
13164
  if (width <= 0 || height <= 0) return;
13141
13165
  const titleHeight = parsed.title ? TITLE_HEIGHT4 + 10 : 0;
13142
13166
  const diagramW = layout.width;
13143
- const diagramH = layout.height;
13144
- const availH = height - titleHeight;
13167
+ const hasLegend = layout.legend.length > 0;
13168
+ const C4_LAYOUT_MARGIN = 40;
13169
+ const LEGEND_FIXED_GAP4 = 8;
13170
+ const fixedLegend = !exportDims && hasLegend;
13171
+ const legendLayoutSpace = C4_LAYOUT_MARGIN + LEGEND_HEIGHT;
13172
+ const legendReserveH = fixedLegend ? LEGEND_HEIGHT + LEGEND_FIXED_GAP4 : 0;
13173
+ const diagramH = fixedLegend ? layout.height - legendLayoutSpace : layout.height;
13174
+ const availH = height - titleHeight - legendReserveH;
13145
13175
  const scaleX = (width - DIAGRAM_PADDING7 * 2) / diagramW;
13146
13176
  const scaleY = (availH - DIAGRAM_PADDING7 * 2) / diagramH;
13147
13177
  const scale = Math.min(MAX_SCALE6, scaleX, scaleY);
@@ -13213,6 +13243,20 @@ function renderC4Context(container, parsed, layout, palette, isDark, onClickItem
13213
13243
  }
13214
13244
  for (const node of layout.nodes) {
13215
13245
  const nodeG = contentG.append("g").attr("transform", `translate(${node.x}, ${node.y})`).attr("class", "c4-card").attr("data-line-number", String(node.lineNumber)).attr("data-node-id", node.id);
13246
+ if (activeTagGroup) {
13247
+ const tagKey = activeTagGroup.toLowerCase();
13248
+ const tagValue = node.metadata[tagKey];
13249
+ if (tagValue) {
13250
+ nodeG.attr(`data-tag-${tagKey}`, tagValue.toLowerCase());
13251
+ } else {
13252
+ const tagGroup = parsed.tagGroups.find(
13253
+ (g) => g.name.toLowerCase() === tagKey || g.alias?.toLowerCase() === tagKey
13254
+ );
13255
+ if (tagGroup?.defaultValue) {
13256
+ nodeG.attr(`data-tag-${tagKey}`, tagGroup.defaultValue.toLowerCase());
13257
+ }
13258
+ }
13259
+ }
13216
13260
  if (node.importPath) {
13217
13261
  nodeG.attr("data-import-path", node.importPath);
13218
13262
  }
@@ -13265,36 +13309,12 @@ function renderC4Context(container, parsed, layout, palette, isDark, onClickItem
13265
13309
  nodeG.append("rect").attr("x", -w / 2).attr("y", h / 2 - DRILL_BAR_HEIGHT).attr("width", w).attr("height", DRILL_BAR_HEIGHT).attr("fill", stroke2).attr("clip-path", `url(#${clipId})`).attr("class", "c4-drill-bar");
13266
13310
  }
13267
13311
  }
13268
- if (!exportDims) {
13269
- for (const group of layout.legend) {
13270
- const isActive = activeTagGroup != null && group.name.toLowerCase() === (activeTagGroup ?? "").toLowerCase();
13271
- if (activeTagGroup != null && !isActive) continue;
13272
- const groupBg = isDark ? mix(palette.surface, palette.bg, 50) : mix(palette.surface, palette.bg, 30);
13273
- const pillLabel = group.name;
13274
- const pillWidth = pillLabel.length * LEGEND_PILL_FONT_W6 + LEGEND_PILL_PAD6;
13275
- const gEl = contentG.append("g").attr("transform", `translate(${group.x}, ${group.y})`).attr("class", "c4-legend-group").attr("data-legend-group", group.name.toLowerCase()).style("cursor", "pointer");
13276
- if (isActive) {
13277
- gEl.append("rect").attr("width", group.width).attr("height", LEGEND_HEIGHT7).attr("rx", LEGEND_HEIGHT7 / 2).attr("fill", groupBg);
13278
- }
13279
- const pillX = isActive ? LEGEND_CAPSULE_PAD6 : 0;
13280
- const pillY = isActive ? LEGEND_CAPSULE_PAD6 : 0;
13281
- const pillH = LEGEND_HEIGHT7 - (isActive ? LEGEND_CAPSULE_PAD6 * 2 : 0);
13282
- gEl.append("rect").attr("x", pillX).attr("y", pillY).attr("width", pillWidth).attr("height", pillH).attr("rx", pillH / 2).attr("fill", isActive ? palette.bg : groupBg);
13283
- if (isActive) {
13284
- gEl.append("rect").attr("x", pillX).attr("y", pillY).attr("width", pillWidth).attr("height", pillH).attr("rx", pillH / 2).attr("fill", "none").attr("stroke", mix(palette.textMuted, palette.bg, 50)).attr("stroke-width", 0.75);
13285
- }
13286
- gEl.append("text").attr("x", pillX + pillWidth / 2).attr("y", LEGEND_HEIGHT7 / 2 + LEGEND_PILL_FONT_SIZE4 / 2 - 2).attr("font-size", LEGEND_PILL_FONT_SIZE4).attr("font-weight", "500").attr("fill", isActive ? palette.text : palette.textMuted).attr("text-anchor", "middle").text(pillLabel);
13287
- if (isActive) {
13288
- let entryX = pillX + pillWidth + 4;
13289
- for (const entry of group.entries) {
13290
- const entryG = gEl.append("g").attr("data-legend-entry", entry.value.toLowerCase()).style("cursor", "pointer");
13291
- entryG.append("circle").attr("cx", entryX + LEGEND_DOT_R7).attr("cy", LEGEND_HEIGHT7 / 2).attr("r", LEGEND_DOT_R7).attr("fill", entry.color);
13292
- const textX = entryX + LEGEND_DOT_R7 * 2 + LEGEND_ENTRY_DOT_GAP6;
13293
- entryG.append("text").attr("x", textX).attr("y", LEGEND_HEIGHT7 / 2 + LEGEND_ENTRY_FONT_SIZE5 / 2 - 1).attr("font-size", LEGEND_ENTRY_FONT_SIZE5).attr("fill", palette.textMuted).text(entry.value);
13294
- entryX = textX + entry.value.length * LEGEND_ENTRY_FONT_W6 + LEGEND_ENTRY_TRAIL6;
13295
- }
13296
- }
13312
+ if (hasLegend) {
13313
+ const legendParent = fixedLegend ? svg.append("g").attr("class", "c4-legend-fixed").attr("transform", `translate(0, ${height - DIAGRAM_PADDING7 - LEGEND_HEIGHT})`) : contentG.append("g").attr("class", "c4-legend");
13314
+ if (activeTagGroup) {
13315
+ legendParent.attr("data-legend-active", activeTagGroup.toLowerCase());
13297
13316
  }
13317
+ renderLegend2(legendParent, layout, palette, isDark, activeTagGroup, fixedLegend ? width : null);
13298
13318
  }
13299
13319
  }
13300
13320
  function renderC4ContextForExport(content, theme, palette) {
@@ -13582,33 +13602,47 @@ function placeEdgeLabels(labels, edges, obstacleRects) {
13582
13602
  placedRects.push({ x: lbl.x, y: lbl.y, w: lbl.bgW, h: lbl.bgH });
13583
13603
  }
13584
13604
  }
13585
- function renderLegend2(contentG, layout, palette, isDark, activeTagGroup) {
13586
- for (const group of layout.legend) {
13605
+ function renderLegend2(parent, layout, palette, isDark, activeTagGroup, fixedWidth) {
13606
+ const visibleGroups = activeTagGroup != null ? layout.legend.filter((g) => g.name.toLowerCase() === (activeTagGroup ?? "").toLowerCase()) : layout.legend;
13607
+ const pillWidthOf = (g) => g.name.length * LEGEND_PILL_FONT_W + LEGEND_PILL_PAD;
13608
+ const effectiveW = (g) => activeTagGroup != null ? g.width : pillWidthOf(g);
13609
+ let fixedPositions = null;
13610
+ if (fixedWidth != null && visibleGroups.length > 0) {
13611
+ fixedPositions = /* @__PURE__ */ new Map();
13612
+ const totalW = visibleGroups.reduce((s, g) => s + effectiveW(g), 0) + (visibleGroups.length - 1) * LEGEND_GROUP_GAP;
13613
+ let cx = Math.max(DIAGRAM_PADDING7, (fixedWidth - totalW) / 2);
13614
+ for (const g of visibleGroups) {
13615
+ fixedPositions.set(g.name, cx);
13616
+ cx += effectiveW(g) + LEGEND_GROUP_GAP;
13617
+ }
13618
+ }
13619
+ for (const group of visibleGroups) {
13587
13620
  const isActive = activeTagGroup != null && group.name.toLowerCase() === (activeTagGroup ?? "").toLowerCase();
13588
- if (activeTagGroup != null && !isActive) continue;
13589
13621
  const groupBg = isDark ? mix(palette.surface, palette.bg, 50) : mix(palette.surface, palette.bg, 30);
13590
13622
  const pillLabel = group.name;
13591
- const pillWidth = pillLabel.length * LEGEND_PILL_FONT_W6 + LEGEND_PILL_PAD6;
13592
- const gEl = contentG.append("g").attr("transform", `translate(${group.x}, ${group.y})`).attr("class", "c4-legend-group").attr("data-legend-group", group.name.toLowerCase()).style("cursor", "pointer");
13623
+ const pillWidth = pillWidthOf(group);
13624
+ const gX = fixedPositions?.get(group.name) ?? group.x;
13625
+ const gY = fixedPositions != null ? 0 : group.y;
13626
+ const gEl = parent.append("g").attr("transform", `translate(${gX}, ${gY})`).attr("class", "c4-legend-group").attr("data-legend-group", group.name.toLowerCase()).style("cursor", "pointer");
13593
13627
  if (isActive) {
13594
- gEl.append("rect").attr("width", group.width).attr("height", LEGEND_HEIGHT7).attr("rx", LEGEND_HEIGHT7 / 2).attr("fill", groupBg);
13628
+ gEl.append("rect").attr("width", group.width).attr("height", LEGEND_HEIGHT).attr("rx", LEGEND_HEIGHT / 2).attr("fill", groupBg);
13595
13629
  }
13596
- const pillX = isActive ? LEGEND_CAPSULE_PAD6 : 0;
13597
- const pillY = isActive ? LEGEND_CAPSULE_PAD6 : 0;
13598
- const pillH = LEGEND_HEIGHT7 - (isActive ? LEGEND_CAPSULE_PAD6 * 2 : 0);
13630
+ const pillX = isActive ? LEGEND_CAPSULE_PAD : 0;
13631
+ const pillY = isActive ? LEGEND_CAPSULE_PAD : 0;
13632
+ const pillH = LEGEND_HEIGHT - (isActive ? LEGEND_CAPSULE_PAD * 2 : 0);
13599
13633
  gEl.append("rect").attr("x", pillX).attr("y", pillY).attr("width", pillWidth).attr("height", pillH).attr("rx", pillH / 2).attr("fill", isActive ? palette.bg : groupBg);
13600
13634
  if (isActive) {
13601
13635
  gEl.append("rect").attr("x", pillX).attr("y", pillY).attr("width", pillWidth).attr("height", pillH).attr("rx", pillH / 2).attr("fill", "none").attr("stroke", mix(palette.textMuted, palette.bg, 50)).attr("stroke-width", 0.75);
13602
13636
  }
13603
- gEl.append("text").attr("x", pillX + pillWidth / 2).attr("y", LEGEND_HEIGHT7 / 2 + LEGEND_PILL_FONT_SIZE4 / 2 - 2).attr("font-size", LEGEND_PILL_FONT_SIZE4).attr("font-weight", "500").attr("fill", isActive ? palette.text : palette.textMuted).attr("text-anchor", "middle").text(pillLabel);
13637
+ gEl.append("text").attr("x", pillX + pillWidth / 2).attr("y", LEGEND_HEIGHT / 2 + LEGEND_PILL_FONT_SIZE / 2 - 2).attr("font-size", LEGEND_PILL_FONT_SIZE).attr("font-weight", "500").attr("fill", isActive ? palette.text : palette.textMuted).attr("text-anchor", "middle").text(pillLabel);
13604
13638
  if (isActive) {
13605
13639
  let entryX = pillX + pillWidth + 4;
13606
13640
  for (const entry of group.entries) {
13607
13641
  const entryG = gEl.append("g").attr("data-legend-entry", entry.value.toLowerCase()).style("cursor", "pointer");
13608
- entryG.append("circle").attr("cx", entryX + LEGEND_DOT_R7).attr("cy", LEGEND_HEIGHT7 / 2).attr("r", LEGEND_DOT_R7).attr("fill", entry.color);
13609
- const textX = entryX + LEGEND_DOT_R7 * 2 + LEGEND_ENTRY_DOT_GAP6;
13610
- entryG.append("text").attr("x", textX).attr("y", LEGEND_HEIGHT7 / 2 + LEGEND_ENTRY_FONT_SIZE5 / 2 - 1).attr("font-size", LEGEND_ENTRY_FONT_SIZE5).attr("fill", palette.textMuted).text(entry.value);
13611
- entryX = textX + entry.value.length * LEGEND_ENTRY_FONT_W6 + LEGEND_ENTRY_TRAIL6;
13642
+ entryG.append("circle").attr("cx", entryX + LEGEND_DOT_R).attr("cy", LEGEND_HEIGHT / 2).attr("r", LEGEND_DOT_R).attr("fill", entry.color);
13643
+ const textX = entryX + LEGEND_DOT_R * 2 + LEGEND_ENTRY_DOT_GAP;
13644
+ entryG.append("text").attr("x", textX).attr("y", LEGEND_HEIGHT / 2 + LEGEND_ENTRY_FONT_SIZE / 2 - 1).attr("font-size", LEGEND_ENTRY_FONT_SIZE).attr("fill", palette.textMuted).text(entry.value);
13645
+ entryX = textX + entry.value.length * LEGEND_ENTRY_FONT_W + LEGEND_ENTRY_TRAIL;
13612
13646
  }
13613
13647
  }
13614
13648
  }
@@ -13620,8 +13654,14 @@ function renderC4Containers(container, parsed, layout, palette, isDark, onClickI
13620
13654
  if (width <= 0 || height <= 0) return;
13621
13655
  const titleHeight = parsed.title ? TITLE_HEIGHT4 + 10 : 0;
13622
13656
  const diagramW = layout.width;
13623
- const diagramH = layout.height;
13624
- const availH = height - titleHeight;
13657
+ const hasLegend = layout.legend.length > 0;
13658
+ const C4_LAYOUT_MARGIN = 40;
13659
+ const LEGEND_FIXED_GAP4 = 8;
13660
+ const fixedLegend = !exportDims && hasLegend;
13661
+ const legendLayoutSpace = C4_LAYOUT_MARGIN + LEGEND_HEIGHT;
13662
+ const legendReserveH = fixedLegend ? LEGEND_HEIGHT + LEGEND_FIXED_GAP4 : 0;
13663
+ const diagramH = fixedLegend ? layout.height - legendLayoutSpace : layout.height;
13664
+ const availH = height - titleHeight - legendReserveH;
13625
13665
  const scaleX = (width - DIAGRAM_PADDING7 * 2) / diagramW;
13626
13666
  const scaleY = (availH - DIAGRAM_PADDING7 * 2) / diagramH;
13627
13667
  const scale = Math.min(MAX_SCALE6, scaleX, scaleY);
@@ -13692,6 +13732,20 @@ function renderC4Containers(container, parsed, layout, palette, isDark, onClickI
13692
13732
  renderEdges(contentG, layout.edges, palette, onClickItem, boundaryLabelObstacles);
13693
13733
  for (const node of layout.nodes) {
13694
13734
  const nodeG = contentG.append("g").attr("transform", `translate(${node.x}, ${node.y})`).attr("class", "c4-card").attr("data-line-number", String(node.lineNumber)).attr("data-node-id", node.id);
13735
+ if (activeTagGroup) {
13736
+ const tagKey = activeTagGroup.toLowerCase();
13737
+ const tagValue = node.metadata[tagKey];
13738
+ if (tagValue) {
13739
+ nodeG.attr(`data-tag-${tagKey}`, tagValue.toLowerCase());
13740
+ } else {
13741
+ const tagGroup = parsed.tagGroups.find(
13742
+ (g) => g.name.toLowerCase() === tagKey || g.alias?.toLowerCase() === tagKey
13743
+ );
13744
+ if (tagGroup?.defaultValue) {
13745
+ nodeG.attr(`data-tag-${tagKey}`, tagGroup.defaultValue.toLowerCase());
13746
+ }
13747
+ }
13748
+ }
13695
13749
  if (node.shape) {
13696
13750
  nodeG.attr("data-shape", node.shape);
13697
13751
  }
@@ -13777,8 +13831,12 @@ function renderC4Containers(container, parsed, layout, palette, isDark, onClickI
13777
13831
  nodeG.append("rect").attr("x", -w / 2).attr("y", h / 2 - DRILL_BAR_HEIGHT).attr("width", w).attr("height", DRILL_BAR_HEIGHT).attr("fill", stroke2).attr("clip-path", `url(#${clipId})`).attr("class", "c4-drill-bar");
13778
13832
  }
13779
13833
  }
13780
- if (!exportDims) {
13781
- renderLegend2(contentG, layout, palette, isDark, activeTagGroup);
13834
+ if (hasLegend) {
13835
+ const legendParent = fixedLegend ? svg.append("g").attr("class", "c4-legend-fixed").attr("transform", `translate(0, ${height - DIAGRAM_PADDING7 - LEGEND_HEIGHT})`) : contentG.append("g").attr("class", "c4-legend");
13836
+ if (activeTagGroup) {
13837
+ legendParent.attr("data-legend-active", activeTagGroup.toLowerCase());
13838
+ }
13839
+ renderLegend2(legendParent, layout, palette, isDark, activeTagGroup, fixedLegend ? width : null);
13782
13840
  }
13783
13841
  }
13784
13842
  function renderC4ContainersForExport(content, systemName, theme, palette) {
@@ -13880,7 +13938,7 @@ function renderC4DeploymentForExport(content, theme, palette) {
13880
13938
  document.body.removeChild(el);
13881
13939
  }
13882
13940
  }
13883
- var d3Selection7, d3Shape5, DIAGRAM_PADDING7, MAX_SCALE6, TITLE_HEIGHT4, TITLE_FONT_SIZE4, TYPE_FONT_SIZE, NAME_FONT_SIZE, DESC_FONT_SIZE, DESC_LINE_HEIGHT2, DESC_CHAR_WIDTH2, EDGE_LABEL_FONT_SIZE5, TECH_FONT_SIZE, EDGE_STROKE_WIDTH6, NODE_STROKE_WIDTH6, CARD_RADIUS4, CARD_H_PAD4, CARD_V_PAD4, TYPE_LABEL_HEIGHT2, DIVIDER_GAP2, NAME_HEIGHT2, META_FONT_SIZE3, META_CHAR_WIDTH2, META_LINE_HEIGHT6, BOUNDARY_LABEL_FONT_SIZE, BOUNDARY_STROKE_WIDTH, BOUNDARY_RADIUS, DRILL_BAR_HEIGHT, CYLINDER_RY, PERSON_HEAD_R, PERSON_ARM_SPAN, PERSON_LEG_SPAN, PERSON_ICON_W, PERSON_SW, LEGEND_HEIGHT7, LEGEND_PILL_FONT_SIZE4, LEGEND_PILL_FONT_W6, LEGEND_PILL_PAD6, LEGEND_DOT_R7, LEGEND_ENTRY_FONT_SIZE5, LEGEND_ENTRY_FONT_W6, LEGEND_ENTRY_DOT_GAP6, LEGEND_ENTRY_TRAIL6, LEGEND_CAPSULE_PAD6, lineGenerator5;
13941
+ var d3Selection7, d3Shape5, DIAGRAM_PADDING7, MAX_SCALE6, TITLE_HEIGHT4, TITLE_FONT_SIZE4, TYPE_FONT_SIZE, NAME_FONT_SIZE, DESC_FONT_SIZE, DESC_LINE_HEIGHT2, DESC_CHAR_WIDTH2, EDGE_LABEL_FONT_SIZE5, TECH_FONT_SIZE, EDGE_STROKE_WIDTH6, NODE_STROKE_WIDTH6, CARD_RADIUS4, CARD_H_PAD4, CARD_V_PAD4, TYPE_LABEL_HEIGHT2, DIVIDER_GAP2, NAME_HEIGHT2, META_FONT_SIZE3, META_CHAR_WIDTH2, META_LINE_HEIGHT6, BOUNDARY_LABEL_FONT_SIZE, BOUNDARY_STROKE_WIDTH, BOUNDARY_RADIUS, DRILL_BAR_HEIGHT, CYLINDER_RY, PERSON_HEAD_R, PERSON_ARM_SPAN, PERSON_LEG_SPAN, PERSON_ICON_W, PERSON_SW, lineGenerator5;
13884
13942
  var init_renderer7 = __esm({
13885
13943
  "src/c4/renderer.ts"() {
13886
13944
  "use strict";
@@ -13891,6 +13949,7 @@ var init_renderer7 = __esm({
13891
13949
  init_inline_markdown();
13892
13950
  init_parser6();
13893
13951
  init_layout6();
13952
+ init_legend_constants();
13894
13953
  DIAGRAM_PADDING7 = 20;
13895
13954
  MAX_SCALE6 = 3;
13896
13955
  TITLE_HEIGHT4 = 30;
@@ -13923,16 +13982,6 @@ var init_renderer7 = __esm({
13923
13982
  PERSON_LEG_SPAN = 7;
13924
13983
  PERSON_ICON_W = PERSON_ARM_SPAN * 2;
13925
13984
  PERSON_SW = 1.5;
13926
- LEGEND_HEIGHT7 = 28;
13927
- LEGEND_PILL_FONT_SIZE4 = 11;
13928
- LEGEND_PILL_FONT_W6 = LEGEND_PILL_FONT_SIZE4 * 0.6;
13929
- LEGEND_PILL_PAD6 = 16;
13930
- LEGEND_DOT_R7 = 4;
13931
- LEGEND_ENTRY_FONT_SIZE5 = 10;
13932
- LEGEND_ENTRY_FONT_W6 = LEGEND_ENTRY_FONT_SIZE5 * 0.6;
13933
- LEGEND_ENTRY_DOT_GAP6 = 4;
13934
- LEGEND_ENTRY_TRAIL6 = 8;
13935
- LEGEND_CAPSULE_PAD6 = 4;
13936
13985
  lineGenerator5 = d3Shape5.line().x((d) => d.x).y((d) => d.y).curve(d3Shape5.curveBasis);
13937
13986
  }
13938
13987
  });
@@ -14788,23 +14837,6 @@ function computeInfra(parsed, params = {}) {
14788
14837
  const defaultLatencyMs = parseFloat(parsed.options["default-latency-ms"] ?? "") || 0;
14789
14838
  const defaultUptime = parseFloat(parsed.options["default-uptime"] ?? "") || 100;
14790
14839
  let effectiveNodes = parsed.nodes;
14791
- if (params.scenario) {
14792
- const overrides = params.scenario.overrides;
14793
- effectiveNodes = parsed.nodes.map((node) => {
14794
- const nodeOverrides = overrides[node.id];
14795
- if (!nodeOverrides) return node;
14796
- const props = node.properties.map((p) => {
14797
- const ov = nodeOverrides[p.key];
14798
- return ov != null ? { ...p, value: ov } : p;
14799
- });
14800
- for (const [key, val] of Object.entries(nodeOverrides)) {
14801
- if (!props.some((p) => p.key === key)) {
14802
- props.push({ key, value: val, lineNumber: node.lineNumber });
14803
- }
14804
- }
14805
- return { ...node, properties: props };
14806
- });
14807
- }
14808
14840
  if (params.propertyOverrides) {
14809
14841
  const propOv = params.propertyOverrides;
14810
14842
  effectiveNodes = effectiveNodes.map((node) => {
@@ -16401,16 +16433,16 @@ function computeInfraLegendGroups(nodes, tagGroups, palette, edges) {
16401
16433
  color: r.color,
16402
16434
  key: r.name.toLowerCase().replace(/\s+/g, "-")
16403
16435
  }));
16404
- const pillWidth = "Capabilities".length * LEGEND_PILL_FONT_W7 + LEGEND_PILL_PAD7;
16436
+ const pillWidth = "Capabilities".length * LEGEND_PILL_FONT_W + LEGEND_PILL_PAD;
16405
16437
  let entriesWidth = 0;
16406
16438
  for (const e of entries) {
16407
- entriesWidth += LEGEND_DOT_R8 * 2 + LEGEND_ENTRY_DOT_GAP7 + e.value.length * LEGEND_ENTRY_FONT_W7 + LEGEND_ENTRY_TRAIL7;
16439
+ entriesWidth += LEGEND_DOT_R * 2 + LEGEND_ENTRY_DOT_GAP + e.value.length * LEGEND_ENTRY_FONT_W + LEGEND_ENTRY_TRAIL;
16408
16440
  }
16409
16441
  groups.push({
16410
16442
  name: "Capabilities",
16411
16443
  type: "role",
16412
16444
  entries,
16413
- width: LEGEND_CAPSULE_PAD7 * 2 + pillWidth + 4 + entriesWidth,
16445
+ width: LEGEND_CAPSULE_PAD * 2 + pillWidth + 4 + entriesWidth,
16414
16446
  minifiedWidth: pillWidth
16415
16447
  });
16416
16448
  }
@@ -16426,123 +16458,72 @@ function computeInfraLegendGroups(nodes, tagGroups, palette, edges) {
16426
16458
  }
16427
16459
  }
16428
16460
  if (entries.length === 0) continue;
16429
- const pillWidth = tg.name.length * LEGEND_PILL_FONT_W7 + LEGEND_PILL_PAD7;
16461
+ const pillWidth = tg.name.length * LEGEND_PILL_FONT_W + LEGEND_PILL_PAD;
16430
16462
  let entriesWidth = 0;
16431
16463
  for (const e of entries) {
16432
- entriesWidth += LEGEND_DOT_R8 * 2 + LEGEND_ENTRY_DOT_GAP7 + e.value.length * LEGEND_ENTRY_FONT_W7 + LEGEND_ENTRY_TRAIL7;
16464
+ entriesWidth += LEGEND_DOT_R * 2 + LEGEND_ENTRY_DOT_GAP + e.value.length * LEGEND_ENTRY_FONT_W + LEGEND_ENTRY_TRAIL;
16433
16465
  }
16434
16466
  groups.push({
16435
16467
  name: tg.name,
16436
16468
  type: "tag",
16437
16469
  tagKey: (tg.alias ?? tg.name).toLowerCase(),
16438
16470
  entries,
16439
- width: LEGEND_CAPSULE_PAD7 * 2 + pillWidth + 4 + entriesWidth,
16471
+ width: LEGEND_CAPSULE_PAD * 2 + pillWidth + 4 + entriesWidth,
16440
16472
  minifiedWidth: pillWidth
16441
16473
  });
16442
16474
  }
16443
16475
  return groups;
16444
16476
  }
16445
- function computePlaybackWidth(playback) {
16446
- if (!playback) return 0;
16447
- const pillWidth = "Playback".length * LEGEND_PILL_FONT_W7 + LEGEND_PILL_PAD7;
16448
- if (!playback.expanded) return pillWidth;
16449
- let entriesW = 8;
16450
- entriesW += LEGEND_PILL_FONT_SIZE5 * 0.8 + 6;
16451
- for (const s of playback.speedOptions) {
16452
- entriesW += `${s}x`.length * LEGEND_ENTRY_FONT_W7 + SPEED_BADGE_H_PAD * 2 + SPEED_BADGE_GAP;
16453
- }
16454
- return LEGEND_CAPSULE_PAD7 * 2 + pillWidth + entriesW;
16455
- }
16456
- function renderLegend3(rootSvg, legendGroups, totalWidth, legendY, palette, isDark, activeGroup, playback) {
16457
- if (legendGroups.length === 0 && !playback) return;
16477
+ function renderLegend3(rootSvg, legendGroups, totalWidth, legendY, palette, isDark, activeGroup) {
16478
+ if (legendGroups.length === 0) return;
16458
16479
  const legendG = rootSvg.append("g").attr("transform", `translate(0, ${legendY})`);
16480
+ if (activeGroup) {
16481
+ legendG.attr("data-legend-active", activeGroup.toLowerCase());
16482
+ }
16459
16483
  const effectiveW = (g) => activeGroup != null && g.name.toLowerCase() === activeGroup.toLowerCase() ? g.width : g.minifiedWidth;
16460
- const playbackW = computePlaybackWidth(playback);
16461
- const trailingGaps = legendGroups.length > 0 && playbackW > 0 ? LEGEND_GROUP_GAP5 : 0;
16462
- const totalLegendW = legendGroups.reduce((s, g) => s + effectiveW(g), 0) + (legendGroups.length - 1) * LEGEND_GROUP_GAP5 + trailingGaps + playbackW;
16484
+ const totalLegendW = legendGroups.reduce((s, g) => s + effectiveW(g), 0) + (legendGroups.length - 1) * LEGEND_GROUP_GAP;
16463
16485
  let cursorX = (totalWidth - totalLegendW) / 2;
16464
16486
  for (const group of legendGroups) {
16465
16487
  const isActive = activeGroup != null && group.name.toLowerCase() === activeGroup.toLowerCase();
16466
16488
  const groupBg = isDark ? mix(palette.bg, palette.text, 85) : mix(palette.bg, palette.text, 92);
16467
16489
  const pillLabel = group.name;
16468
- const pillWidth = pillLabel.length * LEGEND_PILL_FONT_W7 + LEGEND_PILL_PAD7;
16469
- const gEl = legendG.append("g").attr("transform", `translate(${cursorX}, 0)`).attr("class", "infra-legend-group").attr("data-legend-group", group.name.toLowerCase()).attr("data-legend-type", group.type).style("cursor", "pointer");
16490
+ const pillWidth = pillLabel.length * LEGEND_PILL_FONT_W + LEGEND_PILL_PAD;
16491
+ const gEl = legendG.append("g").attr("transform", `translate(${cursorX}, 0)`).attr("class", "infra-legend-group").attr("data-legend-group", group.name.toLowerCase()).style("cursor", "pointer");
16470
16492
  if (isActive) {
16471
- gEl.append("rect").attr("width", group.width).attr("height", LEGEND_HEIGHT8).attr("rx", LEGEND_HEIGHT8 / 2).attr("fill", groupBg);
16493
+ gEl.append("rect").attr("width", group.width).attr("height", LEGEND_HEIGHT).attr("rx", LEGEND_HEIGHT / 2).attr("fill", groupBg);
16472
16494
  }
16473
- const pillXOff = isActive ? LEGEND_CAPSULE_PAD7 : 0;
16474
- const pillYOff = isActive ? LEGEND_CAPSULE_PAD7 : 0;
16475
- const pillH = LEGEND_HEIGHT8 - (isActive ? LEGEND_CAPSULE_PAD7 * 2 : 0);
16495
+ const pillXOff = isActive ? LEGEND_CAPSULE_PAD : 0;
16496
+ const pillYOff = isActive ? LEGEND_CAPSULE_PAD : 0;
16497
+ const pillH = LEGEND_HEIGHT - (isActive ? LEGEND_CAPSULE_PAD * 2 : 0);
16476
16498
  gEl.append("rect").attr("x", pillXOff).attr("y", pillYOff).attr("width", pillWidth).attr("height", pillH).attr("rx", pillH / 2).attr("fill", isActive ? palette.bg : groupBg);
16477
16499
  if (isActive) {
16478
- gEl.append("rect").attr("x", pillXOff).attr("y", pillYOff).attr("width", pillWidth).attr("height", pillH).attr("rx", pillH / 2).attr("fill", "none").attr("stroke", isDark ? mix(palette.textMuted, palette.bg, 50) : mix(palette.textMuted, palette.bg, 50)).attr("stroke-width", 0.75);
16500
+ gEl.append("rect").attr("x", pillXOff).attr("y", pillYOff).attr("width", pillWidth).attr("height", pillH).attr("rx", pillH / 2).attr("fill", "none").attr("stroke", mix(palette.textMuted, palette.bg, 50)).attr("stroke-width", 0.75);
16479
16501
  }
16480
- gEl.append("text").attr("x", pillXOff + pillWidth / 2).attr("y", LEGEND_HEIGHT8 / 2 + LEGEND_PILL_FONT_SIZE5 / 2 - 2).attr("font-family", FONT_FAMILY).attr("font-size", LEGEND_PILL_FONT_SIZE5).attr("font-weight", "500").attr("fill", isActive ? palette.text : palette.textMuted).attr("text-anchor", "middle").text(pillLabel);
16502
+ gEl.append("text").attr("x", pillXOff + pillWidth / 2).attr("y", LEGEND_HEIGHT / 2 + LEGEND_PILL_FONT_SIZE / 2 - 2).attr("font-family", FONT_FAMILY).attr("font-size", LEGEND_PILL_FONT_SIZE).attr("font-weight", "500").attr("fill", isActive ? palette.text : palette.textMuted).attr("text-anchor", "middle").text(pillLabel);
16481
16503
  if (isActive) {
16482
16504
  let entryX = pillXOff + pillWidth + 4;
16483
16505
  for (const entry of group.entries) {
16484
- const entryG = gEl.append("g").attr("class", "infra-legend-entry").attr("data-legend-entry", entry.key).attr("data-legend-type", group.type).attr("data-legend-color", entry.color).style("cursor", "pointer");
16485
- if (group.type === "tag" && group.tagKey) {
16486
- entryG.attr("data-legend-tag-group", group.tagKey);
16487
- }
16488
- entryG.append("circle").attr("cx", entryX + LEGEND_DOT_R8).attr("cy", LEGEND_HEIGHT8 / 2).attr("r", LEGEND_DOT_R8).attr("fill", entry.color);
16489
- const textX = entryX + LEGEND_DOT_R8 * 2 + LEGEND_ENTRY_DOT_GAP7;
16490
- entryG.append("text").attr("x", textX).attr("y", LEGEND_HEIGHT8 / 2 + LEGEND_ENTRY_FONT_SIZE6 / 2 - 1).attr("font-family", FONT_FAMILY).attr("font-size", LEGEND_ENTRY_FONT_SIZE6).attr("fill", palette.textMuted).text(entry.value);
16491
- entryX = textX + entry.value.length * LEGEND_ENTRY_FONT_W7 + LEGEND_ENTRY_TRAIL7;
16506
+ const entryG = gEl.append("g").attr("class", "infra-legend-entry").attr("data-legend-entry", entry.key.toLowerCase()).attr("data-legend-color", entry.color).attr("data-legend-type", group.type).attr("data-legend-tag-group", group.type === "tag" ? group.tagKey ?? "" : null).style("cursor", "pointer");
16507
+ entryG.append("circle").attr("cx", entryX + LEGEND_DOT_R).attr("cy", LEGEND_HEIGHT / 2).attr("r", LEGEND_DOT_R).attr("fill", entry.color);
16508
+ const textX = entryX + LEGEND_DOT_R * 2 + LEGEND_ENTRY_DOT_GAP;
16509
+ entryG.append("text").attr("x", textX).attr("y", LEGEND_HEIGHT / 2 + LEGEND_ENTRY_FONT_SIZE / 2 - 1).attr("font-family", FONT_FAMILY).attr("font-size", LEGEND_ENTRY_FONT_SIZE).attr("fill", palette.textMuted).text(entry.value);
16510
+ entryX = textX + entry.value.length * LEGEND_ENTRY_FONT_W + LEGEND_ENTRY_TRAIL;
16492
16511
  }
16493
16512
  }
16494
- cursorX += effectiveW(group) + LEGEND_GROUP_GAP5;
16513
+ cursorX += effectiveW(group) + LEGEND_GROUP_GAP;
16495
16514
  }
16496
- if (playback) {
16497
- const isExpanded = playback.expanded;
16498
- const groupBg = isDark ? mix(palette.bg, palette.text, 85) : mix(palette.bg, palette.text, 92);
16499
- const pillLabel = "Playback";
16500
- const pillWidth = pillLabel.length * LEGEND_PILL_FONT_W7 + LEGEND_PILL_PAD7;
16501
- const fullW = computePlaybackWidth(playback);
16502
- const pbG = legendG.append("g").attr("transform", `translate(${cursorX}, 0)`).attr("class", "infra-legend-group infra-playback-pill").style("cursor", "pointer");
16503
- if (isExpanded) {
16504
- pbG.append("rect").attr("width", fullW).attr("height", LEGEND_HEIGHT8).attr("rx", LEGEND_HEIGHT8 / 2).attr("fill", groupBg);
16505
- }
16506
- const pillXOff = isExpanded ? LEGEND_CAPSULE_PAD7 : 0;
16507
- const pillYOff = isExpanded ? LEGEND_CAPSULE_PAD7 : 0;
16508
- const pillH = LEGEND_HEIGHT8 - (isExpanded ? LEGEND_CAPSULE_PAD7 * 2 : 0);
16509
- pbG.append("rect").attr("x", pillXOff).attr("y", pillYOff).attr("width", pillWidth).attr("height", pillH).attr("rx", pillH / 2).attr("fill", isExpanded ? palette.bg : groupBg);
16510
- if (isExpanded) {
16511
- pbG.append("rect").attr("x", pillXOff).attr("y", pillYOff).attr("width", pillWidth).attr("height", pillH).attr("rx", pillH / 2).attr("fill", "none").attr("stroke", mix(palette.textMuted, palette.bg, 50)).attr("stroke-width", 0.75);
16512
- }
16513
- pbG.append("text").attr("x", pillXOff + pillWidth / 2).attr("y", LEGEND_HEIGHT8 / 2 + LEGEND_PILL_FONT_SIZE5 / 2 - 2).attr("font-family", FONT_FAMILY).attr("font-size", LEGEND_PILL_FONT_SIZE5).attr("font-weight", "500").attr("fill", isExpanded ? palette.text : palette.textMuted).attr("text-anchor", "middle").text(pillLabel);
16514
- if (isExpanded) {
16515
- let entryX = pillXOff + pillWidth + 8;
16516
- const entryY = LEGEND_HEIGHT8 / 2 + LEGEND_ENTRY_FONT_SIZE6 / 2 - 1;
16517
- const ppLabel = playback.paused ? "\u25B6" : "\u23F8";
16518
- pbG.append("text").attr("x", entryX).attr("y", entryY).attr("font-family", FONT_FAMILY).attr("font-size", LEGEND_PILL_FONT_SIZE5).attr("fill", palette.textMuted).attr("data-playback-action", "toggle-pause").style("cursor", "pointer").text(ppLabel);
16519
- entryX += LEGEND_PILL_FONT_SIZE5 * 0.8 + 6;
16520
- for (const s of playback.speedOptions) {
16521
- const label = `${s}x`;
16522
- const isActive = playback.speed === s;
16523
- const slotW = label.length * LEGEND_ENTRY_FONT_W7 + SPEED_BADGE_H_PAD * 2;
16524
- const badgeH = LEGEND_ENTRY_FONT_SIZE6 + SPEED_BADGE_V_PAD * 2;
16525
- const badgeY = (LEGEND_HEIGHT8 - badgeH) / 2;
16526
- const speedG = pbG.append("g").attr("data-playback-action", "set-speed").attr("data-playback-value", String(s)).style("cursor", "pointer");
16527
- speedG.append("rect").attr("x", entryX).attr("y", badgeY).attr("width", slotW).attr("height", badgeH).attr("rx", badgeH / 2).attr("fill", isActive ? palette.primary : "transparent");
16528
- speedG.append("text").attr("x", entryX + slotW / 2).attr("y", entryY).attr("font-family", FONT_FAMILY).attr("font-size", LEGEND_ENTRY_FONT_SIZE6).attr("font-weight", isActive ? "600" : "400").attr("fill", isActive ? palette.bg : palette.textMuted).attr("text-anchor", "middle").text(label);
16529
- entryX += slotW + SPEED_BADGE_GAP;
16530
- }
16531
- }
16532
- cursorX += fullW + LEGEND_GROUP_GAP5;
16533
- }
16534
- }
16535
- function renderInfra(container, layout, palette, isDark, title, titleLineNumber, tagGroups, activeGroup, animate, playback, expandedNodeIds, exportMode, collapsedNodes) {
16515
+ }
16516
+ function renderInfra(container, layout, palette, isDark, title, titleLineNumber, tagGroups, activeGroup, animate, _playback, expandedNodeIds, exportMode, collapsedNodes) {
16536
16517
  d3Selection9.select(container).selectAll(":not([data-d3-tooltip])").remove();
16537
16518
  const legendGroups = computeInfraLegendGroups(layout.nodes, tagGroups ?? [], palette, layout.edges);
16538
- const hasLegend = legendGroups.length > 0 || !!playback;
16519
+ const hasLegend = legendGroups.length > 0;
16539
16520
  const fixedLegend = !exportMode && hasLegend;
16540
- const legendOffset = hasLegend && !fixedLegend ? LEGEND_HEIGHT8 : 0;
16521
+ const legendOffset = hasLegend && !fixedLegend ? LEGEND_HEIGHT : 0;
16541
16522
  const titleOffset = title ? 40 : 0;
16542
16523
  const totalWidth = layout.width;
16543
16524
  const totalHeight = layout.height + titleOffset + legendOffset;
16544
16525
  const shouldAnimate = animate !== false;
16545
- const rootSvg = d3Selection9.select(container).append("svg").attr("xmlns", "http://www.w3.org/2000/svg").attr("width", "100%").attr("height", fixedLegend ? `calc(100% - ${LEGEND_HEIGHT8 + LEGEND_FIXED_GAP3}px)` : "100%").attr("viewBox", `0 0 ${totalWidth} ${totalHeight}`).attr("preserveAspectRatio", "xMidYMid meet");
16526
+ const rootSvg = d3Selection9.select(container).append("svg").attr("xmlns", "http://www.w3.org/2000/svg").attr("width", "100%").attr("height", fixedLegend ? `calc(100% - ${LEGEND_HEIGHT + LEGEND_FIXED_GAP3}px)` : "100%").attr("viewBox", `0 0 ${totalWidth} ${totalHeight}`).attr("preserveAspectRatio", "xMidYMid meet");
16546
16527
  if (shouldAnimate) {
16547
16528
  rootSvg.append("style").text(`
16548
16529
  @keyframes infra-pulse-warning {
@@ -16606,10 +16587,10 @@ function renderInfra(container, layout, palette, isDark, title, titleLineNumber,
16606
16587
  if (hasLegend) {
16607
16588
  if (fixedLegend) {
16608
16589
  const containerWidth = container.clientWidth || totalWidth;
16609
- const legendSvg = d3Selection9.select(container).append("svg").attr("class", "infra-legend-fixed").attr("width", "100%").attr("height", LEGEND_HEIGHT8 + LEGEND_FIXED_GAP3).attr("viewBox", `0 0 ${containerWidth} ${LEGEND_HEIGHT8 + LEGEND_FIXED_GAP3}`).attr("preserveAspectRatio", "xMidYMid meet").style("display", "block");
16610
- renderLegend3(legendSvg, legendGroups, containerWidth, LEGEND_FIXED_GAP3 / 2, palette, isDark, activeGroup ?? null, playback ?? void 0);
16590
+ const legendSvg = d3Selection9.select(container).append("svg").attr("class", "infra-legend-fixed").attr("width", "100%").attr("height", LEGEND_HEIGHT + LEGEND_FIXED_GAP3).attr("viewBox", `0 0 ${containerWidth} ${LEGEND_HEIGHT + LEGEND_FIXED_GAP3}`).attr("preserveAspectRatio", "xMidYMid meet").style("display", "block");
16591
+ renderLegend3(legendSvg, legendGroups, containerWidth, LEGEND_FIXED_GAP3 / 2, palette, isDark, activeGroup ?? null);
16611
16592
  } else {
16612
- renderLegend3(rootSvg, legendGroups, totalWidth, titleOffset + layout.height + 4, palette, isDark, activeGroup ?? null, playback ?? void 0);
16593
+ renderLegend3(rootSvg, legendGroups, totalWidth, titleOffset + layout.height + 4, palette, isDark, activeGroup ?? null);
16613
16594
  }
16614
16595
  }
16615
16596
  }
@@ -16620,7 +16601,7 @@ function parseAndLayoutInfra(content) {
16620
16601
  const layout = layoutInfra(computed);
16621
16602
  return { parsed, computed, layout };
16622
16603
  }
16623
- var d3Selection9, d3Shape7, NODE_FONT_SIZE4, META_FONT_SIZE4, META_LINE_HEIGHT8, EDGE_LABEL_FONT_SIZE7, GROUP_LABEL_FONT_SIZE2, NODE_BORDER_RADIUS, EDGE_STROKE_WIDTH8, NODE_STROKE_WIDTH8, OVERLOAD_STROKE_WIDTH, ROLE_DOT_RADIUS, NODE_HEADER_HEIGHT2, NODE_SEPARATOR_GAP2, NODE_PAD_BOTTOM2, COLLAPSE_BAR_HEIGHT5, COLLAPSE_BAR_INSET2, LEGEND_HEIGHT8, LEGEND_PILL_PAD7, LEGEND_PILL_FONT_SIZE5, LEGEND_PILL_FONT_W7, LEGEND_CAPSULE_PAD7, LEGEND_DOT_R8, LEGEND_ENTRY_FONT_SIZE6, LEGEND_ENTRY_FONT_W7, LEGEND_ENTRY_DOT_GAP7, LEGEND_ENTRY_TRAIL7, LEGEND_GROUP_GAP5, LEGEND_FIXED_GAP3, SPEED_BADGE_H_PAD, SPEED_BADGE_V_PAD, SPEED_BADGE_GAP, COLOR_HEALTHY, COLOR_WARNING, COLOR_OVERLOADED, FLOW_SPEED_MIN, FLOW_SPEED_MAX, PARTICLE_R, PARTICLE_COUNT_MIN, PARTICLE_COUNT_MAX, NODE_PULSE_SPEED, NODE_PULSE_OVERLOAD, REJECT_PARTICLE_R, REJECT_DROP_DISTANCE, REJECT_DURATION_MIN, REJECT_DURATION_MAX, REJECT_COUNT_MIN, REJECT_COUNT_MAX, lineGenerator7, PROP_DISPLAY, DESC_MAX_CHARS, RPS_FORMAT_KEYS, MS_FORMAT_KEYS, PCT_FORMAT_KEYS;
16604
+ var d3Selection9, d3Shape7, NODE_FONT_SIZE4, META_FONT_SIZE4, META_LINE_HEIGHT8, EDGE_LABEL_FONT_SIZE7, GROUP_LABEL_FONT_SIZE2, NODE_BORDER_RADIUS, EDGE_STROKE_WIDTH8, NODE_STROKE_WIDTH8, OVERLOAD_STROKE_WIDTH, ROLE_DOT_RADIUS, NODE_HEADER_HEIGHT2, NODE_SEPARATOR_GAP2, NODE_PAD_BOTTOM2, COLLAPSE_BAR_HEIGHT5, COLLAPSE_BAR_INSET2, LEGEND_FIXED_GAP3, COLOR_HEALTHY, COLOR_WARNING, COLOR_OVERLOADED, FLOW_SPEED_MIN, FLOW_SPEED_MAX, PARTICLE_R, PARTICLE_COUNT_MIN, PARTICLE_COUNT_MAX, NODE_PULSE_SPEED, NODE_PULSE_OVERLOAD, REJECT_PARTICLE_R, REJECT_DROP_DISTANCE, REJECT_DURATION_MIN, REJECT_DURATION_MAX, REJECT_COUNT_MIN, REJECT_COUNT_MAX, lineGenerator7, PROP_DISPLAY, DESC_MAX_CHARS, RPS_FORMAT_KEYS, MS_FORMAT_KEYS, PCT_FORMAT_KEYS;
16624
16605
  var init_renderer8 = __esm({
16625
16606
  "src/infra/renderer.ts"() {
16626
16607
  "use strict";
@@ -16633,6 +16614,7 @@ var init_renderer8 = __esm({
16633
16614
  init_parser9();
16634
16615
  init_compute();
16635
16616
  init_layout8();
16617
+ init_legend_constants();
16636
16618
  NODE_FONT_SIZE4 = 13;
16637
16619
  META_FONT_SIZE4 = 10;
16638
16620
  META_LINE_HEIGHT8 = 14;
@@ -16648,21 +16630,7 @@ var init_renderer8 = __esm({
16648
16630
  NODE_PAD_BOTTOM2 = 10;
16649
16631
  COLLAPSE_BAR_HEIGHT5 = 6;
16650
16632
  COLLAPSE_BAR_INSET2 = 0;
16651
- LEGEND_HEIGHT8 = 28;
16652
- LEGEND_PILL_PAD7 = 16;
16653
- LEGEND_PILL_FONT_SIZE5 = 11;
16654
- LEGEND_PILL_FONT_W7 = LEGEND_PILL_FONT_SIZE5 * 0.6;
16655
- LEGEND_CAPSULE_PAD7 = 4;
16656
- LEGEND_DOT_R8 = 4;
16657
- LEGEND_ENTRY_FONT_SIZE6 = 10;
16658
- LEGEND_ENTRY_FONT_W7 = LEGEND_ENTRY_FONT_SIZE6 * 0.6;
16659
- LEGEND_ENTRY_DOT_GAP7 = 4;
16660
- LEGEND_ENTRY_TRAIL7 = 8;
16661
- LEGEND_GROUP_GAP5 = 12;
16662
16633
  LEGEND_FIXED_GAP3 = 16;
16663
- SPEED_BADGE_H_PAD = 5;
16664
- SPEED_BADGE_V_PAD = 3;
16665
- SPEED_BADGE_GAP = 6;
16666
16634
  COLOR_HEALTHY = "#22c55e";
16667
16635
  COLOR_WARNING = "#eab308";
16668
16636
  COLOR_OVERLOADED = "#ef4444";
@@ -17682,9 +17650,8 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
17682
17650
  const GROUP_PADDING_BOTTOM = 8;
17683
17651
  const GROUP_LABEL_SIZE = 11;
17684
17652
  const titleOffset = title ? TITLE_HEIGHT5 : 0;
17685
- const legendOffset = parsed.tagGroups.length > 0 ? LEGEND_HEIGHT9 + LEGEND_BOTTOM_GAP : 0;
17686
17653
  const groupOffset = groups.length > 0 ? GROUP_PADDING_TOP + GROUP_LABEL_SIZE : 0;
17687
- const participantStartY = TOP_MARGIN + titleOffset + legendOffset + PARTICIPANT_Y_OFFSET + groupOffset;
17654
+ const participantStartY = TOP_MARGIN + titleOffset + PARTICIPANT_Y_OFFSET + groupOffset;
17688
17655
  const lifelineStartY0 = participantStartY + PARTICIPANT_BOX_HEIGHT;
17689
17656
  const hasActors = participants.some((p) => p.type === "actor");
17690
17657
  const messageStartOffset = MESSAGE_START_OFFSET + (hasActors ? 20 : 0);
@@ -17766,7 +17733,9 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
17766
17733
  participants.length * PARTICIPANT_GAP,
17767
17734
  PARTICIPANT_BOX_WIDTH + 40
17768
17735
  );
17769
- const totalHeight = participantStartY + PARTICIPANT_BOX_HEIGHT + Math.max(lifelineLength, 40) + 40;
17736
+ const contentHeight = participantStartY + PARTICIPANT_BOX_HEIGHT + Math.max(lifelineLength, 40) + 40;
17737
+ const legendSpace = parsed.tagGroups.length > 0 ? LEGEND_HEIGHT : 0;
17738
+ const totalHeight = contentHeight + legendSpace;
17770
17739
  const containerWidth = options?.exportWidth ?? container.getBoundingClientRect().width;
17771
17740
  const svgWidth = Math.max(totalWidth, containerWidth);
17772
17741
  const diagramWidth = participants.length * PARTICIPANT_GAP;
@@ -17824,13 +17793,13 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
17824
17793
  }
17825
17794
  }
17826
17795
  if (parsed.tagGroups.length > 0) {
17827
- const legendY = TOP_MARGIN + titleOffset;
17796
+ const legendY = contentHeight;
17828
17797
  const groupBg = isDark ? mix(palette.surface, palette.bg, 50) : mix(palette.surface, palette.bg, 30);
17829
17798
  const legendItems = [];
17830
17799
  for (const tg of parsed.tagGroups) {
17831
17800
  if (tg.entries.length === 0) continue;
17832
17801
  const isActive = !!activeTagGroup && tg.name.toLowerCase() === activeTagGroup.toLowerCase();
17833
- const pillWidth = tg.name.length * LEGEND_PILL_FONT_W8 + LEGEND_PILL_PAD8;
17802
+ const pillWidth = tg.name.length * LEGEND_PILL_FONT_W + LEGEND_PILL_PAD;
17834
17803
  const entries = tg.entries.map((e) => ({
17835
17804
  value: e.value,
17836
17805
  color: resolveColor(e.color)
@@ -17839,38 +17808,42 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
17839
17808
  if (isActive) {
17840
17809
  let entriesWidth = 0;
17841
17810
  for (const entry of entries) {
17842
- entriesWidth += LEGEND_DOT_R9 * 2 + LEGEND_ENTRY_DOT_GAP8 + entry.value.length * LEGEND_ENTRY_FONT_W8 + LEGEND_ENTRY_TRAIL8;
17811
+ entriesWidth += LEGEND_DOT_R * 2 + LEGEND_ENTRY_DOT_GAP + entry.value.length * LEGEND_ENTRY_FONT_W + LEGEND_ENTRY_TRAIL;
17843
17812
  }
17844
- totalWidth2 = LEGEND_CAPSULE_PAD8 * 2 + pillWidth + 4 + entriesWidth;
17813
+ totalWidth2 = LEGEND_CAPSULE_PAD * 2 + pillWidth + 4 + entriesWidth;
17845
17814
  }
17846
17815
  legendItems.push({ group: tg, isActive, pillWidth, totalWidth: totalWidth2, entries });
17847
17816
  }
17848
- const totalLegendWidth = legendItems.reduce((s, item) => s + item.totalWidth, 0) + (legendItems.length - 1) * LEGEND_GROUP_GAP6;
17817
+ const totalLegendWidth = legendItems.reduce((s, item) => s + item.totalWidth, 0) + (legendItems.length - 1) * LEGEND_GROUP_GAP;
17849
17818
  let legendX = (svgWidth - totalLegendWidth) / 2;
17819
+ const legendContainer = svg.append("g").attr("class", "sequence-legend");
17820
+ if (activeTagGroup) {
17821
+ legendContainer.attr("data-legend-active", activeTagGroup.toLowerCase());
17822
+ }
17850
17823
  for (const item of legendItems) {
17851
- const gEl = svg.append("g").attr("transform", `translate(${legendX}, ${legendY})`).attr("class", "sequence-legend-group").attr("data-legend-group", item.group.name.toLowerCase()).style("cursor", "pointer");
17824
+ const gEl = legendContainer.append("g").attr("transform", `translate(${legendX}, ${legendY})`).attr("class", "sequence-legend-group").attr("data-legend-group", item.group.name.toLowerCase()).style("cursor", "pointer");
17852
17825
  if (item.isActive) {
17853
- gEl.append("rect").attr("width", item.totalWidth).attr("height", LEGEND_HEIGHT9).attr("rx", LEGEND_HEIGHT9 / 2).attr("fill", groupBg);
17826
+ gEl.append("rect").attr("width", item.totalWidth).attr("height", LEGEND_HEIGHT).attr("rx", LEGEND_HEIGHT / 2).attr("fill", groupBg);
17854
17827
  }
17855
- const pillXOff = item.isActive ? LEGEND_CAPSULE_PAD8 : 0;
17856
- const pillYOff = item.isActive ? LEGEND_CAPSULE_PAD8 : 0;
17857
- const pillH = LEGEND_HEIGHT9 - (item.isActive ? LEGEND_CAPSULE_PAD8 * 2 : 0);
17828
+ const pillXOff = item.isActive ? LEGEND_CAPSULE_PAD : 0;
17829
+ const pillYOff = item.isActive ? LEGEND_CAPSULE_PAD : 0;
17830
+ const pillH = LEGEND_HEIGHT - (item.isActive ? LEGEND_CAPSULE_PAD * 2 : 0);
17858
17831
  gEl.append("rect").attr("x", pillXOff).attr("y", pillYOff).attr("width", item.pillWidth).attr("height", pillH).attr("rx", pillH / 2).attr("fill", item.isActive ? palette.bg : groupBg);
17859
17832
  if (item.isActive) {
17860
17833
  gEl.append("rect").attr("x", pillXOff).attr("y", pillYOff).attr("width", item.pillWidth).attr("height", pillH).attr("rx", pillH / 2).attr("fill", "none").attr("stroke", mix(palette.textMuted, palette.bg, 50)).attr("stroke-width", 0.75);
17861
17834
  }
17862
- gEl.append("text").attr("x", pillXOff + item.pillWidth / 2).attr("y", LEGEND_HEIGHT9 / 2 + LEGEND_PILL_FONT_SIZE6 / 2 - 2).attr("font-size", LEGEND_PILL_FONT_SIZE6).attr("font-weight", "500").attr("fill", item.isActive ? palette.text : palette.textMuted).attr("text-anchor", "middle").text(item.group.name);
17835
+ gEl.append("text").attr("x", pillXOff + item.pillWidth / 2).attr("y", LEGEND_HEIGHT / 2 + LEGEND_PILL_FONT_SIZE / 2 - 2).attr("font-size", LEGEND_PILL_FONT_SIZE).attr("font-weight", "500").attr("fill", item.isActive ? palette.text : palette.textMuted).attr("text-anchor", "middle").text(item.group.name);
17863
17836
  if (item.isActive) {
17864
17837
  let entryX = pillXOff + item.pillWidth + 4;
17865
17838
  for (const entry of item.entries) {
17866
17839
  const entryG = gEl.append("g").attr("data-legend-entry", entry.value.toLowerCase()).style("cursor", "pointer");
17867
- entryG.append("circle").attr("cx", entryX + LEGEND_DOT_R9).attr("cy", LEGEND_HEIGHT9 / 2).attr("r", LEGEND_DOT_R9).attr("fill", entry.color);
17868
- const textX = entryX + LEGEND_DOT_R9 * 2 + LEGEND_ENTRY_DOT_GAP8;
17869
- entryG.append("text").attr("x", textX).attr("y", LEGEND_HEIGHT9 / 2 + LEGEND_ENTRY_FONT_SIZE7 / 2 - 1).attr("font-size", LEGEND_ENTRY_FONT_SIZE7).attr("fill", palette.textMuted).text(entry.value);
17870
- entryX = textX + entry.value.length * LEGEND_ENTRY_FONT_W8 + LEGEND_ENTRY_TRAIL8;
17840
+ entryG.append("circle").attr("cx", entryX + LEGEND_DOT_R).attr("cy", LEGEND_HEIGHT / 2).attr("r", LEGEND_DOT_R).attr("fill", entry.color);
17841
+ const textX = entryX + LEGEND_DOT_R * 2 + LEGEND_ENTRY_DOT_GAP;
17842
+ entryG.append("text").attr("x", textX).attr("y", LEGEND_HEIGHT / 2 + LEGEND_ENTRY_FONT_SIZE / 2 - 1).attr("font-size", LEGEND_ENTRY_FONT_SIZE).attr("fill", palette.textMuted).text(entry.value);
17843
+ entryX = textX + entry.value.length * LEGEND_ENTRY_FONT_W + LEGEND_ENTRY_TRAIL;
17871
17844
  }
17872
17845
  }
17873
- legendX += item.totalWidth + LEGEND_GROUP_GAP6;
17846
+ legendX += item.totalWidth + LEGEND_GROUP_GAP;
17874
17847
  }
17875
17848
  }
17876
17849
  for (const group of groups) {
@@ -18391,7 +18364,7 @@ function renderParticipant(svg, participant, cx, cy, palette, isDark, color, tag
18391
18364
  });
18392
18365
  }
18393
18366
  }
18394
- var d3Selection11, PARTICIPANT_GAP, PARTICIPANT_BOX_WIDTH, PARTICIPANT_BOX_HEIGHT, TOP_MARGIN, TITLE_HEIGHT5, PARTICIPANT_Y_OFFSET, SERVICE_BORDER_RADIUS, MESSAGE_START_OFFSET, LIFELINE_TAIL, ARROWHEAD_SIZE, NOTE_MAX_W, NOTE_FOLD, NOTE_PAD_H, NOTE_PAD_V, NOTE_FONT_SIZE, NOTE_LINE_H, NOTE_GAP, NOTE_CHAR_W, NOTE_CHARS_PER_LINE, COLLAPSED_NOTE_H, COLLAPSED_NOTE_W, LEGEND_HEIGHT9, LEGEND_PILL_PAD8, LEGEND_PILL_FONT_SIZE6, LEGEND_PILL_FONT_W8, LEGEND_CAPSULE_PAD8, LEGEND_DOT_R9, LEGEND_ENTRY_FONT_SIZE7, LEGEND_ENTRY_FONT_W8, LEGEND_ENTRY_DOT_GAP8, LEGEND_ENTRY_TRAIL8, LEGEND_GROUP_GAP6, LEGEND_BOTTOM_GAP, LABEL_CHAR_WIDTH, LABEL_MAX_CHARS, fill, stroke, SW, W, H;
18367
+ var d3Selection11, PARTICIPANT_GAP, PARTICIPANT_BOX_WIDTH, PARTICIPANT_BOX_HEIGHT, TOP_MARGIN, TITLE_HEIGHT5, PARTICIPANT_Y_OFFSET, SERVICE_BORDER_RADIUS, MESSAGE_START_OFFSET, LIFELINE_TAIL, ARROWHEAD_SIZE, NOTE_MAX_W, NOTE_FOLD, NOTE_PAD_H, NOTE_PAD_V, NOTE_FONT_SIZE, NOTE_LINE_H, NOTE_GAP, NOTE_CHAR_W, NOTE_CHARS_PER_LINE, COLLAPSED_NOTE_H, COLLAPSED_NOTE_W, LABEL_CHAR_WIDTH, LABEL_MAX_CHARS, fill, stroke, SW, W, H;
18395
18368
  var init_renderer9 = __esm({
18396
18369
  "src/sequence/renderer.ts"() {
18397
18370
  "use strict";
@@ -18402,6 +18375,7 @@ var init_renderer9 = __esm({
18402
18375
  init_colors();
18403
18376
  init_parser();
18404
18377
  init_tag_resolution();
18378
+ init_legend_constants();
18405
18379
  PARTICIPANT_GAP = 160;
18406
18380
  PARTICIPANT_BOX_WIDTH = 120;
18407
18381
  PARTICIPANT_BOX_HEIGHT = 50;
@@ -18423,18 +18397,6 @@ var init_renderer9 = __esm({
18423
18397
  NOTE_CHARS_PER_LINE = Math.floor((NOTE_MAX_W - NOTE_PAD_H * 2 - NOTE_FOLD) / NOTE_CHAR_W);
18424
18398
  COLLAPSED_NOTE_H = 20;
18425
18399
  COLLAPSED_NOTE_W = 40;
18426
- LEGEND_HEIGHT9 = 28;
18427
- LEGEND_PILL_PAD8 = 16;
18428
- LEGEND_PILL_FONT_SIZE6 = 11;
18429
- LEGEND_PILL_FONT_W8 = LEGEND_PILL_FONT_SIZE6 * 0.6;
18430
- LEGEND_CAPSULE_PAD8 = 4;
18431
- LEGEND_DOT_R9 = 4;
18432
- LEGEND_ENTRY_FONT_SIZE7 = 10;
18433
- LEGEND_ENTRY_FONT_W8 = LEGEND_ENTRY_FONT_SIZE7 * 0.6;
18434
- LEGEND_ENTRY_DOT_GAP8 = 4;
18435
- LEGEND_ENTRY_TRAIL8 = 8;
18436
- LEGEND_GROUP_GAP6 = 12;
18437
- LEGEND_BOTTOM_GAP = 8;
18438
18400
  LABEL_CHAR_WIDTH = 7.5;
18439
18401
  LABEL_MAX_CHARS = Math.floor((PARTICIPANT_BOX_WIDTH - 10) / LABEL_CHAR_WIDTH);
18440
18402
  fill = (palette, isDark, color) => color ? mix(color, isDark ? palette.surface : palette.bg, isDark ? 30 : 40) : isDark ? mix(palette.overlay, palette.surface, 50) : mix(palette.bg, palette.surface, 50);
@@ -18522,7 +18484,7 @@ function addDurationToDate(startDate, amount, unit) {
18522
18484
  return `${endYear}-${endMonth}-${endDay}`;
18523
18485
  }
18524
18486
  }
18525
- function parseD3(content, palette) {
18487
+ function parseVisualization(content, palette) {
18526
18488
  const result = {
18527
18489
  type: null,
18528
18490
  title: null,
@@ -20042,9 +20004,9 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
20042
20004
  const scaleMargin = timelineScale ? 40 : 0;
20043
20005
  const markerMargin = timelineMarkers.length > 0 ? 30 : 0;
20044
20006
  const margin = {
20045
- top: 104 + markerMargin + tagLegendReserve,
20007
+ top: 104 + markerMargin,
20046
20008
  right: 40 + scaleMargin,
20047
- bottom: 40,
20009
+ bottom: 40 + tagLegendReserve,
20048
20010
  left: 60 + scaleMargin
20049
20011
  };
20050
20012
  const innerWidth = width - margin.left - margin.right;
@@ -20151,9 +20113,9 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
20151
20113
  const scaleMargin = timelineScale ? 40 : 0;
20152
20114
  const markerMargin = timelineMarkers.length > 0 ? 30 : 0;
20153
20115
  const margin = {
20154
- top: 104 + markerMargin + tagLegendReserve,
20116
+ top: 104 + markerMargin,
20155
20117
  right: 200,
20156
- bottom: 40,
20118
+ bottom: 40 + tagLegendReserve,
20157
20119
  left: 60 + scaleMargin
20158
20120
  };
20159
20121
  const innerWidth = width - margin.left - margin.right;
@@ -20290,9 +20252,9 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
20290
20252
  const dynamicLeftMargin = Math.max(120, maxGroupNameLen * 7 + 30);
20291
20253
  const baseTopMargin = title ? 50 : 20;
20292
20254
  const margin = {
20293
- top: baseTopMargin + (timelineScale ? 40 : 0) + markerMargin + tagLegendReserve,
20255
+ top: baseTopMargin + (timelineScale ? 40 : 0) + markerMargin,
20294
20256
  right: 40,
20295
- bottom: 40 + scaleMargin,
20257
+ bottom: 40 + scaleMargin + tagLegendReserve,
20296
20258
  left: dynamicLeftMargin
20297
20259
  };
20298
20260
  const innerWidth = width - margin.left - margin.right;
@@ -20436,9 +20398,9 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
20436
20398
  const scaleMargin = timelineScale ? 24 : 0;
20437
20399
  const markerMargin = timelineMarkers.length > 0 ? 30 : 0;
20438
20400
  const margin = {
20439
- top: 104 + (timelineScale ? 40 : 0) + markerMargin + tagLegendReserve,
20401
+ top: 104 + (timelineScale ? 40 : 0) + markerMargin,
20440
20402
  right: 40,
20441
- bottom: 40 + scaleMargin,
20403
+ bottom: 40 + scaleMargin + tagLegendReserve,
20442
20404
  left: 60
20443
20405
  };
20444
20406
  const innerWidth = width - margin.left - margin.right;
@@ -20569,17 +20531,17 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
20569
20531
  });
20570
20532
  }
20571
20533
  if (parsed.timelineTagGroups.length > 0) {
20572
- const LG_HEIGHT = 28;
20573
- const LG_PILL_PAD = 16;
20574
- const LG_PILL_FONT_SIZE = 11;
20575
- const LG_PILL_FONT_W = LG_PILL_FONT_SIZE * 0.6;
20576
- const LG_CAPSULE_PAD = 4;
20577
- const LG_DOT_R = 4;
20578
- const LG_ENTRY_FONT_SIZE = 10;
20579
- const LG_ENTRY_FONT_W = LG_ENTRY_FONT_SIZE * 0.6;
20580
- const LG_ENTRY_DOT_GAP = 4;
20581
- const LG_ENTRY_TRAIL = 8;
20582
- const LG_GROUP_GAP = 12;
20534
+ const LG_HEIGHT = LEGEND_HEIGHT;
20535
+ const LG_PILL_PAD = LEGEND_PILL_PAD;
20536
+ const LG_PILL_FONT_SIZE = LEGEND_PILL_FONT_SIZE;
20537
+ const LG_PILL_FONT_W = LEGEND_PILL_FONT_W;
20538
+ const LG_CAPSULE_PAD = LEGEND_CAPSULE_PAD;
20539
+ const LG_DOT_R = LEGEND_DOT_R;
20540
+ const LG_ENTRY_FONT_SIZE = LEGEND_ENTRY_FONT_SIZE;
20541
+ const LG_ENTRY_FONT_W = LEGEND_ENTRY_FONT_W;
20542
+ const LG_ENTRY_DOT_GAP = LEGEND_ENTRY_DOT_GAP;
20543
+ const LG_ENTRY_TRAIL = LEGEND_ENTRY_TRAIL;
20544
+ const LG_GROUP_GAP = LEGEND_GROUP_GAP;
20583
20545
  const LG_ICON_W = 20;
20584
20546
  const mainSvg = d3Selection12.select(container).select("svg");
20585
20547
  const mainG = mainSvg.select("g");
@@ -20612,6 +20574,7 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
20612
20574
  );
20613
20575
  }, drawLegend2 = function() {
20614
20576
  mainSvg.selectAll(".tl-tag-legend-group").remove();
20577
+ mainSvg.selectAll(".tl-tag-legend-container").remove();
20615
20578
  const effectiveColorKey = (currentActiveGroup ?? currentSwimlaneGroup)?.toLowerCase() ?? null;
20616
20579
  const visibleGroups = viewMode ? legendGroups.filter(
20617
20580
  (lg) => effectiveColorKey != null && lg.group.name.toLowerCase() === effectiveColorKey
@@ -20622,13 +20585,17 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
20622
20585
  return s + (isActive ? lg.expandedWidth : lg.minifiedWidth);
20623
20586
  }, 0) + (visibleGroups.length - 1) * LG_GROUP_GAP;
20624
20587
  let cx = (width - totalW) / 2;
20588
+ const legendContainer = mainSvg.append("g").attr("class", "tl-tag-legend-container");
20589
+ if (currentActiveGroup) {
20590
+ legendContainer.attr("data-legend-active", currentActiveGroup.toLowerCase());
20591
+ }
20625
20592
  for (const lg of visibleGroups) {
20626
20593
  const groupKey = lg.group.name.toLowerCase();
20627
20594
  const isActive = viewMode || currentActiveGroup != null && currentActiveGroup.toLowerCase() === groupKey;
20628
20595
  const isSwimActive = currentSwimlaneGroup != null && currentSwimlaneGroup.toLowerCase() === groupKey;
20629
20596
  const pillLabel = lg.group.name;
20630
20597
  const pillWidth = pillLabel.length * LG_PILL_FONT_W + LG_PILL_PAD;
20631
- const gEl = mainSvg.append("g").attr("transform", `translate(${cx}, ${legendY})`).attr("class", "tl-tag-legend-group tl-tag-legend-entry").attr("data-legend-group", groupKey).attr("data-tag-group", groupKey).attr("data-legend-entry", "__group__");
20598
+ const gEl = legendContainer.append("g").attr("transform", `translate(${cx}, ${legendY})`).attr("class", "tl-tag-legend-group tl-tag-legend-entry").attr("data-legend-group", groupKey).attr("data-tag-group", groupKey).attr("data-legend-entry", "__group__");
20632
20599
  if (!viewMode) {
20633
20600
  gEl.style("cursor", "pointer").on("click", () => {
20634
20601
  currentActiveGroup = currentActiveGroup === groupKey ? null : groupKey;
@@ -20718,7 +20685,7 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
20718
20685
  });
20719
20686
  };
20720
20687
  var drawSwimlaneIcon = drawSwimlaneIcon2, relayout = relayout2, drawLegend = drawLegend2, recolorEvents = recolorEvents2;
20721
- const legendY = title ? 50 : 10;
20688
+ const legendY = height - LG_HEIGHT - 4;
20722
20689
  const groupBg = isDark ? mix(palette.surface, palette.bg, 50) : mix(palette.surface, palette.bg, 30);
20723
20690
  const legendGroups = parsed.timelineTagGroups.map((g) => {
20724
20691
  const pillW = g.name.length * LG_PILL_FONT_W + LG_PILL_PAD;
@@ -21476,7 +21443,7 @@ function finalizeSvgExport(container, theme, palette, options) {
21476
21443
  }
21477
21444
  return svgHtml;
21478
21445
  }
21479
- async function renderD3ForExport(content, theme, palette, orgExportState, options) {
21446
+ async function renderForExport(content, theme, palette, orgExportState, options) {
21480
21447
  const { parseDgmoChartType: parseDgmoChartType2 } = await Promise.resolve().then(() => (init_dgmo_router(), dgmo_router_exports));
21481
21448
  const detectedType = parseDgmoChartType2(content);
21482
21449
  if (detectedType === "org") {
@@ -21489,7 +21456,7 @@ async function renderD3ForExport(content, theme, palette, orgExportState, option
21489
21456
  const orgParsed = parseOrg2(content, effectivePalette2);
21490
21457
  if (orgParsed.error) return "";
21491
21458
  const collapsedNodes = orgExportState?.collapsedNodes;
21492
- const activeTagGroup = orgExportState?.activeTagGroup ?? null;
21459
+ const activeTagGroup = orgExportState?.activeTagGroup ?? options?.tagGroup ?? null;
21493
21460
  const hiddenAttributes = orgExportState?.hiddenAttributes;
21494
21461
  const { parsed: effectiveParsed, hiddenCounts } = collapsedNodes && collapsedNodes.size > 0 ? collapseOrgTree2(orgParsed, collapsedNodes) : { parsed: orgParsed, hiddenCounts: /* @__PURE__ */ new Map() };
21495
21462
  const orgLayout = layoutOrg2(
@@ -21518,7 +21485,7 @@ async function renderD3ForExport(content, theme, palette, orgExportState, option
21518
21485
  const sitemapParsed = parseSitemap2(content, effectivePalette2);
21519
21486
  if (sitemapParsed.error || sitemapParsed.roots.length === 0) return "";
21520
21487
  const collapsedNodes = orgExportState?.collapsedNodes;
21521
- const activeTagGroup = orgExportState?.activeTagGroup ?? null;
21488
+ const activeTagGroup = orgExportState?.activeTagGroup ?? options?.tagGroup ?? null;
21522
21489
  const hiddenAttributes = orgExportState?.hiddenAttributes;
21523
21490
  const { parsed: effectiveParsed, hiddenCounts } = collapsedNodes && collapsedNodes.size > 0 ? collapseSitemapTree2(sitemapParsed, collapsedNodes) : { parsed: sitemapParsed, hiddenCounts: /* @__PURE__ */ new Map() };
21524
21491
  const sitemapLayout = layoutSitemap2(
@@ -21546,7 +21513,7 @@ async function renderD3ForExport(content, theme, palette, orgExportState, option
21546
21513
  container2.style.position = "absolute";
21547
21514
  container2.style.left = "-9999px";
21548
21515
  document.body.appendChild(container2);
21549
- renderKanban2(container2, kanbanParsed, effectivePalette2, theme === "dark");
21516
+ renderKanban2(container2, kanbanParsed, effectivePalette2, theme === "dark", void 0, void 0, options?.tagGroup);
21550
21517
  return finalizeSvgExport(container2, theme, effectivePalette2, options);
21551
21518
  }
21552
21519
  if (detectedType === "class") {
@@ -21578,7 +21545,7 @@ async function renderD3ForExport(content, theme, palette, orgExportState, option
21578
21545
  const exportWidth = erLayout.width + PADDING * 2;
21579
21546
  const exportHeight = erLayout.height + PADDING * 2 + titleOffset;
21580
21547
  const container2 = createExportContainer(exportWidth, exportHeight);
21581
- renderERDiagram2(container2, erParsed, erLayout, effectivePalette2, theme === "dark", void 0, { width: exportWidth, height: exportHeight });
21548
+ renderERDiagram2(container2, erParsed, erLayout, effectivePalette2, theme === "dark", void 0, { width: exportWidth, height: exportHeight }, options?.tagGroup);
21582
21549
  return finalizeSvgExport(container2, theme, effectivePalette2, options);
21583
21550
  }
21584
21551
  if (detectedType === "initiative-status") {
@@ -21615,7 +21582,7 @@ async function renderD3ForExport(content, theme, palette, orgExportState, option
21615
21582
  const exportHeight = c4Layout.height + PADDING * 2 + titleOffset;
21616
21583
  const container2 = createExportContainer(exportWidth, exportHeight);
21617
21584
  const renderFn = c4Level === "deployment" || c4Level === "components" && c4System && c4Container || c4Level === "containers" && c4System ? renderC4Containers2 : renderC4Context2;
21618
- renderFn(container2, c4Parsed, c4Layout, effectivePalette2, theme === "dark", void 0, { width: exportWidth, height: exportHeight });
21585
+ renderFn(container2, c4Parsed, c4Layout, effectivePalette2, theme === "dark", void 0, { width: exportWidth, height: exportHeight }, options?.tagGroup);
21619
21586
  return finalizeSvgExport(container2, theme, effectivePalette2, options);
21620
21587
  }
21621
21588
  if (detectedType === "flowchart") {
@@ -21638,16 +21605,16 @@ async function renderD3ForExport(content, theme, palette, orgExportState, option
21638
21605
  const effectivePalette2 = await resolveExportPalette(theme, palette);
21639
21606
  const infraParsed = parseInfra2(content);
21640
21607
  if (infraParsed.error || infraParsed.nodes.length === 0) return "";
21641
- const selectedScenario = options?.scenario ? infraParsed.scenarios.find((s) => s.name.toLowerCase() === options.scenario.toLowerCase()) ?? null : null;
21642
- const infraComputed = computeInfra2(infraParsed, selectedScenario ? { scenario: selectedScenario } : {});
21608
+ const infraComputed = computeInfra2(infraParsed);
21643
21609
  const infraLayout = layoutInfra2(infraComputed);
21610
+ const activeTagGroup = options?.tagGroup ?? null;
21644
21611
  const titleOffset = infraParsed.title ? 40 : 0;
21645
21612
  const legendGroups = computeInfraLegendGroups2(infraLayout.nodes, infraParsed.tagGroups, effectivePalette2);
21646
21613
  const legendOffset = legendGroups.length > 0 ? 28 : 0;
21647
21614
  const exportWidth = infraLayout.width;
21648
21615
  const exportHeight = infraLayout.height + titleOffset + legendOffset;
21649
21616
  const container2 = createExportContainer(exportWidth, exportHeight);
21650
- renderInfra2(container2, infraLayout, effectivePalette2, theme === "dark", infraParsed.title, infraParsed.titleLineNumber, infraParsed.tagGroups, null, false, null, null, true);
21617
+ renderInfra2(container2, infraLayout, effectivePalette2, theme === "dark", infraParsed.title, infraParsed.titleLineNumber, infraParsed.tagGroups, activeTagGroup, false, null, null, true);
21651
21618
  const infraSvg = container2.querySelector("svg");
21652
21619
  if (infraSvg) {
21653
21620
  infraSvg.setAttribute("width", String(exportWidth));
@@ -21667,7 +21634,7 @@ async function renderD3ForExport(content, theme, palette, orgExportState, option
21667
21634
  renderState2(container2, stateParsed, layout, effectivePalette2, theme === "dark", void 0, { width: EXPORT_WIDTH, height: EXPORT_HEIGHT });
21668
21635
  return finalizeSvgExport(container2, theme, effectivePalette2, options);
21669
21636
  }
21670
- const parsed = parseD3(content, palette);
21637
+ const parsed = parseVisualization(content, palette);
21671
21638
  if (parsed.error && parsed.type !== "sequence") {
21672
21639
  const looksLikeSequence2 = /->|~>|<-/.test(content);
21673
21640
  if (!looksLikeSequence2) return "";
@@ -21691,7 +21658,8 @@ async function renderD3ForExport(content, theme, palette, orgExportState, option
21691
21658
  const seqParsed = parseSequenceDgmo2(content);
21692
21659
  if (seqParsed.error || seqParsed.participants.length === 0) return "";
21693
21660
  renderSequenceDiagram2(container, seqParsed, effectivePalette, isDark, void 0, {
21694
- exportWidth: EXPORT_WIDTH
21661
+ exportWidth: EXPORT_WIDTH,
21662
+ activeTagGroup: options?.tagGroup
21695
21663
  });
21696
21664
  } else if (parsed.type === "wordcloud") {
21697
21665
  await renderWordCloudAsync(container, parsed, effectivePalette, isDark, dims);
@@ -21705,7 +21673,7 @@ async function renderD3ForExport(content, theme, palette, orgExportState, option
21705
21673
  isDark,
21706
21674
  void 0,
21707
21675
  dims,
21708
- orgExportState?.activeTagGroup,
21676
+ orgExportState?.activeTagGroup ?? options?.tagGroup,
21709
21677
  orgExportState?.swimlaneTagGroup
21710
21678
  );
21711
21679
  } else if (parsed.type === "venn") {
@@ -21734,6 +21702,7 @@ var init_d3 = __esm({
21734
21702
  init_diagnostics();
21735
21703
  init_parsing();
21736
21704
  init_tag_groups();
21705
+ init_legend_constants();
21737
21706
  DEFAULT_CLOUD_OPTIONS = {
21738
21707
  rotate: "none",
21739
21708
  max: 0,
@@ -21877,20 +21846,18 @@ var init_d3 = __esm({
21877
21846
  // src/index.ts
21878
21847
  var index_exports = {};
21879
21848
  __export(index_exports, {
21880
- DGMO_CHART_TYPE_MAP: () => DGMO_CHART_TYPE_MAP,
21881
21849
  INFRA_BEHAVIOR_KEYS: () => INFRA_BEHAVIOR_KEYS,
21882
21850
  RULE_COUNT: () => RULE_COUNT,
21883
- STANDARD_CHART_TYPES: () => STANDARD_CHART_TYPES,
21884
21851
  addDurationToDate: () => addDurationToDate,
21885
21852
  applyGroupOrdering: () => applyGroupOrdering,
21886
21853
  applyPositionOverrides: () => applyPositionOverrides,
21887
21854
  boldPalette: () => boldPalette,
21888
- buildEChartsOption: () => buildEChartsOption,
21889
- buildEChartsOptionFromChart: () => buildEChartsOptionFromChart,
21855
+ buildExtendedChartOption: () => buildExtendedChartOption,
21890
21856
  buildMermaidQuadrant: () => buildMermaidQuadrant,
21891
21857
  buildMermaidThemeVars: () => buildMermaidThemeVars,
21892
21858
  buildNoteMessageMap: () => buildNoteMessageMap,
21893
21859
  buildRenderSequence: () => buildRenderSequence,
21860
+ buildSimpleChartOption: () => buildSimpleChartOption,
21894
21861
  buildThemeCSS: () => buildThemeCSS,
21895
21862
  catppuccinPalette: () => catppuccinPalette,
21896
21863
  collapseInitiativeStatus: () => collapseInitiativeStatus,
@@ -21910,8 +21877,8 @@ __export(index_exports, {
21910
21877
  formatDateLabel: () => formatDateLabel,
21911
21878
  formatDgmoError: () => formatDgmoError,
21912
21879
  getAvailablePalettes: () => getAvailablePalettes,
21913
- getDgmoFramework: () => getDgmoFramework,
21914
21880
  getPalette: () => getPalette,
21881
+ getRenderCategory: () => getRenderCategory,
21915
21882
  getSeriesColors: () => getSeriesColors,
21916
21883
  groupMessagesBySection: () => groupMessagesBySection,
21917
21884
  gruvboxPalette: () => gruvboxPalette,
@@ -21922,6 +21889,7 @@ __export(index_exports, {
21922
21889
  inferRoles: () => inferRoles,
21923
21890
  injectBranding: () => injectBranding,
21924
21891
  isArchiveColumn: () => isArchiveColumn,
21892
+ isExtendedChartType: () => isExtendedChartType,
21925
21893
  isSequenceBlock: () => isSequenceBlock,
21926
21894
  isSequenceNote: () => isSequenceNote,
21927
21895
  isValidHex: () => isValidHex,
@@ -21953,11 +21921,10 @@ __export(index_exports, {
21953
21921
  parseC4: () => parseC4,
21954
21922
  parseChart: () => parseChart,
21955
21923
  parseClassDiagram: () => parseClassDiagram,
21956
- parseD3: () => parseD3,
21957
21924
  parseDgmo: () => parseDgmo,
21958
21925
  parseDgmoChartType: () => parseDgmoChartType,
21959
- parseEChart: () => parseEChart,
21960
21926
  parseERDiagram: () => parseERDiagram,
21927
+ parseExtendedChart: () => parseExtendedChart,
21961
21928
  parseFlowchart: () => parseFlowchart,
21962
21929
  parseInfra: () => parseInfra,
21963
21930
  parseInitiativeStatus: () => parseInitiativeStatus,
@@ -21969,6 +21936,7 @@ __export(index_exports, {
21969
21936
  parseSitemap: () => parseSitemap,
21970
21937
  parseState: () => parseState,
21971
21938
  parseTimelineDate: () => parseTimelineDate,
21939
+ parseVisualization: () => parseVisualization,
21972
21940
  registerPalette: () => registerPalette,
21973
21941
  render: () => render,
21974
21942
  renderArcDiagram: () => renderArcDiagram,
@@ -21981,12 +21949,12 @@ __export(index_exports, {
21981
21949
  renderC4DeploymentForExport: () => renderC4DeploymentForExport,
21982
21950
  renderClassDiagram: () => renderClassDiagram,
21983
21951
  renderClassDiagramForExport: () => renderClassDiagramForExport,
21984
- renderD3ForExport: () => renderD3ForExport,
21985
- renderEChartsForExport: () => renderEChartsForExport,
21986
21952
  renderERDiagram: () => renderERDiagram,
21987
21953
  renderERDiagramForExport: () => renderERDiagramForExport,
21954
+ renderExtendedChartForExport: () => renderExtendedChartForExport,
21988
21955
  renderFlowchart: () => renderFlowchart,
21989
21956
  renderFlowchartForExport: () => renderFlowchartForExport,
21957
+ renderForExport: () => renderForExport,
21990
21958
  renderInfra: () => renderInfra,
21991
21959
  renderInitiativeStatus: () => renderInitiativeStatus,
21992
21960
  renderInitiativeStatusForExport: () => renderInitiativeStatusForExport,
@@ -22042,17 +22010,17 @@ async function render(content, options) {
22042
22010
  const branding = options?.branding ?? true;
22043
22011
  const paletteColors = getPalette(paletteName)[theme === "dark" ? "dark" : "light"];
22044
22012
  const chartType = parseDgmoChartType(content);
22045
- const framework = chartType ? getDgmoFramework(chartType) : null;
22046
- if (framework === "echart") {
22047
- return renderEChartsForExport(content, theme, paletteColors, { branding });
22013
+ const category = chartType ? getRenderCategory(chartType) : null;
22014
+ if (category === "data-chart") {
22015
+ return renderExtendedChartForExport(content, theme, paletteColors, { branding });
22048
22016
  }
22049
22017
  await ensureDom();
22050
- return renderD3ForExport(content, theme, paletteColors, void 0, {
22018
+ return renderForExport(content, theme, paletteColors, void 0, {
22051
22019
  branding,
22052
22020
  c4Level: options?.c4Level,
22053
22021
  c4System: options?.c4System,
22054
22022
  c4Container: options?.c4Container,
22055
- scenario: options?.scenario
22023
+ tagGroup: options?.tagGroup
22056
22024
  });
22057
22025
  }
22058
22026
 
@@ -22826,20 +22794,18 @@ function decodeDiagramUrl(hash) {
22826
22794
  init_branding();
22827
22795
  // Annotate the CommonJS export names for ESM import in node:
22828
22796
  0 && (module.exports = {
22829
- DGMO_CHART_TYPE_MAP,
22830
22797
  INFRA_BEHAVIOR_KEYS,
22831
22798
  RULE_COUNT,
22832
- STANDARD_CHART_TYPES,
22833
22799
  addDurationToDate,
22834
22800
  applyGroupOrdering,
22835
22801
  applyPositionOverrides,
22836
22802
  boldPalette,
22837
- buildEChartsOption,
22838
- buildEChartsOptionFromChart,
22803
+ buildExtendedChartOption,
22839
22804
  buildMermaidQuadrant,
22840
22805
  buildMermaidThemeVars,
22841
22806
  buildNoteMessageMap,
22842
22807
  buildRenderSequence,
22808
+ buildSimpleChartOption,
22843
22809
  buildThemeCSS,
22844
22810
  catppuccinPalette,
22845
22811
  collapseInitiativeStatus,
@@ -22859,8 +22825,8 @@ init_branding();
22859
22825
  formatDateLabel,
22860
22826
  formatDgmoError,
22861
22827
  getAvailablePalettes,
22862
- getDgmoFramework,
22863
22828
  getPalette,
22829
+ getRenderCategory,
22864
22830
  getSeriesColors,
22865
22831
  groupMessagesBySection,
22866
22832
  gruvboxPalette,
@@ -22871,6 +22837,7 @@ init_branding();
22871
22837
  inferRoles,
22872
22838
  injectBranding,
22873
22839
  isArchiveColumn,
22840
+ isExtendedChartType,
22874
22841
  isSequenceBlock,
22875
22842
  isSequenceNote,
22876
22843
  isValidHex,
@@ -22902,11 +22869,10 @@ init_branding();
22902
22869
  parseC4,
22903
22870
  parseChart,
22904
22871
  parseClassDiagram,
22905
- parseD3,
22906
22872
  parseDgmo,
22907
22873
  parseDgmoChartType,
22908
- parseEChart,
22909
22874
  parseERDiagram,
22875
+ parseExtendedChart,
22910
22876
  parseFlowchart,
22911
22877
  parseInfra,
22912
22878
  parseInitiativeStatus,
@@ -22918,6 +22884,7 @@ init_branding();
22918
22884
  parseSitemap,
22919
22885
  parseState,
22920
22886
  parseTimelineDate,
22887
+ parseVisualization,
22921
22888
  registerPalette,
22922
22889
  render,
22923
22890
  renderArcDiagram,
@@ -22930,12 +22897,12 @@ init_branding();
22930
22897
  renderC4DeploymentForExport,
22931
22898
  renderClassDiagram,
22932
22899
  renderClassDiagramForExport,
22933
- renderD3ForExport,
22934
- renderEChartsForExport,
22935
22900
  renderERDiagram,
22936
22901
  renderERDiagramForExport,
22902
+ renderExtendedChartForExport,
22937
22903
  renderFlowchart,
22938
22904
  renderFlowchartForExport,
22905
+ renderForExport,
22939
22906
  renderInfra,
22940
22907
  renderInitiativeStatus,
22941
22908
  renderInitiativeStatusForExport,