@diagrammo/dgmo 0.31.0 → 0.32.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/.cursorrules +4 -1
- package/.github/copilot-instructions.md +4 -1
- package/.windsurfrules +4 -1
- package/SKILL.md +4 -1
- package/dist/advanced.cjs +1297 -358
- package/dist/advanced.d.cts +117 -15
- package/dist/advanced.d.ts +117 -15
- package/dist/advanced.js +1291 -358
- package/dist/auto.cjs +1087 -316
- package/dist/auto.js +98 -98
- package/dist/auto.mjs +1087 -316
- package/dist/cli.cjs +140 -140
- package/dist/index.cjs +1090 -397
- package/dist/index.js +1090 -397
- package/docs/ai-integration.md +4 -1
- package/docs/language-reference.md +282 -27
- package/gallery/fixtures/boxes-and-lines.dgmo +2 -2
- package/gallery/fixtures/c4-full.dgmo +4 -5
- package/gallery/fixtures/c4.dgmo +2 -3
- package/package.json +7 -1
- package/src/advanced.ts +7 -0
- package/src/boxes-and-lines/focus.ts +257 -0
- package/src/boxes-and-lines/layout-search.ts +131 -65
- package/src/boxes-and-lines/layout.ts +7 -1
- package/src/boxes-and-lines/parser.ts +19 -4
- package/src/boxes-and-lines/renderer.ts +54 -3
- package/src/c4/parser.ts +8 -7
- package/src/chart-type-registry.ts +129 -4
- package/src/chart-types.ts +4 -4
- package/src/chart.ts +18 -1
- package/src/colors.ts +225 -2
- package/src/cycle/parser.ts +2 -7
- package/src/d3.ts +67 -54
- package/src/diagnostics.ts +17 -0
- package/src/dimensions.ts +9 -13
- package/src/echarts.ts +42 -14
- package/src/er/parser.ts +6 -1
- package/src/gantt/parser.ts +44 -7
- package/src/graph/flowchart-parser.ts +77 -3
- package/src/graph/state-renderer.ts +2 -2
- package/src/infra/parser.ts +80 -0
- package/src/journey-map/parser.ts +8 -7
- package/src/kanban/parser.ts +8 -7
- package/src/map/context-labels.ts +134 -27
- package/src/map/geo.ts +10 -2
- package/src/map/layout.ts +259 -4
- package/src/map/parser.ts +2 -0
- package/src/map/renderer.ts +22 -11
- package/src/map/resolver.ts +68 -19
- package/src/mindmap/parser.ts +15 -7
- package/src/mindmap/renderer.ts +50 -12
- package/src/org/parser.ts +8 -7
- package/src/org/renderer.ts +22 -7
- package/src/palettes/color-utils.ts +12 -2
- package/src/palettes/index.ts +1 -0
- package/src/pert/renderer.ts +2 -2
- package/src/pyramid/parser.ts +2 -7
- package/src/quadrant/renderer.ts +2 -2
- package/src/raci/parser.ts +2 -7
- package/src/raci/renderer.ts +4 -4
- package/src/ring/parser.ts +2 -7
- package/src/sequence/parser.ts +18 -7
- package/src/sequence/renderer.ts +4 -4
- package/src/sitemap/parser.ts +8 -7
- package/src/sitemap/renderer.ts +2 -2
- package/src/tech-radar/parser.ts +2 -7
- package/src/timeline/renderer.ts +15 -5
- package/src/utils/parsing.ts +13 -1
- package/src/utils/scaling.ts +38 -81
- package/src/utils/tag-groups.ts +38 -0
- package/src/visualizations/parse.ts +6 -1
- package/src/wireframe/parser.ts +6 -1
|
@@ -199,16 +199,22 @@ export async function layoutBoxesAndLines(
|
|
|
199
199
|
/** Previous node positions (label → {x,y}) for layout stability —
|
|
200
200
|
* minimizes node drift on edit/collapse. */
|
|
201
201
|
previousPositions?: ReadonlyMap<string, { x: number; y: number }>;
|
|
202
|
+
/** Progress hook (interactive path). When set, the search yields between
|
|
203
|
+
* candidates so the UI can paint a "trying X of Y" indicator. */
|
|
204
|
+
onProgress?: (done: number, total: number, phase: string) => void;
|
|
202
205
|
}
|
|
203
206
|
): Promise<BLLayoutResult> {
|
|
204
207
|
const { layoutBoxesAndLinesSearch } = await import('./layout-search');
|
|
205
|
-
const searched = layoutBoxesAndLinesSearch(parsed, collapseInfo, {
|
|
208
|
+
const searched = await layoutBoxesAndLinesSearch(parsed, collapseInfo, {
|
|
206
209
|
...(layoutOptions?.hideDescriptions !== undefined && {
|
|
207
210
|
hideDescriptions: layoutOptions.hideDescriptions,
|
|
208
211
|
}),
|
|
209
212
|
...(layoutOptions?.previousPositions !== undefined && {
|
|
210
213
|
previousPositions: layoutOptions.previousPositions,
|
|
211
214
|
}),
|
|
215
|
+
...(layoutOptions?.onProgress !== undefined && {
|
|
216
|
+
onProgress: layoutOptions.onProgress,
|
|
217
|
+
}),
|
|
212
218
|
});
|
|
213
219
|
// Engine-agnostic post-processing: fan parallel edges, then float notes
|
|
214
220
|
// (and shift the canvas to fit them).
|
|
@@ -42,6 +42,11 @@ import type { PaletteColors } from '../palettes';
|
|
|
42
42
|
|
|
43
43
|
const MAX_GROUP_DEPTH = 2;
|
|
44
44
|
|
|
45
|
+
// §1.4/§1.10 legacy-pipe detection — module-scope so they aren't re-created per
|
|
46
|
+
// line. `|` inside a directed (`->`) or undirected (`~>`) arrow label is valid.
|
|
47
|
+
const ARROW_LABEL_PIPE_DIRECTED_RE = /-\S*\|\S*->/;
|
|
48
|
+
const ARROW_LABEL_PIPE_UNDIRECTED_RE = /~\S*\|\S*~>/;
|
|
49
|
+
|
|
45
50
|
/** Boxes-and-lines requires explicit first line — no heuristic detection. */
|
|
46
51
|
export function looksLikeBoxesAndLines(_content: string): boolean {
|
|
47
52
|
return false;
|
|
@@ -247,8 +252,8 @@ export function parseBoxesAndLines(
|
|
|
247
252
|
// regions.
|
|
248
253
|
if (
|
|
249
254
|
trimmed.includes('|') &&
|
|
250
|
-
|
|
251
|
-
|
|
255
|
+
!ARROW_LABEL_PIPE_DIRECTED_RE.test(trimmed) &&
|
|
256
|
+
!ARROW_LABEL_PIPE_UNDIRECTED_RE.test(trimmed)
|
|
252
257
|
) {
|
|
253
258
|
result.diagnostics.push(
|
|
254
259
|
makeDgmoError(
|
|
@@ -404,7 +409,12 @@ export function parseBoxesAndLines(
|
|
|
404
409
|
if (tagBlockMatch.inlineValues) {
|
|
405
410
|
for (const rawVal of tagBlockMatch.inlineValues) {
|
|
406
411
|
const { text: cleanVal, isDefault } = stripDefaultModifier(rawVal);
|
|
407
|
-
const { label, color } = extractColor(
|
|
412
|
+
const { label, color } = extractColor(
|
|
413
|
+
cleanVal,
|
|
414
|
+
palette,
|
|
415
|
+
result.diagnostics,
|
|
416
|
+
lineNum
|
|
417
|
+
);
|
|
408
418
|
newTagGroup.entries.push({
|
|
409
419
|
value: label,
|
|
410
420
|
color: color ?? AUTO_TAG_COLOR_SENTINEL,
|
|
@@ -424,7 +434,12 @@ export function parseBoxesAndLines(
|
|
|
424
434
|
// Tag group entries (indented under tag heading)
|
|
425
435
|
if (currentTagGroup && !contentStarted && indent > 0) {
|
|
426
436
|
const { text: cleanEntry, isDefault } = stripDefaultModifier(trimmed);
|
|
427
|
-
const { label, color } = extractColor(
|
|
437
|
+
const { label, color } = extractColor(
|
|
438
|
+
cleanEntry,
|
|
439
|
+
palette,
|
|
440
|
+
result.diagnostics,
|
|
441
|
+
lineNum
|
|
442
|
+
);
|
|
428
443
|
currentTagGroup.entries.push({
|
|
429
444
|
value: label,
|
|
430
445
|
color: color ?? AUTO_TAG_COLOR_SENTINEL,
|
|
@@ -30,6 +30,7 @@ import {
|
|
|
30
30
|
relativeLuminance,
|
|
31
31
|
shapeFill,
|
|
32
32
|
valueRampColor,
|
|
33
|
+
themeBaseBg,
|
|
33
34
|
} from '../palettes/color-utils';
|
|
34
35
|
import { resolveColor } from '../colors';
|
|
35
36
|
import { resolveTagColor } from '../utils/tag-groups';
|
|
@@ -438,6 +439,11 @@ interface BLRenderOptions {
|
|
|
438
439
|
/** When 'app', the description toggle is hosted by the app overlay strip
|
|
439
440
|
* (inline gear suppressed, controls row + anchor reserved). */
|
|
440
441
|
controlsHost?: 'app' | 'inline';
|
|
442
|
+
/** Explicit value-ramp domain override. When provided, the choropleth ramp
|
|
443
|
+
* uses these endpoints instead of computing min/max from `parsed.nodes`.
|
|
444
|
+
* Focus mode passes the GLOBAL (pre-filter) domain so neighbor colours stay
|
|
445
|
+
* stable when only a subset is rendered (Decision 20 / FM1). */
|
|
446
|
+
rampDomain?: { min: number; max: number };
|
|
441
447
|
}
|
|
442
448
|
|
|
443
449
|
export function renderBoxesAndLines(
|
|
@@ -459,6 +465,7 @@ export function renderBoxesAndLines(
|
|
|
459
465
|
onToggleControlsExpand,
|
|
460
466
|
exportMode = false,
|
|
461
467
|
controlsHost,
|
|
468
|
+
rampDomain,
|
|
462
469
|
} = options ?? {};
|
|
463
470
|
d3Selection.select(container).selectAll(':not([data-d3-tooltip])').remove();
|
|
464
471
|
|
|
@@ -492,8 +499,10 @@ export function renderBoxesAndLines(
|
|
|
492
499
|
// Anchor the low end at the lowest value (not 0) to maximise within-diagram
|
|
493
500
|
// dynamic range; mirrors the map's region-metric ramp. Equal-value data
|
|
494
501
|
// (rampMin === rampMax) falls back to t = 1 in fillForValue below.
|
|
495
|
-
|
|
496
|
-
|
|
502
|
+
// A caller-supplied domain (focus mode) wins so colours don't shift when a
|
|
503
|
+
// subset is rendered; otherwise derive from the nodes on screen.
|
|
504
|
+
const rampMin = rampDomain?.min ?? (hasRamp ? Math.min(...nodeValues) : 0);
|
|
505
|
+
const rampMax = rampDomain?.max ?? Math.max(...nodeValues);
|
|
497
506
|
// Default hue = palette.primary (NOT red like the map — boxes have no water to
|
|
498
507
|
// stand out against, and red reads as alarm on a neutral metric). A trailing
|
|
499
508
|
// color on `box-metric` overrides.
|
|
@@ -751,7 +760,7 @@ export function renderBoxesAndLines(
|
|
|
751
760
|
|
|
752
761
|
if (group.collapsed) {
|
|
753
762
|
// Collapsed: solid rounded rect matching node style + 6px collapse bar
|
|
754
|
-
const fillColor =
|
|
763
|
+
const fillColor = themeBaseBg(palette, isDark);
|
|
755
764
|
const strokeColor = palette.border;
|
|
756
765
|
|
|
757
766
|
groupG
|
|
@@ -1446,6 +1455,48 @@ export function renderBoxesAndLines(
|
|
|
1446
1455
|
});
|
|
1447
1456
|
legendG.selectAll('[data-legend-group]').classed('bl-legend-group', true);
|
|
1448
1457
|
}
|
|
1458
|
+
|
|
1459
|
+
// ── Focus mode: one reusable hover-reveal icon (interactive only) ──
|
|
1460
|
+
// A single hidden icon the app repositions over the hovered box/group and
|
|
1461
|
+
// stamps `data-focus-id`/`data-focus-kind` on (Decision 22 / ADR-4) — NOT one
|
|
1462
|
+
// per node (~4k elements on a large graph). Appended to the SVG root so the
|
|
1463
|
+
// app positions it in root (screen-mapped) coordinates, counter-scaled to a
|
|
1464
|
+
// constant size regardless of fit. Excluded from export like org's icon.
|
|
1465
|
+
if (!exportDims && !exportMode) {
|
|
1466
|
+
const iconSize = 14;
|
|
1467
|
+
const focusG = svg
|
|
1468
|
+
.append('g')
|
|
1469
|
+
.attr('class', 'bl-focus-icon')
|
|
1470
|
+
.attr('data-export-ignore', 'true')
|
|
1471
|
+
.style('display', 'none')
|
|
1472
|
+
.style('pointer-events', 'auto')
|
|
1473
|
+
.style('cursor', 'pointer');
|
|
1474
|
+
// Hit area
|
|
1475
|
+
focusG
|
|
1476
|
+
.append('rect')
|
|
1477
|
+
.attr('x', -3)
|
|
1478
|
+
.attr('y', -3)
|
|
1479
|
+
.attr('width', iconSize + 6)
|
|
1480
|
+
.attr('height', iconSize + 6)
|
|
1481
|
+
.attr('fill', 'transparent');
|
|
1482
|
+
// Scope/target icon: outer circle + inner dot (mirrors org-focus-icon)
|
|
1483
|
+
const cx = iconSize / 2;
|
|
1484
|
+
const cy = iconSize / 2;
|
|
1485
|
+
focusG
|
|
1486
|
+
.append('circle')
|
|
1487
|
+
.attr('cx', cx)
|
|
1488
|
+
.attr('cy', cy)
|
|
1489
|
+
.attr('r', iconSize / 2 - 1)
|
|
1490
|
+
.attr('fill', palette.bg)
|
|
1491
|
+
.attr('stroke', palette.textMuted)
|
|
1492
|
+
.attr('stroke-width', 1.5);
|
|
1493
|
+
focusG
|
|
1494
|
+
.append('circle')
|
|
1495
|
+
.attr('cx', cx)
|
|
1496
|
+
.attr('cy', cy)
|
|
1497
|
+
.attr('r', 2)
|
|
1498
|
+
.attr('fill', palette.textMuted);
|
|
1499
|
+
}
|
|
1449
1500
|
}
|
|
1450
1501
|
|
|
1451
1502
|
// ── Export helper ──────────────────────────────────────────
|
package/src/c4/parser.ts
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
descriptionBareRemovedMessage,
|
|
9
9
|
formatDgmoError,
|
|
10
10
|
makeDgmoError,
|
|
11
|
+
makeFail,
|
|
11
12
|
METADATA_DIAGNOSTIC_CODES,
|
|
12
13
|
pipeOperatorRemovedMessage,
|
|
13
14
|
suggest,
|
|
@@ -296,12 +297,7 @@ export function parseC4(content: string, palette?: PaletteColors): ParsedC4 {
|
|
|
296
297
|
result.error = formatDgmoError(diag);
|
|
297
298
|
};
|
|
298
299
|
|
|
299
|
-
const fail = (
|
|
300
|
-
const diag = makeDgmoError(line, message);
|
|
301
|
-
result.diagnostics.push(diag);
|
|
302
|
-
result.error = formatDgmoError(diag);
|
|
303
|
-
return result;
|
|
304
|
-
};
|
|
300
|
+
const fail = makeFail(result);
|
|
305
301
|
|
|
306
302
|
if (!content?.trim()) {
|
|
307
303
|
return fail(0, 'No content provided');
|
|
@@ -455,7 +451,12 @@ export function parseC4(content: string, palette?: PaletteColors): ParsedC4 {
|
|
|
455
451
|
const indent = measureIndent(line);
|
|
456
452
|
if (indent > 0) {
|
|
457
453
|
const { text: cleanEntry, isDefault } = stripDefaultModifier(trimmed);
|
|
458
|
-
const { label, color } = extractColor(
|
|
454
|
+
const { label, color } = extractColor(
|
|
455
|
+
cleanEntry,
|
|
456
|
+
palette,
|
|
457
|
+
result.diagnostics,
|
|
458
|
+
lineNumber
|
|
459
|
+
);
|
|
459
460
|
// Bare value (no explicit color) → keep it; the post-parse
|
|
460
461
|
// finalize pass assigns a deterministic palette color.
|
|
461
462
|
if (isDefault) {
|
|
@@ -87,6 +87,10 @@ export interface ChartTypeDescriptor {
|
|
|
87
87
|
readonly category: RenderCategory;
|
|
88
88
|
readonly parse: ParseFn;
|
|
89
89
|
readonly measure?: (content: string) => ContentCounts;
|
|
90
|
+
readonly minDims?: (counts: ContentCounts) => {
|
|
91
|
+
width: number;
|
|
92
|
+
height: number;
|
|
93
|
+
};
|
|
90
94
|
}
|
|
91
95
|
|
|
92
96
|
// ============================================================
|
|
@@ -210,6 +214,92 @@ function measureInfra(content: string): ContentCounts {
|
|
|
210
214
|
return { nodes: parsed.nodes.length };
|
|
211
215
|
}
|
|
212
216
|
|
|
217
|
+
// ============================================================
|
|
218
|
+
// minDims() implementations — relocated verbatim from computeMinDimensions() in
|
|
219
|
+
// utils/scaling.ts so the registry owns per-type minimum-dimension formulas
|
|
220
|
+
// alongside measure(). Each maps ContentCounts → {width,height}. Types without a
|
|
221
|
+
// minDims fall back to {300,200} (the old switch `default`) via the
|
|
222
|
+
// REGISTRY_BY_ID lookup in dimensions.ts.
|
|
223
|
+
// ============================================================
|
|
224
|
+
|
|
225
|
+
function minDimsSequence(c: ContentCounts): { width: number; height: number } {
|
|
226
|
+
return {
|
|
227
|
+
width: Math.max((c.participants ?? 2) * 80, 320),
|
|
228
|
+
height: Math.max((c.messages ?? 1) * 20 + 120, 200),
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
function minDimsRaci(c: ContentCounts): { width: number; height: number } {
|
|
232
|
+
return {
|
|
233
|
+
width: Math.max((c.roles ?? 2) * 50 + 180, 300),
|
|
234
|
+
height: Math.max((c.tasks ?? 1) * 28 + 80, 200),
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
function minDimsMindmap(c: ContentCounts): { width: number; height: number } {
|
|
238
|
+
return {
|
|
239
|
+
width: Math.max((c.nodes ?? 3) * 30, 300),
|
|
240
|
+
height: Math.max((c.depth ?? 2) * 60, 200),
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
function minDimsTechRadar(): { width: number; height: number } {
|
|
244
|
+
return { width: 360, height: 400 };
|
|
245
|
+
}
|
|
246
|
+
function minDimsHeatmap(c: ContentCounts): { width: number; height: number } {
|
|
247
|
+
return {
|
|
248
|
+
width: Math.max((c.columns ?? 3) * 40, 300),
|
|
249
|
+
height: Math.max((c.rows ?? 3) * 30 + 60, 200),
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
function minDimsArc(c: ContentCounts): { width: number; height: number } {
|
|
253
|
+
return {
|
|
254
|
+
width: 300,
|
|
255
|
+
height: Math.max((c.nodes ?? 3) * 20 + 120, 200),
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
function minDimsOrg(c: ContentCounts): { width: number; height: number } {
|
|
259
|
+
return {
|
|
260
|
+
width: Math.max((c.nodes ?? 3) * 60, 300),
|
|
261
|
+
height: Math.max((c.depth ?? 2) * 80, 200),
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
function minDimsGantt(c: ContentCounts): { width: number; height: number } {
|
|
265
|
+
return {
|
|
266
|
+
width: 400,
|
|
267
|
+
height: Math.max((c.tasks ?? 3) * 24 + 80, 200),
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
function minDimsKanban(c: ContentCounts): { width: number; height: number } {
|
|
271
|
+
return {
|
|
272
|
+
width: Math.max((c.columns ?? 3) * 120, 360),
|
|
273
|
+
height: 300,
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
// er + class share this formula.
|
|
277
|
+
function minDimsEntities(c: ContentCounts): { width: number; height: number } {
|
|
278
|
+
return {
|
|
279
|
+
width: Math.max((c.nodes ?? 2) * 140, 300),
|
|
280
|
+
height: Math.max((c.nodes ?? 2) * 80, 200),
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
// flowchart + state share this formula.
|
|
284
|
+
function minDimsGraph(c: ContentCounts): { width: number; height: number } {
|
|
285
|
+
return {
|
|
286
|
+
width: Math.max((c.nodes ?? 3) * 60, 300),
|
|
287
|
+
height: Math.max((c.nodes ?? 3) * 50, 200),
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
function minDimsPert(c: ContentCounts): { width: number; height: number } {
|
|
291
|
+
return {
|
|
292
|
+
width: Math.max((c.tasks ?? 3) * 80, 340),
|
|
293
|
+
height: Math.max((c.tasks ?? 3) * 40 + 80, 200),
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
function minDimsInfra(c: ContentCounts): { width: number; height: number } {
|
|
297
|
+
return {
|
|
298
|
+
width: Math.max((c.nodes ?? 3) * 80, 300),
|
|
299
|
+
height: Math.max((c.nodes ?? 3) * 60, 200),
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
|
|
213
303
|
// ============================================================
|
|
214
304
|
// THE REGISTRY — ordered to match the previous chartTypeParsers grouping
|
|
215
305
|
// (structured diagrams, standard ECharts, extended ECharts, D3 visualizations,
|
|
@@ -224,32 +314,49 @@ export const CHART_TYPE_REGISTRY: readonly ChartTypeDescriptor[] = [
|
|
|
224
314
|
category: 'diagram',
|
|
225
315
|
parse: parseSequenceDgmo,
|
|
226
316
|
measure: measureSequence,
|
|
317
|
+
minDims: minDimsSequence,
|
|
227
318
|
},
|
|
228
319
|
{
|
|
229
320
|
id: 'flowchart',
|
|
230
321
|
category: 'diagram',
|
|
231
322
|
parse: parseFlowchart,
|
|
232
323
|
measure: measureFlowchart,
|
|
324
|
+
minDims: minDimsGraph,
|
|
233
325
|
},
|
|
234
326
|
{
|
|
235
327
|
id: 'class',
|
|
236
328
|
category: 'diagram',
|
|
237
329
|
parse: parseClassDiagram,
|
|
238
330
|
measure: measureClass,
|
|
331
|
+
minDims: minDimsEntities,
|
|
332
|
+
},
|
|
333
|
+
{
|
|
334
|
+
id: 'er',
|
|
335
|
+
category: 'diagram',
|
|
336
|
+
parse: parseERDiagram,
|
|
337
|
+
measure: measureER,
|
|
338
|
+
minDims: minDimsEntities,
|
|
239
339
|
},
|
|
240
|
-
{ id: 'er', category: 'diagram', parse: parseERDiagram, measure: measureER },
|
|
241
340
|
{
|
|
242
341
|
id: 'state',
|
|
243
342
|
category: 'diagram',
|
|
244
343
|
parse: parseState,
|
|
245
344
|
measure: measureStateGraph,
|
|
345
|
+
minDims: minDimsGraph,
|
|
346
|
+
},
|
|
347
|
+
{
|
|
348
|
+
id: 'org',
|
|
349
|
+
category: 'diagram',
|
|
350
|
+
parse: parseOrg,
|
|
351
|
+
measure: measureOrg,
|
|
352
|
+
minDims: minDimsOrg,
|
|
246
353
|
},
|
|
247
|
-
{ id: 'org', category: 'diagram', parse: parseOrg, measure: measureOrg },
|
|
248
354
|
{
|
|
249
355
|
id: 'kanban',
|
|
250
356
|
category: 'diagram',
|
|
251
357
|
parse: parseKanban,
|
|
252
358
|
measure: measureKanban,
|
|
359
|
+
minDims: minDimsKanban,
|
|
253
360
|
},
|
|
254
361
|
{ id: 'c4', category: 'diagram', parse: parseC4 },
|
|
255
362
|
{ id: 'sitemap', category: 'diagram', parse: parseSitemap },
|
|
@@ -258,24 +365,39 @@ export const CHART_TYPE_REGISTRY: readonly ChartTypeDescriptor[] = [
|
|
|
258
365
|
category: 'diagram',
|
|
259
366
|
parse: parseInfra,
|
|
260
367
|
measure: measureInfra,
|
|
368
|
+
minDims: minDimsInfra,
|
|
261
369
|
},
|
|
262
370
|
{
|
|
263
371
|
id: 'gantt',
|
|
264
372
|
category: 'diagram',
|
|
265
373
|
parse: parseGantt,
|
|
266
374
|
measure: measureGantt,
|
|
375
|
+
minDims: minDimsGantt,
|
|
376
|
+
},
|
|
377
|
+
{
|
|
378
|
+
id: 'pert',
|
|
379
|
+
category: 'diagram',
|
|
380
|
+
parse: parsePert,
|
|
381
|
+
measure: measurePert,
|
|
382
|
+
minDims: minDimsPert,
|
|
267
383
|
},
|
|
268
|
-
{ id: 'pert', category: 'diagram', parse: parsePert, measure: measurePert },
|
|
269
384
|
{ id: 'boxes-and-lines', category: 'diagram', parse: parseBoxesAndLines },
|
|
270
385
|
{
|
|
271
386
|
id: 'mindmap',
|
|
272
387
|
category: 'diagram',
|
|
273
388
|
parse: parseMindmap,
|
|
274
389
|
measure: measureMindmap,
|
|
390
|
+
minDims: minDimsMindmap,
|
|
275
391
|
},
|
|
276
392
|
{ id: 'wireframe', category: 'diagram', parse: parseWireframe },
|
|
277
393
|
{ id: 'journey-map', category: 'diagram', parse: parseJourneyMap },
|
|
278
|
-
{
|
|
394
|
+
{
|
|
395
|
+
id: 'raci',
|
|
396
|
+
category: 'diagram',
|
|
397
|
+
parse: parseRaci,
|
|
398
|
+
measure: measureRaci,
|
|
399
|
+
minDims: minDimsRaci,
|
|
400
|
+
},
|
|
279
401
|
{ id: 'rasci', category: 'diagram', parse: parseRaci, measure: measureRaci },
|
|
280
402
|
{ id: 'daci', category: 'diagram', parse: parseRaci, measure: measureRaci },
|
|
281
403
|
|
|
@@ -300,6 +422,7 @@ export const CHART_TYPE_REGISTRY: readonly ChartTypeDescriptor[] = [
|
|
|
300
422
|
category: 'data-chart',
|
|
301
423
|
parse: parseHeatmap,
|
|
302
424
|
measure: measureHeatmap,
|
|
425
|
+
minDims: minDimsHeatmap,
|
|
303
426
|
},
|
|
304
427
|
{ id: 'funnel', category: 'data-chart', parse: parseFunnel },
|
|
305
428
|
|
|
@@ -311,6 +434,7 @@ export const CHART_TYPE_REGISTRY: readonly ChartTypeDescriptor[] = [
|
|
|
311
434
|
category: 'visualization',
|
|
312
435
|
parse: parseArc,
|
|
313
436
|
measure: measureArc,
|
|
437
|
+
minDims: minDimsArc,
|
|
314
438
|
},
|
|
315
439
|
{ id: 'timeline', category: 'visualization', parse: parseTimeline },
|
|
316
440
|
{ id: 'venn', category: 'visualization', parse: parseVenn },
|
|
@@ -322,6 +446,7 @@ export const CHART_TYPE_REGISTRY: readonly ChartTypeDescriptor[] = [
|
|
|
322
446
|
category: 'visualization',
|
|
323
447
|
parse: parseTechRadar,
|
|
324
448
|
measure: measureTechRadar,
|
|
449
|
+
minDims: minDimsTechRadar,
|
|
325
450
|
},
|
|
326
451
|
{ id: 'cycle', category: 'visualization', parse: parseCycle },
|
|
327
452
|
{ id: 'pyramid', category: 'visualization', parse: parsePyramid },
|
package/src/chart-types.ts
CHANGED
|
@@ -46,7 +46,7 @@ export const chartTypes: readonly ChartTypeMeta[] = [
|
|
|
46
46
|
},
|
|
47
47
|
{
|
|
48
48
|
id: 'sequence',
|
|
49
|
-
description: 'Message
|
|
49
|
+
description: 'Message request and response interaction flows',
|
|
50
50
|
fallback: true,
|
|
51
51
|
},
|
|
52
52
|
{
|
|
@@ -125,7 +125,7 @@ export const chartTypes: readonly ChartTypeMeta[] = [
|
|
|
125
125
|
{
|
|
126
126
|
id: 'map',
|
|
127
127
|
description:
|
|
128
|
-
'Geographic map:
|
|
128
|
+
'Geographic concept map: highlight/score regions, drop points of interest, connect with routes or edges',
|
|
129
129
|
},
|
|
130
130
|
|
|
131
131
|
// ── Tier 3 — Specialized analytical charts ────────────────
|
|
@@ -143,7 +143,7 @@ export const chartTypes: readonly ChartTypeMeta[] = [
|
|
|
143
143
|
},
|
|
144
144
|
{
|
|
145
145
|
id: 'slope',
|
|
146
|
-
description: 'Change
|
|
146
|
+
description: 'Change between 2 time periods',
|
|
147
147
|
},
|
|
148
148
|
{
|
|
149
149
|
id: 'sankey',
|
|
@@ -173,7 +173,7 @@ export const chartTypes: readonly ChartTypeMeta[] = [
|
|
|
173
173
|
// ── Tier 4 — General-purpose data charts ──────────────────
|
|
174
174
|
{
|
|
175
175
|
id: 'bar',
|
|
176
|
-
description: 'Categorical comparisons',
|
|
176
|
+
description: 'Categorical comparisons for 3 - 5 figures',
|
|
177
177
|
fallback: true,
|
|
178
178
|
},
|
|
179
179
|
{
|
package/src/chart.ts
CHANGED
|
@@ -405,7 +405,9 @@ export function parseChart(
|
|
|
405
405
|
if (dataValues) {
|
|
406
406
|
const { label: rawLabel, color: pointColor } = extractColor(
|
|
407
407
|
dataValues.label,
|
|
408
|
-
palette
|
|
408
|
+
palette,
|
|
409
|
+
result.diagnostics,
|
|
410
|
+
lineNumber
|
|
409
411
|
);
|
|
410
412
|
const [first, ...rest] = dataValues.values;
|
|
411
413
|
result.data.push({
|
|
@@ -485,6 +487,21 @@ export function parseChart(
|
|
|
485
487
|
);
|
|
486
488
|
}
|
|
487
489
|
|
|
490
|
+
// Plain "bar" renders a single series per row — extra series are dropped
|
|
491
|
+
// silently by the renderer. Surface that instead of losing data quietly so
|
|
492
|
+
// the author switches to a multi-series type. (multi-line/line parse to
|
|
493
|
+
// type "line" and DO render every series, so they are unaffected.)
|
|
494
|
+
if (
|
|
495
|
+
!result.error &&
|
|
496
|
+
result.type === 'bar' &&
|
|
497
|
+
(result.seriesNames?.length ?? 0) > 1
|
|
498
|
+
) {
|
|
499
|
+
warn(
|
|
500
|
+
result.seriesLineNumber ?? 1,
|
|
501
|
+
`Plain "bar" shows only the first series ("${result.seriesNames![0]}"); the other ${result.seriesNames!.length - 1} are dropped at render. Use "bar-stacked" for stacked bars or "multi-line" to plot every series.`
|
|
502
|
+
);
|
|
503
|
+
}
|
|
504
|
+
|
|
488
505
|
if (!result.error && result.seriesNames) {
|
|
489
506
|
const expectedCount = result.seriesNames.length;
|
|
490
507
|
for (const dp of result.data) {
|