@diagrammo/dgmo 0.8.8 → 0.8.10

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.
@@ -9,7 +9,7 @@ import type { PaletteColors } from '../palettes';
9
9
  import { mix } from '../palettes/color-utils';
10
10
  import { renderInlineText } from '../utils/inline-markdown';
11
11
  import type { ParsedC4 } from './types';
12
- import type { C4LayoutResult, C4LayoutEdge, C4LegendGroup } from './layout';
12
+ import type { C4LayoutResult, C4LayoutEdge } from './layout';
13
13
  import { parseC4 } from './parser';
14
14
  import {
15
15
  layoutC4Context,
@@ -18,18 +18,9 @@ import {
18
18
  layoutC4Deployment,
19
19
  collectCardMetadata,
20
20
  } from './layout';
21
- import {
22
- LEGEND_HEIGHT,
23
- LEGEND_PILL_FONT_SIZE,
24
- LEGEND_PILL_PAD,
25
- LEGEND_DOT_R,
26
- LEGEND_ENTRY_FONT_SIZE,
27
- LEGEND_ENTRY_DOT_GAP,
28
- LEGEND_ENTRY_TRAIL,
29
- LEGEND_CAPSULE_PAD,
30
- LEGEND_GROUP_GAP,
31
- measureLegendText,
32
- } from '../utils/legend-constants';
21
+ import { LEGEND_HEIGHT } from '../utils/legend-constants';
22
+ import { renderLegendD3 } from '../utils/legend-d3';
23
+ import type { LegendConfig, LegendState } from '../utils/legend-types';
33
24
  import { TITLE_FONT_SIZE, TITLE_FONT_WEIGHT } from '../utils/title-constants';
34
25
 
35
26
  // ============================================================
@@ -1251,133 +1242,29 @@ function renderLegend(
1251
1242
  palette: PaletteColors,
1252
1243
  isDark: boolean,
1253
1244
  activeTagGroup?: string | null,
1254
- /** When set, center groups horizontally across this width (fixed overlay mode). */
1255
1245
  fixedWidth?: number | null
1256
1246
  ): void {
1257
- const visibleGroups =
1258
- activeTagGroup != null
1259
- ? layout.legend.filter(
1260
- (g) => g.name.toLowerCase() === (activeTagGroup ?? '').toLowerCase()
1261
- )
1262
- : layout.legend;
1263
-
1264
- const pillWidthOf = (g: C4LegendGroup) =>
1265
- measureLegendText(g.name, LEGEND_PILL_FONT_SIZE) + LEGEND_PILL_PAD;
1266
- const effectiveW = (g: C4LegendGroup) =>
1267
- activeTagGroup != null ? g.width : pillWidthOf(g);
1268
-
1269
- // In fixed mode, compute centered x-positions
1270
- let fixedPositions: Map<string, number> | null = null;
1271
- if (fixedWidth != null && visibleGroups.length > 0) {
1272
- fixedPositions = new Map();
1273
- const totalW =
1274
- visibleGroups.reduce((s, g) => s + effectiveW(g), 0) +
1275
- (visibleGroups.length - 1) * LEGEND_GROUP_GAP;
1276
- let cx = Math.max(DIAGRAM_PADDING, (fixedWidth - totalW) / 2);
1277
- for (const g of visibleGroups) {
1278
- fixedPositions.set(g.name, cx);
1279
- cx += effectiveW(g) + LEGEND_GROUP_GAP;
1280
- }
1281
- }
1282
-
1283
- for (const group of visibleGroups) {
1284
- const isActive =
1285
- activeTagGroup != null &&
1286
- group.name.toLowerCase() === (activeTagGroup ?? '').toLowerCase();
1287
-
1288
- const groupBg = isDark
1289
- ? mix(palette.surface, palette.bg, 50)
1290
- : mix(palette.surface, palette.bg, 30);
1291
-
1292
- const pillLabel = group.name;
1293
- const pillWidth = pillWidthOf(group);
1294
-
1295
- const gX = fixedPositions?.get(group.name) ?? group.x;
1296
- const gY = fixedPositions != null ? 0 : group.y;
1297
-
1298
- const gEl = parent
1299
- .append('g')
1300
- .attr('transform', `translate(${gX}, ${gY})`)
1301
- .attr('class', 'c4-legend-group')
1302
- .attr('data-legend-group', group.name.toLowerCase())
1303
- .style('cursor', 'pointer');
1304
-
1305
- if (isActive) {
1306
- gEl
1307
- .append('rect')
1308
- .attr('width', group.width)
1309
- .attr('height', LEGEND_HEIGHT)
1310
- .attr('rx', LEGEND_HEIGHT / 2)
1311
- .attr('fill', groupBg);
1312
- }
1313
-
1314
- const pillX = isActive ? LEGEND_CAPSULE_PAD : 0;
1315
- const pillY = LEGEND_CAPSULE_PAD;
1316
- const pillH = LEGEND_HEIGHT - LEGEND_CAPSULE_PAD * 2;
1317
-
1318
- gEl
1319
- .append('rect')
1320
- .attr('x', pillX)
1321
- .attr('y', pillY)
1322
- .attr('width', pillWidth)
1323
- .attr('height', pillH)
1324
- .attr('rx', pillH / 2)
1325
- .attr('fill', isActive ? palette.bg : groupBg);
1326
-
1327
- if (isActive) {
1328
- gEl
1329
- .append('rect')
1330
- .attr('x', pillX)
1331
- .attr('y', pillY)
1332
- .attr('width', pillWidth)
1333
- .attr('height', pillH)
1334
- .attr('rx', pillH / 2)
1335
- .attr('fill', 'none')
1336
- .attr('stroke', mix(palette.textMuted, palette.bg, 50))
1337
- .attr('stroke-width', 0.75);
1338
- }
1339
-
1340
- gEl
1341
- .append('text')
1342
- .attr('x', pillX + pillWidth / 2)
1343
- .attr('y', LEGEND_HEIGHT / 2 + LEGEND_PILL_FONT_SIZE / 2 - 2)
1344
- .attr('font-size', LEGEND_PILL_FONT_SIZE)
1345
- .attr('font-weight', '500')
1346
- .attr('fill', isActive ? palette.text : palette.textMuted)
1347
- .attr('text-anchor', 'middle')
1348
- .text(pillLabel);
1349
-
1350
- if (isActive) {
1351
- let entryX = pillX + pillWidth + 4;
1352
- for (const entry of group.entries) {
1353
- const entryG = gEl
1354
- .append('g')
1355
- .attr('data-legend-entry', entry.value.toLowerCase())
1356
- .style('cursor', 'pointer');
1357
-
1358
- entryG
1359
- .append('circle')
1360
- .attr('cx', entryX + LEGEND_DOT_R)
1361
- .attr('cy', LEGEND_HEIGHT / 2)
1362
- .attr('r', LEGEND_DOT_R)
1363
- .attr('fill', entry.color);
1364
-
1365
- const textX = entryX + LEGEND_DOT_R * 2 + LEGEND_ENTRY_DOT_GAP;
1366
- entryG
1367
- .append('text')
1368
- .attr('x', textX)
1369
- .attr('y', LEGEND_HEIGHT / 2 + LEGEND_ENTRY_FONT_SIZE / 2 - 1)
1370
- .attr('font-size', LEGEND_ENTRY_FONT_SIZE)
1371
- .attr('fill', palette.textMuted)
1372
- .text(entry.value);
1373
-
1374
- entryX =
1375
- textX +
1376
- measureLegendText(entry.value, LEGEND_ENTRY_FONT_SIZE) +
1377
- LEGEND_ENTRY_TRAIL;
1378
- }
1379
- }
1380
- }
1247
+ const groups = layout.legend.map((g) => ({
1248
+ name: g.name,
1249
+ entries: g.entries.map((e) => ({ value: e.value, color: e.color })),
1250
+ }));
1251
+ const legendConfig: LegendConfig = {
1252
+ groups,
1253
+ position: { placement: 'top-center', titleRelation: 'below-title' },
1254
+ mode: 'fixed',
1255
+ };
1256
+ const legendState: LegendState = { activeGroup: activeTagGroup ?? null };
1257
+ const containerWidth = fixedWidth ?? layout.width;
1258
+ renderLegendD3(
1259
+ parent,
1260
+ legendConfig,
1261
+ legendState,
1262
+ palette,
1263
+ isDark,
1264
+ undefined,
1265
+ containerWidth
1266
+ );
1267
+ parent.selectAll('[data-legend-group]').classed('c4-legend-group', true);
1381
1268
  }
1382
1269
 
1383
1270
  // ============================================================