@diagrammo/dgmo 0.33.0 → 0.35.0
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/.claude/commands/dgmo.md +17 -32
- package/.github/copilot-instructions.md +1 -1
- package/README.md +7 -1
- package/SKILL.md +1 -1
- package/dist/advanced.cjs +791 -614
- package/dist/advanced.d.cts +8 -51
- package/dist/advanced.d.ts +8 -51
- package/dist/advanced.js +791 -615
- package/dist/auto.cjs +793 -292
- package/dist/auto.js +95 -95
- package/dist/auto.mjs +793 -292
- package/dist/cli.cjs +145 -328
- package/dist/index.cjs +792 -291
- package/dist/index.js +792 -291
- package/docs/ai-integration.md +46 -26
- package/docs/language-reference.md +2 -2
- package/package.json +3 -3
- package/src/advanced.ts +0 -12
- package/src/boxes-and-lines/label-placement.ts +339 -0
- package/src/boxes-and-lines/layout-search.ts +16 -2
- package/src/boxes-and-lines/layout.ts +32 -7
- package/src/boxes-and-lines/renderer.ts +67 -139
- package/src/c4/parser.ts +15 -6
- package/src/chart.ts +1 -1
- package/src/class/parser.ts +6 -2
- package/src/cli-banner.ts +2 -3
- package/src/cli.ts +539 -1223
- package/src/cycle/parser.ts +4 -1
- package/src/dgmo-router.ts +16 -2
- package/src/diagnostics.ts +0 -0
- package/src/echarts.ts +5 -1
- package/src/er/parser.ts +5 -1
- package/src/gantt/parser.ts +13 -4
- package/src/graph/flowchart-parser.ts +5 -1
- package/src/graph/state-parser.ts +5 -1
- package/src/infra/parser.ts +10 -6
- package/src/journey-map/parser.ts +5 -2
- package/src/kanban/parser.ts +6 -2
- package/src/map/context-labels.ts +29 -19
- package/src/map/layout.ts +403 -108
- package/src/map/legend-band.ts +28 -0
- package/src/map/parser.ts +13 -4
- package/src/map/renderer.ts +74 -23
- package/src/map/resolver.ts +2 -2
- package/src/org/parser.ts +8 -2
- package/src/pyramid/parser.ts +4 -1
- package/src/raci/parser.ts +4 -1
- package/src/ring/parser.ts +4 -1
- package/src/sequence/parser.ts +6 -3
- package/src/sitemap/parser.ts +12 -3
- package/src/tech-radar/parser.ts +6 -3
- package/src/utils/parsing.ts +2 -2
- package/src/utils/tag-groups.ts +3 -3
- package/src/visualizations/parse.ts +9 -3
- package/src/migrate/data-comma.ts +0 -117
- package/src/migrate/embedded.ts +0 -238
- package/src/migrate/index.ts +0 -295
- package/src/migrate/line-classifier.ts +0 -128
- package/src/migrate/line-transformer.ts +0 -218
package/dist/advanced.js
CHANGED
|
@@ -35,6 +35,17 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
35
35
|
function makeDgmoError(line11, message, severity = "error", code) {
|
|
36
36
|
return code !== void 0 ? { line: line11, message, severity, code } : { line: line11, message, severity };
|
|
37
37
|
}
|
|
38
|
+
function dedupeDiagnostics(diagnostics) {
|
|
39
|
+
const seen = /* @__PURE__ */ new Set();
|
|
40
|
+
const out = [];
|
|
41
|
+
for (const d of diagnostics) {
|
|
42
|
+
const key = `${d.line}\0${d.column ?? ""}\0${d.severity}\0${d.code ?? ""}\0${d.message}`;
|
|
43
|
+
if (seen.has(key)) continue;
|
|
44
|
+
seen.add(key);
|
|
45
|
+
out.push(d);
|
|
46
|
+
}
|
|
47
|
+
return out;
|
|
48
|
+
}
|
|
38
49
|
function formatDgmoError(err) {
|
|
39
50
|
return err.line > 0 ? `Line ${err.line}: ${err.message}` : err.message;
|
|
40
51
|
}
|
|
@@ -92,7 +103,7 @@ function vennAliasKeywordRemovedMessage(args) {
|
|
|
92
103
|
return `Venn 'alias' keyword was removed. Use 'as' instead \u2014 '${args.name} as ${args.alias}'.`;
|
|
93
104
|
}
|
|
94
105
|
function pipeOperatorRemovedMessage() {
|
|
95
|
-
return `'|' removed \u2014 'Node | c: red' \u2192 'Node c: red'
|
|
106
|
+
return `'|' removed \u2014 'Node | c: red' \u2192 'Node c: red'`;
|
|
96
107
|
}
|
|
97
108
|
function ganttBarePercentRemovedMessage(percent) {
|
|
98
109
|
return `Bare-percent progress shorthand '| ${percent}' was removed. Use 'progress: ${percent.replace(/%$/, "")}' (integer 0\u2013100, no '%').`;
|
|
@@ -1245,7 +1256,7 @@ var init_parsing = __esm({
|
|
|
1245
1256
|
"no-title",
|
|
1246
1257
|
"no-notes"
|
|
1247
1258
|
]);
|
|
1248
|
-
MULTIPLE_PIPE_ERROR = '
|
|
1259
|
+
MULTIPLE_PIPE_ERROR = "'|' is no longer metadata syntax \u2014 put metadata on the same line as 'key: value, key2: value2' (no pipes), per \xA71.4.";
|
|
1249
1260
|
RESERVED_KEY_RE = /^[A-Za-z][A-Za-z0-9_-]*$/;
|
|
1250
1261
|
AS_ALIAS_RE = /\s+as\s+([A-Za-z][A-Za-z0-9_]{0,11})$/;
|
|
1251
1262
|
POTENTIAL_META_RE = /\b([\w-]+)\s*:/;
|
|
@@ -1426,12 +1437,10 @@ function validateTagValues(entities, tagGroups, pushWarning, suggestFn) {
|
|
|
1426
1437
|
);
|
|
1427
1438
|
if (!isPrefix) {
|
|
1428
1439
|
const defined = group.entries.map((e) => e.value);
|
|
1429
|
-
let msg = `Unknown value '${value}' for tag group '${group.name}'`;
|
|
1440
|
+
let msg = `Unknown value '${value}' for tag group '${group.name}' \u2014 use one of: ${defined.join(", ")}`;
|
|
1430
1441
|
const hint = suggestFn?.(value, defined);
|
|
1431
1442
|
if (hint) {
|
|
1432
1443
|
msg += `. ${hint}`;
|
|
1433
|
-
} else {
|
|
1434
|
-
msg += ` \u2014 defined values: ${defined.join(", ")}`;
|
|
1435
1444
|
}
|
|
1436
1445
|
pushWarning(entity.lineNumber, msg);
|
|
1437
1446
|
}
|
|
@@ -2207,7 +2216,10 @@ function parseVisualizationFull(content, palette) {
|
|
|
2207
2216
|
lineNumber
|
|
2208
2217
|
});
|
|
2209
2218
|
} else {
|
|
2210
|
-
warn(
|
|
2219
|
+
warn(
|
|
2220
|
+
lineNumber,
|
|
2221
|
+
`Unrecognized era entry: "${line11}" \u2014 use '<start> -> <end> Label [color]' (e.g. '1716 -> 1717 Reign').`
|
|
2222
|
+
);
|
|
2211
2223
|
}
|
|
2212
2224
|
continue;
|
|
2213
2225
|
}
|
|
@@ -2235,7 +2247,10 @@ function parseVisualizationFull(content, palette) {
|
|
|
2235
2247
|
lineNumber
|
|
2236
2248
|
});
|
|
2237
2249
|
} else {
|
|
2238
|
-
warn(
|
|
2250
|
+
warn(
|
|
2251
|
+
lineNumber,
|
|
2252
|
+
`Unrecognized marker entry: "${line11}" \u2014 use '<date> Label [color]' (e.g. '1776 Independence').`
|
|
2253
|
+
);
|
|
2239
2254
|
}
|
|
2240
2255
|
continue;
|
|
2241
2256
|
}
|
|
@@ -2913,7 +2928,7 @@ function parseVisualizationFull(content, palette) {
|
|
|
2913
2928
|
result.diagnostics.push(
|
|
2914
2929
|
makeDgmoError(
|
|
2915
2930
|
ov.lineNumber,
|
|
2916
|
-
`Intersection references unknown set or alias "${ref}"`
|
|
2931
|
+
`Intersection references unknown set or alias "${ref}" \u2014 declare the set first on its own line ('Name [as <alias>] [color]', e.g. 'Navigation as nav blue'), then reference it by that name or alias. (\xA716.4)`
|
|
2917
2932
|
)
|
|
2918
2933
|
);
|
|
2919
2934
|
if (!result.error)
|
|
@@ -6296,10 +6311,10 @@ function parseSequenceDgmo(content, palette) {
|
|
|
6296
6311
|
const rawInside = fallbackMatch[1];
|
|
6297
6312
|
const pipeIdx = rawInside.indexOf("|");
|
|
6298
6313
|
const cleanName = rawInside.substring(0, pipeIdx).trim().replace(/\([^)]*\)$/, "").trim();
|
|
6299
|
-
const metaPart = rawInside.substring(pipeIdx).trim();
|
|
6314
|
+
const metaPart = rawInside.substring(pipeIdx).replace(/^\|\s*/, "").trim();
|
|
6300
6315
|
pushError(
|
|
6301
6316
|
lineNumber,
|
|
6302
|
-
`
|
|
6317
|
+
`Metadata goes after the bracket with no pipe \u2014 use '[${cleanName}] ${metaPart}' (e.g. '[Backend] t: Product'), not '[${rawInside.trim()}]'`
|
|
6303
6318
|
);
|
|
6304
6319
|
continue;
|
|
6305
6320
|
}
|
|
@@ -6909,7 +6924,7 @@ function parseSequenceDgmo(content, palette) {
|
|
|
6909
6924
|
}
|
|
6910
6925
|
pushWarning(
|
|
6911
6926
|
lineNumber,
|
|
6912
|
-
`Unexpected line: '${trimmed}'. Expected a message (A -> B), participant, section (== Name ==), or block
|
|
6927
|
+
`Unexpected line: '${trimmed}'. Expected a message ('A -> B' or 'A -label-> B'), participant ('Name' or 'Name is a actor'), note ('note right of A Text'), section ('== Name =='), or block ('if/loop/parallel <label>').`
|
|
6913
6928
|
);
|
|
6914
6929
|
}
|
|
6915
6930
|
if (!hasExplicitChart && result.messages.length === 0) {
|
|
@@ -8071,7 +8086,11 @@ function parseFlowchart(content, palette) {
|
|
|
8071
8086
|
const value = optMatch[2].trim();
|
|
8072
8087
|
if (key === "no-color") {
|
|
8073
8088
|
result.diagnostics.push(
|
|
8074
|
-
makeDgmoError(
|
|
8089
|
+
makeDgmoError(
|
|
8090
|
+
lineNumber,
|
|
8091
|
+
'"no-color" was removed \u2014 node colors are assigned automatically by shape; delete this line.',
|
|
8092
|
+
"warning"
|
|
8093
|
+
)
|
|
8075
8094
|
);
|
|
8076
8095
|
continue;
|
|
8077
8096
|
}
|
|
@@ -8400,7 +8419,11 @@ function parseState(content, palette) {
|
|
|
8400
8419
|
const value = optMatch[2].trim();
|
|
8401
8420
|
if (key === "no-color") {
|
|
8402
8421
|
result.diagnostics.push(
|
|
8403
|
-
makeDgmoError(
|
|
8422
|
+
makeDgmoError(
|
|
8423
|
+
lineNumber,
|
|
8424
|
+
'"no-color" was removed \u2014 state colors are assigned automatically; delete this line.',
|
|
8425
|
+
"warning"
|
|
8426
|
+
)
|
|
8404
8427
|
);
|
|
8405
8428
|
continue;
|
|
8406
8429
|
}
|
|
@@ -8715,7 +8738,7 @@ function parseClassDiagram(content, palette) {
|
|
|
8715
8738
|
result.diagnostics.push(
|
|
8716
8739
|
makeDgmoError(
|
|
8717
8740
|
lineNumber,
|
|
8718
|
-
'"no-auto-color"
|
|
8741
|
+
'"no-auto-color" was removed \u2014 colors are always auto-assigned from the palette; delete this line.',
|
|
8719
8742
|
"warning"
|
|
8720
8743
|
)
|
|
8721
8744
|
);
|
|
@@ -8830,7 +8853,11 @@ function parseClassDiagram(content, palette) {
|
|
|
8830
8853
|
continue;
|
|
8831
8854
|
}
|
|
8832
8855
|
result.diagnostics.push(
|
|
8833
|
-
makeDgmoError(
|
|
8856
|
+
makeDgmoError(
|
|
8857
|
+
lineNumber,
|
|
8858
|
+
`Unexpected line: '${trimmed}'. Classes start uppercase at indent 0 ('Ship'); members are indented and colon-typed ('+ name: string', '+ sail(): void'); relationships are indented arrows ('--|> Vessel'). (\xA710)`,
|
|
8859
|
+
"warning"
|
|
8860
|
+
)
|
|
8834
8861
|
);
|
|
8835
8862
|
}
|
|
8836
8863
|
if (notes.length > 0) {
|
|
@@ -9308,7 +9335,11 @@ function parseERDiagram(content, palette) {
|
|
|
9308
9335
|
continue;
|
|
9309
9336
|
}
|
|
9310
9337
|
result.diagnostics.push(
|
|
9311
|
-
makeDgmoError(
|
|
9338
|
+
makeDgmoError(
|
|
9339
|
+
lineNumber,
|
|
9340
|
+
`Unexpected line: '${trimmed}'. A table is a bare name at indent 0 ('users'); columns are indented and SPACE-separated, no colon ('id int pk'); relationships are indented ('1--* orders'). (\xA79)`,
|
|
9341
|
+
"warning"
|
|
9342
|
+
)
|
|
9312
9343
|
);
|
|
9313
9344
|
}
|
|
9314
9345
|
if (result.tables.length === 0 && !result.error) {
|
|
@@ -9652,7 +9683,10 @@ function parseOrg(content, palette) {
|
|
|
9652
9683
|
const value = metadataMatch[2].trim();
|
|
9653
9684
|
const parent = findMetadataParent(indent, indentStack);
|
|
9654
9685
|
if (!parent) {
|
|
9655
|
-
pushError(
|
|
9686
|
+
pushError(
|
|
9687
|
+
lineNumber,
|
|
9688
|
+
"Metadata 'key: value' must be indented under a node \u2014 no node precedes it."
|
|
9689
|
+
);
|
|
9656
9690
|
} else {
|
|
9657
9691
|
parent.metadata = { ...parent.metadata, [key]: value };
|
|
9658
9692
|
}
|
|
@@ -9670,7 +9704,10 @@ function parseOrg(content, palette) {
|
|
|
9670
9704
|
);
|
|
9671
9705
|
attachNode(node, indent, indentStack, result);
|
|
9672
9706
|
} else {
|
|
9673
|
-
pushError(
|
|
9707
|
+
pushError(
|
|
9708
|
+
lineNumber,
|
|
9709
|
+
"Metadata 'key: value' must be indented under a node \u2014 no node precedes it."
|
|
9710
|
+
);
|
|
9674
9711
|
}
|
|
9675
9712
|
} else {
|
|
9676
9713
|
const node = parseNodeLabel(
|
|
@@ -10019,7 +10056,10 @@ function parseSitemap(content, palette) {
|
|
|
10019
10056
|
if (arrowInfo) {
|
|
10020
10057
|
const source = findParentNode(indent, indentStack);
|
|
10021
10058
|
if (!source) {
|
|
10022
|
-
pushError(
|
|
10059
|
+
pushError(
|
|
10060
|
+
lineNumber,
|
|
10061
|
+
"Arrow '-> target' must be indented under its source page \u2014 no page precedes it."
|
|
10062
|
+
);
|
|
10023
10063
|
} else {
|
|
10024
10064
|
deferredArrows.push({
|
|
10025
10065
|
sourceNode: source,
|
|
@@ -10089,7 +10129,10 @@ function parseSitemap(content, palette) {
|
|
|
10089
10129
|
const value = metadataMatch[2].trim();
|
|
10090
10130
|
const parent = findParentNode(indent, indentStack);
|
|
10091
10131
|
if (!parent) {
|
|
10092
|
-
pushError(
|
|
10132
|
+
pushError(
|
|
10133
|
+
lineNumber,
|
|
10134
|
+
"Metadata 'key: value' must be indented under a page \u2014 no page precedes it."
|
|
10135
|
+
);
|
|
10093
10136
|
} else {
|
|
10094
10137
|
parent.metadata = { ...parent.metadata, [key]: value };
|
|
10095
10138
|
}
|
|
@@ -10109,7 +10152,10 @@ function parseSitemap(content, palette) {
|
|
|
10109
10152
|
const key = normalizeName(node.label);
|
|
10110
10153
|
labelToNode.set(key, node);
|
|
10111
10154
|
} else {
|
|
10112
|
-
pushError(
|
|
10155
|
+
pushError(
|
|
10156
|
+
lineNumber,
|
|
10157
|
+
"Metadata 'key: value' must be indented under a page \u2014 no page precedes it."
|
|
10158
|
+
);
|
|
10113
10159
|
}
|
|
10114
10160
|
} else {
|
|
10115
10161
|
const descResult = tryStripDescriptionKeyword(trimmed);
|
|
@@ -11927,7 +11973,7 @@ function parseChart(content, palette) {
|
|
|
11927
11973
|
result.diagnostics.push(
|
|
11928
11974
|
makeDgmoError(
|
|
11929
11975
|
lineNumber,
|
|
11930
|
-
`'${trimmed}' \u2014 ##
|
|
11976
|
+
`'${trimmed}' removed \u2014 use a bracket container '[${trimmed.replace(/^#+\s*/, "")}]' instead (## headers are no longer supported).`
|
|
11931
11977
|
)
|
|
11932
11978
|
);
|
|
11933
11979
|
continue;
|
|
@@ -12919,7 +12965,11 @@ function parseExtendedChartFull(content, palette) {
|
|
|
12919
12965
|
continue;
|
|
12920
12966
|
}
|
|
12921
12967
|
result.diagnostics.push(
|
|
12922
|
-
makeDgmoError(
|
|
12968
|
+
makeDgmoError(
|
|
12969
|
+
lineNumber,
|
|
12970
|
+
`Unexpected line: '${trimmed}'. Expected a data row ('Label value', space-separated) or a known option.`,
|
|
12971
|
+
"warning"
|
|
12972
|
+
)
|
|
12923
12973
|
);
|
|
12924
12974
|
}
|
|
12925
12975
|
const warn = (line11, message) => {
|
|
@@ -15277,7 +15327,10 @@ function parseKanban(content, palette) {
|
|
|
15277
15327
|
continue;
|
|
15278
15328
|
}
|
|
15279
15329
|
if (!currentColumn) {
|
|
15280
|
-
warn(
|
|
15330
|
+
warn(
|
|
15331
|
+
lineNumber,
|
|
15332
|
+
"Card line found before any column. Declare a column first with '[Column Name]', then indent cards beneath it. (\xA711)"
|
|
15333
|
+
);
|
|
15281
15334
|
continue;
|
|
15282
15335
|
}
|
|
15283
15336
|
if (currentCard && indent > cardBaseIndent) {
|
|
@@ -15416,7 +15469,7 @@ var init_parser13 = __esm({
|
|
|
15416
15469
|
KNOWN_OPTIONS4 = /* @__PURE__ */ new Set(["hide", "active-tag"]);
|
|
15417
15470
|
KNOWN_BOOLEANS3 = /* @__PURE__ */ new Set(["solid-fill", "no-title"]);
|
|
15418
15471
|
REMOVED_BOOLEANS = {
|
|
15419
|
-
"no-auto-color": '"no-auto-color"
|
|
15472
|
+
"no-auto-color": '"no-auto-color" was removed \u2014 colors are always auto-assigned from the palette; delete this line.'
|
|
15420
15473
|
};
|
|
15421
15474
|
}
|
|
15422
15475
|
});
|
|
@@ -15653,7 +15706,7 @@ function parseC4(content, palette) {
|
|
|
15653
15706
|
} else {
|
|
15654
15707
|
pushError(
|
|
15655
15708
|
lineNumber,
|
|
15656
|
-
`"container ${refName}" must be
|
|
15709
|
+
`"container ${refName}" must be indented under a deployment node (e.g. under 'Prod is a deployment-node')`
|
|
15657
15710
|
);
|
|
15658
15711
|
}
|
|
15659
15712
|
continue;
|
|
@@ -15708,7 +15761,10 @@ function parseC4(content, palette) {
|
|
|
15708
15761
|
indent
|
|
15709
15762
|
});
|
|
15710
15763
|
} else {
|
|
15711
|
-
pushError(
|
|
15764
|
+
pushError(
|
|
15765
|
+
lineNumber,
|
|
15766
|
+
`"${sectionType}" must be indented under an element (e.g. under 'Web App is a container')`
|
|
15767
|
+
);
|
|
15712
15768
|
}
|
|
15713
15769
|
continue;
|
|
15714
15770
|
}
|
|
@@ -15735,7 +15791,10 @@ function parseC4(content, palette) {
|
|
|
15735
15791
|
indent
|
|
15736
15792
|
});
|
|
15737
15793
|
} else {
|
|
15738
|
-
pushError(
|
|
15794
|
+
pushError(
|
|
15795
|
+
lineNumber,
|
|
15796
|
+
`Group [${groupName}] must be indented under an element (e.g. under 'Web App is a container')`
|
|
15797
|
+
);
|
|
15739
15798
|
}
|
|
15740
15799
|
continue;
|
|
15741
15800
|
}
|
|
@@ -16065,7 +16124,10 @@ function parseC4(content, palette) {
|
|
|
16065
16124
|
}
|
|
16066
16125
|
desc.push(descResult.text);
|
|
16067
16126
|
} else {
|
|
16068
|
-
pushError(
|
|
16127
|
+
pushError(
|
|
16128
|
+
lineNumber,
|
|
16129
|
+
`Unexpected content: "${trimmed}". Expected an element ('Web App is a container'), a relationship ('-Uses-> Database'), indented metadata ('tech: React'), or a group ('[Backend]'). (\xA78)`
|
|
16130
|
+
);
|
|
16069
16131
|
}
|
|
16070
16132
|
}
|
|
16071
16133
|
finalizeAutoTagColors(result.tagGroups, palette);
|
|
@@ -16127,7 +16189,7 @@ function validateRelationshipTargets(result, knownNames, pushWarning) {
|
|
|
16127
16189
|
for (const el of elements) {
|
|
16128
16190
|
for (const rel of el.relationships) {
|
|
16129
16191
|
if (!knownNames.has(normalizeName(rel.target))) {
|
|
16130
|
-
let msg = `Relationship target "${rel.target}" not found`;
|
|
16192
|
+
let msg = `Relationship target "${rel.target}" not found \u2014 declare it first (e.g. '${rel.target} is a container'), then reference it in the arrow`;
|
|
16131
16193
|
const hint = suggest(normalizeName(rel.target), allNames);
|
|
16132
16194
|
if (hint) msg += `. ${hint}`;
|
|
16133
16195
|
pushWarning(rel.lineNumber, msg, "warning");
|
|
@@ -16155,7 +16217,7 @@ function validateDeploymentRefs(result, knownNames, pushWarning) {
|
|
|
16155
16217
|
for (const node of nodes) {
|
|
16156
16218
|
for (const ref of node.containerRefs) {
|
|
16157
16219
|
if (!knownNames.has(normalizeName(ref))) {
|
|
16158
|
-
let msg = `Deployment reference "container ${ref}" not found`;
|
|
16220
|
+
let msg = `Deployment reference "container ${ref}" not found \u2014 declare the container element first, then reference it under the deployment node`;
|
|
16159
16221
|
const hint = suggest(normalizeName(ref), allNames);
|
|
16160
16222
|
if (hint) msg += `. ${hint}`;
|
|
16161
16223
|
pushWarning(node.lineNumber, msg, "warning");
|
|
@@ -16874,7 +16936,7 @@ function parseInfra(content) {
|
|
|
16874
16936
|
}
|
|
16875
16937
|
warn(
|
|
16876
16938
|
lineNumber,
|
|
16877
|
-
`Invalid tag value '${trimmed}' in tag group '${currentTagGroup.name}'.`
|
|
16939
|
+
`Invalid tag value '${trimmed}' in tag group '${currentTagGroup.name}' \u2014 a value is a bare word with an optional trailing color (e.g. 'Production red'); no ':' or '|'.`
|
|
16878
16940
|
);
|
|
16879
16941
|
continue;
|
|
16880
16942
|
}
|
|
@@ -16947,7 +17009,7 @@ function parseInfra(content) {
|
|
|
16947
17009
|
const n = deprecatedFanout[1];
|
|
16948
17010
|
setError(
|
|
16949
17011
|
lineNumber,
|
|
16950
|
-
`'x${n}' fanout syntax is no longer supported \u2014 use '
|
|
17012
|
+
`'x${n}' fanout syntax is no longer supported \u2014 use 'fanout: ${n}' instead`
|
|
16951
17013
|
);
|
|
16952
17014
|
continue;
|
|
16953
17015
|
}
|
|
@@ -17121,8 +17183,10 @@ function parseInfra(content) {
|
|
|
17121
17183
|
const hint = suggest(key, allKeys);
|
|
17122
17184
|
const valueLooksNumeric = /^[\d.]+%?$/.test(rawVal);
|
|
17123
17185
|
if (hint || valueLooksNumeric) {
|
|
17124
|
-
let msg = `Unknown property '${key}'.`;
|
|
17186
|
+
let msg = `Unknown infra property '${key}'.`;
|
|
17125
17187
|
if (hint) msg += ` ${hint}`;
|
|
17188
|
+
else
|
|
17189
|
+
msg += ` Properties are colon-keyed 'key: value' from the known schema (e.g. latency-ms, max-rps, cache-hit, instances, concurrency).`;
|
|
17126
17190
|
warn(lineNumber, msg);
|
|
17127
17191
|
} else if (!currentNode.isEdge) {
|
|
17128
17192
|
pushDescription(currentNode, trimmed);
|
|
@@ -17133,7 +17197,7 @@ function parseInfra(content) {
|
|
|
17133
17197
|
if (EDGE_ONLY_KEYS.has(key) && !currentNode.isEdge) {
|
|
17134
17198
|
warn(
|
|
17135
17199
|
lineNumber,
|
|
17136
|
-
`Property '${key}'
|
|
17200
|
+
`Property '${key}' belongs on the entry point \u2014 declare it indented under an 'internet' or 'edge' node, not on '${currentNode.label}'.`
|
|
17137
17201
|
);
|
|
17138
17202
|
}
|
|
17139
17203
|
const value = parsePropertyValue(rawVal);
|
|
@@ -17240,7 +17304,7 @@ function parseInfra(content) {
|
|
|
17240
17304
|
}
|
|
17241
17305
|
warn(
|
|
17242
17306
|
lineNumber,
|
|
17243
|
-
currentGroup ? `Unexpected line: '${trimmed}'.
|
|
17307
|
+
currentGroup ? `Unexpected line: '${trimmed}'. Inside a group, indent a component name under the '[Group]'.` : `Unexpected line: '${trimmed}'. Expected a node ('Api Gateway'), a group ('[Backend]'), a tag group ('tag Tier as t'), or an option ('default-rps 100'); node properties go indented under a node as 'key: value'.`
|
|
17244
17308
|
);
|
|
17245
17309
|
}
|
|
17246
17310
|
finishCurrentNode();
|
|
@@ -17616,7 +17680,10 @@ function parseGantt(content, palette) {
|
|
|
17616
17680
|
continue;
|
|
17617
17681
|
}
|
|
17618
17682
|
if (COMMENT_RE.test(line11)) continue;
|
|
17619
|
-
warn(
|
|
17683
|
+
warn(
|
|
17684
|
+
lineNumber,
|
|
17685
|
+
`Unrecognized holiday entry: "${line11}". Use a date '2024-02-19 Presidents Day' or a range '2024-05-27 -> 2024-05-29 Memorial Weekend'. (\xA713.3)`
|
|
17686
|
+
);
|
|
17620
17687
|
continue;
|
|
17621
17688
|
}
|
|
17622
17689
|
}
|
|
@@ -17642,7 +17709,10 @@ function parseGantt(content, palette) {
|
|
|
17642
17709
|
lineNumber
|
|
17643
17710
|
});
|
|
17644
17711
|
} else {
|
|
17645
|
-
warn(
|
|
17712
|
+
warn(
|
|
17713
|
+
lineNumber,
|
|
17714
|
+
`Unrecognized era entry: "${line11}". Use 'YYYY-MM-DD -> YYYY-MM-DD Label [color]' (e.g. '2026-04-06 -> 2026-04-10 Conference purple'). (\xA713.5)`
|
|
17715
|
+
);
|
|
17646
17716
|
}
|
|
17647
17717
|
continue;
|
|
17648
17718
|
}
|
|
@@ -17668,7 +17738,10 @@ function parseGantt(content, palette) {
|
|
|
17668
17738
|
lineNumber
|
|
17669
17739
|
});
|
|
17670
17740
|
} else {
|
|
17671
|
-
warn(
|
|
17741
|
+
warn(
|
|
17742
|
+
lineNumber,
|
|
17743
|
+
`Unrecognized marker entry: "${line11}". Use 'YYYY-MM-DD Label [color]' (e.g. '2026-03-27 Board Review' or '2026-06-15 Release green'). (\xA713.6)`
|
|
17744
|
+
);
|
|
17672
17745
|
}
|
|
17673
17746
|
continue;
|
|
17674
17747
|
}
|
|
@@ -17834,7 +17907,7 @@ function parseGantt(content, palette) {
|
|
|
17834
17907
|
} else {
|
|
17835
17908
|
softError(
|
|
17836
17909
|
lineNumber,
|
|
17837
|
-
`Arrow
|
|
17910
|
+
`Arrow '-> ${content2.name}' has no source task \u2014 indent it under the task it follows (e.g. 'Design 5bd' then indented '-> ${content2.name} 3bd'). (\xA713)`
|
|
17838
17911
|
);
|
|
17839
17912
|
}
|
|
17840
17913
|
}
|
|
@@ -19054,7 +19127,10 @@ function parseMap(content, palette) {
|
|
|
19054
19127
|
function handleTag(trimmed, line11) {
|
|
19055
19128
|
const m = matchTagBlockHeading(trimmed);
|
|
19056
19129
|
if (!m) {
|
|
19057
|
-
pushError(
|
|
19130
|
+
pushError(
|
|
19131
|
+
line11,
|
|
19132
|
+
`Malformed tag declaration: "${trimmed}" \u2014 write 'tag <Group>' (optionally 'tag <Group> as <alias>'), e.g. 'tag Market as m', with indented 'Value color' entries below.`
|
|
19133
|
+
);
|
|
19058
19134
|
return;
|
|
19059
19135
|
}
|
|
19060
19136
|
emitTagLegacyDiagnostic(m, line11, diagnostics);
|
|
@@ -19166,7 +19242,7 @@ function parseMap(content, palette) {
|
|
|
19166
19242
|
if (!pos || pos.kind === "name" && !pos.name) {
|
|
19167
19243
|
pushError(
|
|
19168
19244
|
line11,
|
|
19169
|
-
"route
|
|
19245
|
+
"route needs an origin place \u2014 `route <origin>` then indented legs (`-> dest`); origin may be a city name, IATA code, or `<lat> <lon>`. (\xA724B)"
|
|
19170
19246
|
);
|
|
19171
19247
|
return;
|
|
19172
19248
|
}
|
|
@@ -19229,7 +19305,10 @@ function parseMap(content, palette) {
|
|
|
19229
19305
|
function handleEdges(trimmed, line11) {
|
|
19230
19306
|
const parts = trimmed.split(ARROW_SPLIT);
|
|
19231
19307
|
if (parts.length < 3) {
|
|
19232
|
-
pushError(
|
|
19308
|
+
pushError(
|
|
19309
|
+
line11,
|
|
19310
|
+
`Malformed edge: "${trimmed}" \u2014 an edge is 'A -> B' (or 'A -label-> B', '~>' for arc, '--' undirected), both endpoints non-empty. (\xA724B)`
|
|
19311
|
+
);
|
|
19233
19312
|
return;
|
|
19234
19313
|
}
|
|
19235
19314
|
const endpoints = [];
|
|
@@ -19252,7 +19331,10 @@ function parseMap(content, palette) {
|
|
|
19252
19331
|
const from = endpoints[k];
|
|
19253
19332
|
const to = endpoints[k + 1];
|
|
19254
19333
|
if (!from || !to) {
|
|
19255
|
-
pushError(
|
|
19334
|
+
pushError(
|
|
19335
|
+
line11,
|
|
19336
|
+
`Edge has an empty endpoint: "${trimmed}" \u2014 both sides of the arrow need a place, e.g. 'Paris -> Berlin'. (\xA724B)`
|
|
19337
|
+
);
|
|
19256
19338
|
continue;
|
|
19257
19339
|
}
|
|
19258
19340
|
const isLast = k === links.length - 1;
|
|
@@ -21371,7 +21453,10 @@ function parseTechRadar(content) {
|
|
|
21371
21453
|
}
|
|
21372
21454
|
if (indent === 0 && trimmed.toLowerCase() === "rings") {
|
|
21373
21455
|
if (result.rings.length > 0) {
|
|
21374
|
-
warn(
|
|
21456
|
+
warn(
|
|
21457
|
+
lineNumber,
|
|
21458
|
+
'Duplicate "rings" block \u2014 only the last is kept; merge all ring names into one "rings" block.'
|
|
21459
|
+
);
|
|
21375
21460
|
result.rings = [];
|
|
21376
21461
|
}
|
|
21377
21462
|
inRingsBlock = true;
|
|
@@ -21590,7 +21675,7 @@ function parseTechRadar(content) {
|
|
|
21590
21675
|
result.diagnostics.push(
|
|
21591
21676
|
makeDgmoError(
|
|
21592
21677
|
lineNumber,
|
|
21593
|
-
`Blip "${trimmed}" has no ring
|
|
21678
|
+
`Blip "${trimmed}" has no ring. Put it under a ring section header, or add a colon-keyed ring \u2014 '${trimmed} ring: RingName' (per \xA720).`
|
|
21594
21679
|
)
|
|
21595
21680
|
);
|
|
21596
21681
|
continue;
|
|
@@ -21599,7 +21684,7 @@ function parseTechRadar(content) {
|
|
|
21599
21684
|
if (!trimmed.includes("|") && headerParsed && result.rings.length > 0) {
|
|
21600
21685
|
warn(
|
|
21601
21686
|
lineNumber,
|
|
21602
|
-
`Unrecognized line "${trimmed}".
|
|
21687
|
+
`Unrecognized line "${trimmed}". A quadrant header is 'Name quadrant: <top-left|top-right|bottom-left|bottom-right>' (per \xA720).`
|
|
21603
21688
|
);
|
|
21604
21689
|
}
|
|
21605
21690
|
}
|
|
@@ -21892,7 +21977,10 @@ function parseCycle(content) {
|
|
|
21892
21977
|
currentNode.description.push(descLine);
|
|
21893
21978
|
continue;
|
|
21894
21979
|
}
|
|
21895
|
-
warn(
|
|
21980
|
+
warn(
|
|
21981
|
+
lineNum,
|
|
21982
|
+
`Indented line "${trimmed}" has no step above it \u2014 add a step on a non-indented line first, then indent its details. (\xA721)`
|
|
21983
|
+
);
|
|
21896
21984
|
continue;
|
|
21897
21985
|
}
|
|
21898
21986
|
}
|
|
@@ -22195,7 +22283,7 @@ function parseJourneyMap(content, palette) {
|
|
|
22195
22283
|
if (trimmed.includes("|") || !PHASE_RE.test(trimmed)) {
|
|
22196
22284
|
warn(
|
|
22197
22285
|
lineNumber,
|
|
22198
|
-
"
|
|
22286
|
+
`Step "${trimmed}" sits outside any phase and is ignored \u2014 indent it under a '[Phase]' header (per \xA722).`
|
|
22199
22287
|
);
|
|
22200
22288
|
continue;
|
|
22201
22289
|
}
|
|
@@ -22252,7 +22340,10 @@ function parseJourneyMap(content, palette) {
|
|
|
22252
22340
|
continue;
|
|
22253
22341
|
}
|
|
22254
22342
|
if (indent > 0 && !currentPhase && hasPhases) {
|
|
22255
|
-
warn(
|
|
22343
|
+
warn(
|
|
22344
|
+
lineNumber,
|
|
22345
|
+
`Indented line outside any phase \u2014 add a '[Phase]' header above it, or unindent it to a top-level step. (\xA722)`
|
|
22346
|
+
);
|
|
22256
22347
|
}
|
|
22257
22348
|
}
|
|
22258
22349
|
if (currentStep) {
|
|
@@ -22598,7 +22689,10 @@ function parsePyramid(content) {
|
|
|
22598
22689
|
continue;
|
|
22599
22690
|
}
|
|
22600
22691
|
if (!currentLayer) {
|
|
22601
|
-
warn(
|
|
22692
|
+
warn(
|
|
22693
|
+
lineNum,
|
|
22694
|
+
`Indented description "${trimmed}" has no layer above it \u2014 add a layer name on a non-indented line first. (\xA723)`
|
|
22695
|
+
);
|
|
22602
22696
|
continue;
|
|
22603
22697
|
}
|
|
22604
22698
|
const descLine = trimmed.startsWith("- ") ? `\u2022 ${trimmed.substring(2)}` : trimmed;
|
|
@@ -22772,7 +22866,10 @@ function parseRing(content) {
|
|
|
22772
22866
|
continue;
|
|
22773
22867
|
}
|
|
22774
22868
|
if (!currentLayer) {
|
|
22775
|
-
warn(
|
|
22869
|
+
warn(
|
|
22870
|
+
lineNum,
|
|
22871
|
+
`Indented description "${trimmed}" has no layer above it \u2014 add a layer name on a non-indented line first. (\xA724)`
|
|
22872
|
+
);
|
|
22776
22873
|
continue;
|
|
22777
22874
|
}
|
|
22778
22875
|
const descLine = trimmed.startsWith("- ") ? `\u2022 ${trimmed.substring(2)}` : trimmed;
|
|
@@ -23498,7 +23595,10 @@ function parseRaci(content, palette) {
|
|
|
23498
23595
|
continue;
|
|
23499
23596
|
}
|
|
23500
23597
|
if (bodyStarted) {
|
|
23501
|
-
errorAt(
|
|
23598
|
+
errorAt(
|
|
23599
|
+
lineNumber,
|
|
23600
|
+
`Unexpected line: '${trimmed}'. In the body expect a '[Phase]' header, an indented task name, or an assignment 'Role: A R C I' under a task. (\xA724A)`
|
|
23601
|
+
);
|
|
23502
23602
|
} else {
|
|
23503
23603
|
warn(lineNumber, `Unrecognized directive: '${trimmed}'.`);
|
|
23504
23604
|
}
|
|
@@ -24045,6 +24145,13 @@ function getAllChartTypes() {
|
|
|
24045
24145
|
return chartTypes.map((c) => c.id);
|
|
24046
24146
|
}
|
|
24047
24147
|
function parseDgmo(content) {
|
|
24148
|
+
const result = parseDgmoUndeduped(content);
|
|
24149
|
+
return {
|
|
24150
|
+
diagnostics: dedupeDiagnostics(result.diagnostics),
|
|
24151
|
+
chartType: result.chartType
|
|
24152
|
+
};
|
|
24153
|
+
}
|
|
24154
|
+
function parseDgmoUndeduped(content) {
|
|
24048
24155
|
const chartType = parseDgmoChartType(content);
|
|
24049
24156
|
if (!chartType) {
|
|
24050
24157
|
const colonDiag = detectColonChartType(content);
|
|
@@ -29201,63 +29308,6 @@ function ensureArrowMarkers(defs, colors) {
|
|
|
29201
29308
|
).attr("fill", color);
|
|
29202
29309
|
}
|
|
29203
29310
|
}
|
|
29204
|
-
function edgePolylineMidpoint(points) {
|
|
29205
|
-
if (points.length === 0) return { x: 0, y: 0 };
|
|
29206
|
-
if (points.length === 1) return { x: points[0].x, y: points[0].y };
|
|
29207
|
-
let total = 0;
|
|
29208
|
-
const segLen = [];
|
|
29209
|
-
for (let k = 1; k < points.length; k++) {
|
|
29210
|
-
const len = Math.hypot(
|
|
29211
|
-
points[k].x - points[k - 1].x,
|
|
29212
|
-
points[k].y - points[k - 1].y
|
|
29213
|
-
);
|
|
29214
|
-
segLen.push(len);
|
|
29215
|
-
total += len;
|
|
29216
|
-
}
|
|
29217
|
-
let half = total / 2;
|
|
29218
|
-
for (let k = 1; k < points.length; k++) {
|
|
29219
|
-
const len = segLen[k - 1];
|
|
29220
|
-
if (half <= len || k === points.length - 1) {
|
|
29221
|
-
const t = len === 0 ? 0 : Math.min(1, half / len);
|
|
29222
|
-
return {
|
|
29223
|
-
x: points[k - 1].x + (points[k].x - points[k - 1].x) * t,
|
|
29224
|
-
y: points[k - 1].y + (points[k].y - points[k - 1].y) * t
|
|
29225
|
-
};
|
|
29226
|
-
}
|
|
29227
|
-
half -= len;
|
|
29228
|
-
}
|
|
29229
|
-
const last = points[points.length - 1];
|
|
29230
|
-
return { x: last.x, y: last.y };
|
|
29231
|
-
}
|
|
29232
|
-
function resolveEdgeLabelOverlaps(labels) {
|
|
29233
|
-
const MAX_PASSES = 8;
|
|
29234
|
-
const PAD = 4;
|
|
29235
|
-
for (let pass = 0; pass < MAX_PASSES; pass++) {
|
|
29236
|
-
let moved = false;
|
|
29237
|
-
for (let i = 0; i < labels.length; i++) {
|
|
29238
|
-
for (let j = i + 1; j < labels.length; j++) {
|
|
29239
|
-
const a = labels[i];
|
|
29240
|
-
const b = labels[j];
|
|
29241
|
-
const dx = Math.abs(a.x - b.x);
|
|
29242
|
-
const dy = Math.abs(a.y - b.y);
|
|
29243
|
-
const overlapX = (a.width + b.width) / 2 + PAD - dx;
|
|
29244
|
-
const overlapY = (a.height + b.height) / 2 + PAD - dy;
|
|
29245
|
-
if (overlapX > 0 && overlapY > 0) {
|
|
29246
|
-
const shift = overlapY / 2 + 1;
|
|
29247
|
-
if (a.y < b.y) {
|
|
29248
|
-
a.y -= shift;
|
|
29249
|
-
b.y += shift;
|
|
29250
|
-
} else {
|
|
29251
|
-
a.y += shift;
|
|
29252
|
-
b.y -= shift;
|
|
29253
|
-
}
|
|
29254
|
-
moved = true;
|
|
29255
|
-
}
|
|
29256
|
-
}
|
|
29257
|
-
}
|
|
29258
|
-
if (!moved) break;
|
|
29259
|
-
}
|
|
29260
|
-
}
|
|
29261
29311
|
function renderBoxesAndLines(container, parsed, layout, palette, isDark, options) {
|
|
29262
29312
|
const {
|
|
29263
29313
|
onClickItem,
|
|
@@ -29464,8 +29514,6 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
29464
29514
|
groupG.append("text").attr("class", "bl-group-label").attr("x", gx + group.width / 2).attr("y", gy + 18).attr("text-anchor", "middle").attr("font-family", FONT_FAMILY).attr("font-size", sGroupLabelFontSize).attr("font-weight", "600").attr("fill", palette.text).text(group.label);
|
|
29465
29515
|
}
|
|
29466
29516
|
}
|
|
29467
|
-
const labelPositions = [];
|
|
29468
|
-
const edgeGroups = /* @__PURE__ */ new Map();
|
|
29469
29517
|
for (let i = 0; i < layout.edges.length; i++) {
|
|
29470
29518
|
const le = layout.edges[i];
|
|
29471
29519
|
const color = edgeColorMap.get(i) ?? palette.textMuted;
|
|
@@ -29484,7 +29532,6 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
29484
29532
|
const nodeLayout = layoutNodeMap.get(le.source);
|
|
29485
29533
|
if (nodeLayout) {
|
|
29486
29534
|
const edgeG2 = diagramG.append("g").attr("class", "bl-edge-group").attr("data-line-number", String(le.lineNumber));
|
|
29487
|
-
edgeGroups.set(i, edgeG2);
|
|
29488
29535
|
const markerId2 = `bl-arrow-${color.replace("#", "")}`;
|
|
29489
29536
|
const cx = nodeLayout.x;
|
|
29490
29537
|
const cy = nodeLayout.y;
|
|
@@ -29533,7 +29580,6 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
29533
29580
|
}
|
|
29534
29581
|
if (points.length < 2) continue;
|
|
29535
29582
|
const edgeG = diagramG.append("g").attr("class", "bl-edge-group").attr("data-line-number", String(le.lineNumber));
|
|
29536
|
-
edgeGroups.set(i, edgeG);
|
|
29537
29583
|
const markerId = `bl-arrow-${color.replace("#", "")}`;
|
|
29538
29584
|
const gen = le.straight ? lineGeneratorStraight : parsed.direction === "TB" ? lineGeneratorTB : lineGeneratorLR;
|
|
29539
29585
|
const path = edgeG.append("path").attr("class", "bl-edge").attr("d", gen(points) ?? "").attr("fill", "none").attr("stroke", color).attr("stroke-width", sEdgeStrokeWidth).attr("marker-end", `url(#${markerId})`);
|
|
@@ -29541,31 +29587,6 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
29541
29587
|
const revId = `bl-arrow-rev-${color.replace("#", "")}`;
|
|
29542
29588
|
path.attr("marker-start", `url(#${revId})`);
|
|
29543
29589
|
}
|
|
29544
|
-
if (le.label && le.points.length > 0) {
|
|
29545
|
-
const lw = measureText(le.label, sEdgeLabelFontSize);
|
|
29546
|
-
const labelH = sEdgeLabelFontSize + 6;
|
|
29547
|
-
const mid = edgePolylineMidpoint(le.points);
|
|
29548
|
-
let ly = mid.y;
|
|
29549
|
-
if (le.parallelCount > 1 && le.yOffset !== 0) {
|
|
29550
|
-
ly += (le.yOffset < 0 ? -labelH : labelH) * 0.5;
|
|
29551
|
-
}
|
|
29552
|
-
labelPositions.push({
|
|
29553
|
-
x: mid.x,
|
|
29554
|
-
y: ly,
|
|
29555
|
-
width: lw + 8,
|
|
29556
|
-
height: labelH,
|
|
29557
|
-
idx: i
|
|
29558
|
-
});
|
|
29559
|
-
}
|
|
29560
|
-
}
|
|
29561
|
-
resolveEdgeLabelOverlaps(labelPositions);
|
|
29562
|
-
for (const lp of labelPositions) {
|
|
29563
|
-
const le = layout.edges[lp.idx];
|
|
29564
|
-
if (!le.label) continue;
|
|
29565
|
-
const edgeG = edgeGroups.get(lp.idx);
|
|
29566
|
-
const target = edgeG ?? diagramG;
|
|
29567
|
-
target.append("rect").attr("x", lp.x - lp.width / 2).attr("y", lp.y - lp.height / 2).attr("width", lp.width).attr("height", lp.height).attr("rx", 3).attr("fill", palette.bg).attr("opacity", 0.85);
|
|
29568
|
-
target.append("text").attr("x", lp.x).attr("y", lp.y + sEdgeLabelFontSize / 3).attr("text-anchor", "middle").attr("font-size", sEdgeLabelFontSize).attr("fill", palette.textMuted).text(le.label);
|
|
29569
29590
|
}
|
|
29570
29591
|
for (const ln of layout.nodes) {
|
|
29571
29592
|
const node = nodeMap.get(ln.label);
|
|
@@ -29616,8 +29637,8 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
29616
29637
|
nodeG.append("rect").attr("x", x).attr("y", y).attr("width", ln.width).attr("height", ln.height).attr("rx", NODE_RX).attr("ry", NODE_RX).attr("fill", colors.fill).attr("stroke", colors.stroke).attr("stroke-width", sNodeStrokeWidth);
|
|
29617
29638
|
const desc = node.description;
|
|
29618
29639
|
if (desc && desc.length > 0 && !hideDescriptions) {
|
|
29619
|
-
const
|
|
29620
|
-
const fitted = fitLabelToHeader(node.label, ln.width,
|
|
29640
|
+
const MAX_LABEL_LINES4 = 3;
|
|
29641
|
+
const fitted = fitLabelToHeader(node.label, ln.width, MAX_LABEL_LINES4);
|
|
29621
29642
|
const labelLines = fitted.lines;
|
|
29622
29643
|
const labelLineH = fitted.fontSize * 1.3;
|
|
29623
29644
|
const labelTotalH = labelLines.length * labelLineH;
|
|
@@ -29751,6 +29772,35 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
29751
29772
|
}
|
|
29752
29773
|
}
|
|
29753
29774
|
}
|
|
29775
|
+
const labelLayer = diagramG.append("g").attr("class", "bl-edge-labels");
|
|
29776
|
+
const labelLineHeight = sEdgeLabelFontSize * 1.3;
|
|
29777
|
+
for (const le of layout.edges) {
|
|
29778
|
+
if (!le.labelLines || le.labelLines.length === 0) continue;
|
|
29779
|
+
if (le.labelX === void 0 || le.labelY === void 0) continue;
|
|
29780
|
+
const lx = le.labelX;
|
|
29781
|
+
const ly = le.labelY;
|
|
29782
|
+
if (hidden.size > 0) {
|
|
29783
|
+
let isHidden = false;
|
|
29784
|
+
for (const [groupKey2, hiddenVals] of hidden) {
|
|
29785
|
+
const val = le.metadata[groupKey2];
|
|
29786
|
+
if (val && hiddenVals.has(val.toLowerCase())) {
|
|
29787
|
+
isHidden = true;
|
|
29788
|
+
break;
|
|
29789
|
+
}
|
|
29790
|
+
}
|
|
29791
|
+
if (isHidden) continue;
|
|
29792
|
+
}
|
|
29793
|
+
const lw = le.labelWidth ?? 0;
|
|
29794
|
+
const lh = le.labelHeight ?? sEdgeLabelFontSize + 6;
|
|
29795
|
+
const lines = le.labelLines;
|
|
29796
|
+
const labelG = labelLayer.append("g").attr("class", "bl-edge-label").attr("data-line-number", String(le.lineNumber));
|
|
29797
|
+
labelG.append("rect").attr("x", lx - lw / 2).attr("y", ly - lh / 2).attr("width", lw).attr("height", lh).attr("rx", 3).attr("fill", palette.bg).attr("opacity", 0.72);
|
|
29798
|
+
const text = labelG.append("text").attr("x", lx).attr("text-anchor", "middle").attr("font-family", FONT_FAMILY).attr("font-size", sEdgeLabelFontSize).attr("fill", palette.textMuted);
|
|
29799
|
+
const firstY = ly - (lines.length - 1) / 2 * labelLineHeight + sEdgeLabelFontSize / 3;
|
|
29800
|
+
lines.forEach((line11, k) => {
|
|
29801
|
+
text.append("tspan").attr("x", lx).attr("y", firstY + k * labelLineHeight).text(line11);
|
|
29802
|
+
});
|
|
29803
|
+
}
|
|
29754
29804
|
const hasDescriptions = parsed.nodes.some(
|
|
29755
29805
|
(n) => n.description && n.description.length > 0
|
|
29756
29806
|
);
|
|
@@ -29865,6 +29915,222 @@ var init_renderer6 = __esm({
|
|
|
29865
29915
|
}
|
|
29866
29916
|
});
|
|
29867
29917
|
|
|
29918
|
+
// src/boxes-and-lines/label-placement.ts
|
|
29919
|
+
function measureEdgeLabel(label, fontSize = EDGE_LABEL_FONT_SIZE6, maxWidth = LABEL_MAX_WIDTH) {
|
|
29920
|
+
let lines = wrapTextToWidth(label, fontSize, maxWidth, { hardBreak: true });
|
|
29921
|
+
if (lines.length > MAX_LABEL_LINES) {
|
|
29922
|
+
const kept = lines.slice(0, MAX_LABEL_LINES - 1);
|
|
29923
|
+
const rest = lines.slice(MAX_LABEL_LINES - 1).join(" ");
|
|
29924
|
+
kept.push(truncateText(rest, fontSize, maxWidth));
|
|
29925
|
+
lines = kept;
|
|
29926
|
+
}
|
|
29927
|
+
let textW = 0;
|
|
29928
|
+
for (const ln of lines) {
|
|
29929
|
+
const w = measureText(ln, fontSize);
|
|
29930
|
+
if (w > textW) textW = w;
|
|
29931
|
+
}
|
|
29932
|
+
return {
|
|
29933
|
+
lines,
|
|
29934
|
+
width: textW + 2 * H_PAD,
|
|
29935
|
+
height: lines.length * fontSize * LABEL_LINE_HEIGHT + 2 * V_PAD
|
|
29936
|
+
};
|
|
29937
|
+
}
|
|
29938
|
+
function edgePolylineMidpoint(points) {
|
|
29939
|
+
return pointAtArcFraction(points, 0.5).p;
|
|
29940
|
+
}
|
|
29941
|
+
function pointAtArcFraction(points, t) {
|
|
29942
|
+
if (points.length === 0) return { p: { x: 0, y: 0 }, nx: 0, ny: 1 };
|
|
29943
|
+
if (points.length === 1)
|
|
29944
|
+
return { p: { x: points[0].x, y: points[0].y }, nx: 0, ny: 1 };
|
|
29945
|
+
const segLen = [];
|
|
29946
|
+
let total = 0;
|
|
29947
|
+
for (let k = 1; k < points.length; k++) {
|
|
29948
|
+
const len = Math.hypot(
|
|
29949
|
+
points[k].x - points[k - 1].x,
|
|
29950
|
+
points[k].y - points[k - 1].y
|
|
29951
|
+
);
|
|
29952
|
+
segLen.push(len);
|
|
29953
|
+
total += len;
|
|
29954
|
+
}
|
|
29955
|
+
let want = total * Math.max(0, Math.min(1, t));
|
|
29956
|
+
for (let k = 1; k < points.length; k++) {
|
|
29957
|
+
const len = segLen[k - 1];
|
|
29958
|
+
if (want <= len || k === points.length - 1) {
|
|
29959
|
+
const f = len === 0 ? 0 : Math.min(1, want / len);
|
|
29960
|
+
const ax = points[k - 1].x;
|
|
29961
|
+
const ay = points[k - 1].y;
|
|
29962
|
+
const bx = points[k].x;
|
|
29963
|
+
const by = points[k].y;
|
|
29964
|
+
const dx = bx - ax;
|
|
29965
|
+
const dy = by - ay;
|
|
29966
|
+
const dlen = Math.hypot(dx, dy) || 1;
|
|
29967
|
+
return {
|
|
29968
|
+
p: { x: ax + dx * f, y: ay + dy * f },
|
|
29969
|
+
nx: -dy / dlen,
|
|
29970
|
+
ny: dx / dlen
|
|
29971
|
+
};
|
|
29972
|
+
}
|
|
29973
|
+
want -= len;
|
|
29974
|
+
}
|
|
29975
|
+
const last = points[points.length - 1];
|
|
29976
|
+
return { p: { x: last.x, y: last.y }, nx: 0, ny: 1 };
|
|
29977
|
+
}
|
|
29978
|
+
function rectFromCenter(cx, cy, w, h) {
|
|
29979
|
+
return {
|
|
29980
|
+
minX: cx - w / 2,
|
|
29981
|
+
minY: cy - h / 2,
|
|
29982
|
+
maxX: cx + w / 2,
|
|
29983
|
+
maxY: cy + h / 2
|
|
29984
|
+
};
|
|
29985
|
+
}
|
|
29986
|
+
function overlapsAny(cx, cy, w, h, obstacles, pad2) {
|
|
29987
|
+
const minX = cx - w / 2 - pad2;
|
|
29988
|
+
const minY = cy - h / 2 - pad2;
|
|
29989
|
+
const maxX = cx + w / 2 + pad2;
|
|
29990
|
+
const maxY = cy + h / 2 + pad2;
|
|
29991
|
+
for (const o of obstacles) {
|
|
29992
|
+
if (minX < o.maxX && maxX > o.minX && minY < o.maxY && maxY > o.minY)
|
|
29993
|
+
return true;
|
|
29994
|
+
}
|
|
29995
|
+
return false;
|
|
29996
|
+
}
|
|
29997
|
+
function slideFractions() {
|
|
29998
|
+
const out = [0.5];
|
|
29999
|
+
for (let k = 1; k <= SLIDE_SAMPLES; k++) {
|
|
30000
|
+
const off = k * 0.08;
|
|
30001
|
+
if (0.5 - off >= 0.12) out.push(0.5 - off);
|
|
30002
|
+
if (0.5 + off <= 0.88) out.push(0.5 + off);
|
|
30003
|
+
}
|
|
30004
|
+
return out;
|
|
30005
|
+
}
|
|
30006
|
+
function findClearPosition(w, h, points, obstacles) {
|
|
30007
|
+
const ts = slideFractions();
|
|
30008
|
+
for (const t of ts) {
|
|
30009
|
+
const { p } = pointAtArcFraction(points, t);
|
|
30010
|
+
if (!overlapsAny(p.x, p.y, w, h, obstacles, BOX_CLEAR_PAD)) return p;
|
|
30011
|
+
}
|
|
30012
|
+
for (let mag = PERP_STEP; mag <= PERP_MAX; mag += PERP_STEP) {
|
|
30013
|
+
for (const t of ts) {
|
|
30014
|
+
const { p, nx, ny } = pointAtArcFraction(points, t);
|
|
30015
|
+
for (const sign of [-1, 1]) {
|
|
30016
|
+
const x = p.x + nx * mag * sign;
|
|
30017
|
+
const y = p.y + ny * mag * sign;
|
|
30018
|
+
if (!overlapsAny(x, y, w, h, obstacles, BOX_CLEAR_PAD)) return { x, y };
|
|
30019
|
+
}
|
|
30020
|
+
}
|
|
30021
|
+
}
|
|
30022
|
+
return null;
|
|
30023
|
+
}
|
|
30024
|
+
function resolveLabelOverlaps(boxes) {
|
|
30025
|
+
const MAX_PASSES = 8;
|
|
30026
|
+
const PAD = 4;
|
|
30027
|
+
for (let pass = 0; pass < MAX_PASSES; pass++) {
|
|
30028
|
+
let moved = false;
|
|
30029
|
+
for (let i = 0; i < boxes.length; i++) {
|
|
30030
|
+
for (let j = i + 1; j < boxes.length; j++) {
|
|
30031
|
+
const a = boxes[i];
|
|
30032
|
+
const b = boxes[j];
|
|
30033
|
+
const dx = Math.abs(a.cx - b.cx);
|
|
30034
|
+
const dy = Math.abs(a.cy - b.cy);
|
|
30035
|
+
const overlapX = (a.w + b.w) / 2 + PAD - dx;
|
|
30036
|
+
const overlapY = (a.h + b.h) / 2 + PAD - dy;
|
|
30037
|
+
if (overlapX > 0 && overlapY > 0) {
|
|
30038
|
+
const shift = overlapY / 2 + 1;
|
|
30039
|
+
if (a.cy < b.cy) {
|
|
30040
|
+
a.cy -= shift;
|
|
30041
|
+
b.cy += shift;
|
|
30042
|
+
} else {
|
|
30043
|
+
a.cy += shift;
|
|
30044
|
+
b.cy -= shift;
|
|
30045
|
+
}
|
|
30046
|
+
moved = true;
|
|
30047
|
+
}
|
|
30048
|
+
}
|
|
30049
|
+
}
|
|
30050
|
+
if (!moved) break;
|
|
30051
|
+
}
|
|
30052
|
+
}
|
|
30053
|
+
function placeEdgeLabels(layout, opts) {
|
|
30054
|
+
const fontSize = opts?.fontSize ?? EDGE_LABEL_FONT_SIZE6;
|
|
30055
|
+
const maxWidth = opts?.maxWidth ?? LABEL_MAX_WIDTH;
|
|
30056
|
+
const obstacles = [];
|
|
30057
|
+
for (const n of layout.nodes)
|
|
30058
|
+
obstacles.push(rectFromCenter(n.x, n.y, n.width, n.height));
|
|
30059
|
+
for (const g of layout.groups)
|
|
30060
|
+
if (g.collapsed)
|
|
30061
|
+
obstacles.push(rectFromCenter(g.x, g.y, g.width, g.height));
|
|
30062
|
+
const boxes = [];
|
|
30063
|
+
layout.edges.forEach((e, idx) => {
|
|
30064
|
+
if (!e.label || e.points.length < 2) return;
|
|
30065
|
+
const m = measureEdgeLabel(e.label, fontSize, maxWidth);
|
|
30066
|
+
const mid = edgePolylineMidpoint(e.points);
|
|
30067
|
+
let cy = mid.y;
|
|
30068
|
+
if (e.parallelCount > 1 && e.yOffset !== 0)
|
|
30069
|
+
cy += (e.yOffset < 0 ? -1 : 1) * (m.height / 2);
|
|
30070
|
+
boxes.push({
|
|
30071
|
+
edgeIdx: idx,
|
|
30072
|
+
cx: mid.x,
|
|
30073
|
+
cy,
|
|
30074
|
+
w: m.width,
|
|
30075
|
+
h: m.height,
|
|
30076
|
+
lines: m.lines,
|
|
30077
|
+
resolved: true
|
|
30078
|
+
});
|
|
30079
|
+
});
|
|
30080
|
+
for (const box of boxes) {
|
|
30081
|
+
if (!overlapsAny(box.cx, box.cy, box.w, box.h, obstacles, BOX_CLEAR_PAD))
|
|
30082
|
+
continue;
|
|
30083
|
+
const e = layout.edges[box.edgeIdx];
|
|
30084
|
+
const clear = findClearPosition(box.w, box.h, e.points, obstacles);
|
|
30085
|
+
if (clear) {
|
|
30086
|
+
box.cx = clear.x;
|
|
30087
|
+
box.cy = clear.y;
|
|
30088
|
+
} else {
|
|
30089
|
+
box.resolved = false;
|
|
30090
|
+
}
|
|
30091
|
+
}
|
|
30092
|
+
resolveLabelOverlaps(boxes);
|
|
30093
|
+
for (const box of boxes) {
|
|
30094
|
+
if (overlapsAny(box.cx, box.cy, box.w, box.h, obstacles, BOX_CLEAR_PAD))
|
|
30095
|
+
box.resolved = false;
|
|
30096
|
+
}
|
|
30097
|
+
const boxByIdx = /* @__PURE__ */ new Map();
|
|
30098
|
+
for (const b of boxes) boxByIdx.set(b.edgeIdx, b);
|
|
30099
|
+
const edges = layout.edges.map((e, idx) => {
|
|
30100
|
+
const b = boxByIdx.get(idx);
|
|
30101
|
+
if (!b) return e;
|
|
30102
|
+
return {
|
|
30103
|
+
...e,
|
|
30104
|
+
labelX: b.cx,
|
|
30105
|
+
labelY: b.cy,
|
|
30106
|
+
labelWidth: b.w,
|
|
30107
|
+
labelHeight: b.h,
|
|
30108
|
+
labelLines: b.lines
|
|
30109
|
+
};
|
|
30110
|
+
});
|
|
30111
|
+
return {
|
|
30112
|
+
layout: { ...layout, edges },
|
|
30113
|
+
unresolved: boxes.filter((b) => !b.resolved).map((b) => b.edgeIdx)
|
|
30114
|
+
};
|
|
30115
|
+
}
|
|
30116
|
+
var EDGE_LABEL_FONT_SIZE6, LABEL_MAX_WIDTH, MAX_LABEL_LINES, LABEL_LINE_HEIGHT, H_PAD, V_PAD, BOX_CLEAR_PAD, PERP_STEP, PERP_MAX, SLIDE_SAMPLES;
|
|
30117
|
+
var init_label_placement = __esm({
|
|
30118
|
+
"src/boxes-and-lines/label-placement.ts"() {
|
|
30119
|
+
"use strict";
|
|
30120
|
+
init_text_measure();
|
|
30121
|
+
EDGE_LABEL_FONT_SIZE6 = 11;
|
|
30122
|
+
LABEL_MAX_WIDTH = 160;
|
|
30123
|
+
MAX_LABEL_LINES = 3;
|
|
30124
|
+
LABEL_LINE_HEIGHT = 1.3;
|
|
30125
|
+
H_PAD = 6;
|
|
30126
|
+
V_PAD = 3;
|
|
30127
|
+
BOX_CLEAR_PAD = 4;
|
|
30128
|
+
PERP_STEP = 8;
|
|
30129
|
+
PERP_MAX = 40;
|
|
30130
|
+
SLIDE_SAMPLES = 9;
|
|
30131
|
+
}
|
|
30132
|
+
});
|
|
30133
|
+
|
|
29868
30134
|
// src/boxes-and-lines/layout-layered.ts
|
|
29869
30135
|
function rng(s) {
|
|
29870
30136
|
return () => {
|
|
@@ -31654,6 +31920,7 @@ function edgeLength(layout) {
|
|
|
31654
31920
|
}
|
|
31655
31921
|
async function layoutBoxesAndLinesSearch(parsed, collapseInfo, opts) {
|
|
31656
31922
|
const hideDescriptions = opts?.hideDescriptions ?? false;
|
|
31923
|
+
const reserveEdgeLabels = opts?.reserveEdgeLabels ?? false;
|
|
31657
31924
|
const onProgress = opts?.onProgress;
|
|
31658
31925
|
const tick = onProgress ? () => new Promise((r) => setTimeout(r)) : () => void 0;
|
|
31659
31926
|
const collapsedGroupLabels = /* @__PURE__ */ new Set();
|
|
@@ -31946,8 +32213,14 @@ async function layoutBoxesAndLinesSearch(parsed, collapseInfo, opts) {
|
|
|
31946
32213
|
for (const e of ord(parsed.edges)) {
|
|
31947
32214
|
const s = srcRep(e.source);
|
|
31948
32215
|
const t = tgtRep(e.target);
|
|
31949
|
-
if (s !== t && g.hasNode(s) && g.hasNode(t))
|
|
31950
|
-
|
|
32216
|
+
if (s !== t && g.hasNode(s) && g.hasNode(t)) {
|
|
32217
|
+
let edgeLabel = {};
|
|
32218
|
+
if (reserveEdgeLabels && e.label) {
|
|
32219
|
+
const m = measureEdgeLabel(e.label, EDGE_LABEL_FONT_SIZE6);
|
|
32220
|
+
edgeLabel = { width: m.width, height: m.height, labelpos: "c" };
|
|
32221
|
+
}
|
|
32222
|
+
g.setEdge(s, t, edgeLabel, edgeKey(e));
|
|
32223
|
+
}
|
|
31951
32224
|
}
|
|
31952
32225
|
dagre4.layout(g);
|
|
31953
32226
|
const nodes = parsed.nodes.map((n2) => {
|
|
@@ -32176,6 +32449,7 @@ var init_layout_search = __esm({
|
|
|
32176
32449
|
init_layout5();
|
|
32177
32450
|
init_layout_layered();
|
|
32178
32451
|
init_layout_grouped();
|
|
32452
|
+
init_label_placement();
|
|
32179
32453
|
DEFAULT_LAMBDA = 4;
|
|
32180
32454
|
ESCALATE_THRESHOLD = 4;
|
|
32181
32455
|
ESCALATE_MAX_N = 45;
|
|
@@ -32234,9 +32508,9 @@ function estimateLabelLines(label, nodeWidth = NODE_WIDTH) {
|
|
|
32234
32508
|
current = word;
|
|
32235
32509
|
}
|
|
32236
32510
|
}
|
|
32237
|
-
if (lines <=
|
|
32511
|
+
if (lines <= MAX_LABEL_LINES2) return Math.min(lines, MAX_LABEL_LINES2);
|
|
32238
32512
|
}
|
|
32239
|
-
return
|
|
32513
|
+
return MAX_LABEL_LINES2;
|
|
32240
32514
|
}
|
|
32241
32515
|
function computeNodeSize(node, reserveValueRow) {
|
|
32242
32516
|
if (!node.description || node.description.length === 0) {
|
|
@@ -32244,7 +32518,7 @@ function computeNodeSize(node, reserveValueRow) {
|
|
|
32244
32518
|
}
|
|
32245
32519
|
const w = DESC_NODE_WIDTH;
|
|
32246
32520
|
const labelLines = estimateLabelLines(node.label, w);
|
|
32247
|
-
const labelHeight = labelLines * 13 *
|
|
32521
|
+
const labelHeight = labelLines * 13 * LABEL_LINE_HEIGHT2 + LABEL_PAD;
|
|
32248
32522
|
const maxTextWidth = w - 24;
|
|
32249
32523
|
let totalRenderedLines = 0;
|
|
32250
32524
|
for (const line11 of node.description) {
|
|
@@ -32268,7 +32542,7 @@ function computeNodeSize(node, reserveValueRow) {
|
|
|
32268
32542
|
}
|
|
32269
32543
|
async function layoutBoxesAndLines(parsed, collapseInfo, layoutOptions) {
|
|
32270
32544
|
const { layoutBoxesAndLinesSearch: layoutBoxesAndLinesSearch2 } = await Promise.resolve().then(() => (init_layout_search(), layout_search_exports));
|
|
32271
|
-
const
|
|
32545
|
+
const searchOpts = {
|
|
32272
32546
|
...layoutOptions?.hideDescriptions !== void 0 && {
|
|
32273
32547
|
hideDescriptions: layoutOptions.hideDescriptions
|
|
32274
32548
|
},
|
|
@@ -32278,12 +32552,23 @@ async function layoutBoxesAndLines(parsed, collapseInfo, layoutOptions) {
|
|
|
32278
32552
|
...layoutOptions?.onProgress !== void 0 && {
|
|
32279
32553
|
onProgress: layoutOptions.onProgress
|
|
32280
32554
|
}
|
|
32281
|
-
}
|
|
32282
|
-
|
|
32283
|
-
applyParallelEdgeOffsets(searched),
|
|
32555
|
+
};
|
|
32556
|
+
const searched = await layoutBoxesAndLinesSearch2(
|
|
32284
32557
|
parsed,
|
|
32285
|
-
|
|
32558
|
+
collapseInfo,
|
|
32559
|
+
searchOpts
|
|
32286
32560
|
);
|
|
32561
|
+
let placed = placeEdgeLabels(applyParallelEdgeOffsets(searched));
|
|
32562
|
+
if (placed.unresolved.length > 0) {
|
|
32563
|
+
const relaid = await layoutBoxesAndLinesSearch2(parsed, collapseInfo, {
|
|
32564
|
+
...searchOpts,
|
|
32565
|
+
reserveEdgeLabels: true
|
|
32566
|
+
});
|
|
32567
|
+
const relaidPlaced = placeEdgeLabels(applyParallelEdgeOffsets(relaid));
|
|
32568
|
+
if (relaidPlaced.unresolved.length < placed.unresolved.length)
|
|
32569
|
+
placed = relaidPlaced;
|
|
32570
|
+
}
|
|
32571
|
+
return attachNotes(placed.layout, parsed, layoutOptions?.collapsedNotes);
|
|
32287
32572
|
}
|
|
32288
32573
|
function attachNotes(layout, parsed, collapsedNotes) {
|
|
32289
32574
|
const notesSuppressed = parsed.options?.["no-notes"] === "on";
|
|
@@ -32351,6 +32636,7 @@ function attachNotes(layout, parsed, collapsedNotes) {
|
|
|
32351
32636
|
points: e.points.map((pt) => ({ x: pt.x + shiftX, y: pt.y + shiftY })),
|
|
32352
32637
|
...e.labelX !== void 0 && { labelX: e.labelX + shiftX },
|
|
32353
32638
|
...e.labelY !== void 0 && { labelY: e.labelY + shiftY }
|
|
32639
|
+
// labelWidth/labelHeight/labelLines are shift-invariant — carried via spread.
|
|
32354
32640
|
})) : layout.edges;
|
|
32355
32641
|
const finalGroups = shifted ? layout.groups.map((grp) => ({
|
|
32356
32642
|
...grp,
|
|
@@ -32395,11 +32681,12 @@ function applyParallelEdgeOffsets(layout) {
|
|
|
32395
32681
|
}))
|
|
32396
32682
|
};
|
|
32397
32683
|
}
|
|
32398
|
-
var MARGIN5, MAX_PARALLEL_EDGES, PARALLEL_SPACING, PHI, NODE_HEIGHT, NODE_WIDTH, DESC_NODE_WIDTH, DESC_FONT_SIZE2, DESC_LINE_HEIGHT2, DESC_PADDING, SEPARATOR_GAP4, MAX_DESC_LINES2,
|
|
32684
|
+
var MARGIN5, MAX_PARALLEL_EDGES, PARALLEL_SPACING, PHI, NODE_HEIGHT, NODE_WIDTH, DESC_NODE_WIDTH, DESC_FONT_SIZE2, DESC_LINE_HEIGHT2, DESC_PADDING, SEPARATOR_GAP4, MAX_DESC_LINES2, MAX_LABEL_LINES2, LABEL_LINE_HEIGHT2, LABEL_PAD, VALUE_ROW_FONT, VALUE_ROW_H;
|
|
32399
32685
|
var init_layout5 = __esm({
|
|
32400
32686
|
"src/boxes-and-lines/layout.ts"() {
|
|
32401
32687
|
"use strict";
|
|
32402
32688
|
init_text_measure();
|
|
32689
|
+
init_label_placement();
|
|
32403
32690
|
init_notes();
|
|
32404
32691
|
MARGIN5 = 40;
|
|
32405
32692
|
MAX_PARALLEL_EDGES = 5;
|
|
@@ -32413,8 +32700,8 @@ var init_layout5 = __esm({
|
|
|
32413
32700
|
DESC_PADDING = 8;
|
|
32414
32701
|
SEPARATOR_GAP4 = 4;
|
|
32415
32702
|
MAX_DESC_LINES2 = 6;
|
|
32416
|
-
|
|
32417
|
-
|
|
32703
|
+
MAX_LABEL_LINES2 = 3;
|
|
32704
|
+
LABEL_LINE_HEIGHT2 = 1.3;
|
|
32418
32705
|
LABEL_PAD = 12;
|
|
32419
32706
|
VALUE_ROW_FONT = 11;
|
|
32420
32707
|
VALUE_ROW_H = SEPARATOR_GAP4 + VALUE_ROW_FONT * DESC_LINE_HEIGHT2 + DESC_PADDING;
|
|
@@ -32433,7 +32720,7 @@ function tokenize(text) {
|
|
|
32433
32720
|
return tokens;
|
|
32434
32721
|
}
|
|
32435
32722
|
function tryWrap(tokens, maxWidth, fontSize, maxLines) {
|
|
32436
|
-
const availWidth = maxWidth -
|
|
32723
|
+
const availWidth = maxWidth - H_PAD2;
|
|
32437
32724
|
const lines = [];
|
|
32438
32725
|
let currentLine = "";
|
|
32439
32726
|
for (const token of tokens) {
|
|
@@ -32458,7 +32745,7 @@ function tryWrap(tokens, maxWidth, fontSize, maxLines) {
|
|
|
32458
32745
|
return lines;
|
|
32459
32746
|
}
|
|
32460
32747
|
function truncateLastLine(lines, maxWidth, fontSize) {
|
|
32461
|
-
const availWidth = maxWidth -
|
|
32748
|
+
const availWidth = maxWidth - H_PAD2;
|
|
32462
32749
|
const result = [...lines];
|
|
32463
32750
|
const last = result[result.length - 1];
|
|
32464
32751
|
if (measureText(last, fontSize) > availWidth) {
|
|
@@ -32466,7 +32753,7 @@ function truncateLastLine(lines, maxWidth, fontSize) {
|
|
|
32466
32753
|
}
|
|
32467
32754
|
return result;
|
|
32468
32755
|
}
|
|
32469
|
-
function wrapText(text, maxWidth, baseFontSize, minFontSize, maxLines =
|
|
32756
|
+
function wrapText(text, maxWidth, baseFontSize, minFontSize, maxLines = MAX_LABEL_LINES3) {
|
|
32470
32757
|
if (!text) return { lines: [""], fontSize: baseFontSize };
|
|
32471
32758
|
const tokens = tokenize(text);
|
|
32472
32759
|
for (let fs = baseFontSize; fs >= minFontSize; fs--) {
|
|
@@ -32481,7 +32768,7 @@ function wrapText(text, maxWidth, baseFontSize, minFontSize, maxLines = MAX_LABE
|
|
|
32481
32768
|
if (allLines.length > maxLines) {
|
|
32482
32769
|
const last = truncated[truncated.length - 1];
|
|
32483
32770
|
if (!last.endsWith("\u2026")) {
|
|
32484
|
-
const availWidth = maxWidth -
|
|
32771
|
+
const availWidth = maxWidth - H_PAD2;
|
|
32485
32772
|
if (measureText(last + "\u2026", minFontSize) > availWidth) {
|
|
32486
32773
|
truncated[truncated.length - 1] = truncateText(
|
|
32487
32774
|
last,
|
|
@@ -32508,7 +32795,7 @@ function computeNodeText(label, description, depth, nodeWidth, hideDescriptions)
|
|
|
32508
32795
|
nodeWidth,
|
|
32509
32796
|
baseFontSize,
|
|
32510
32797
|
MIN_FONT_SIZE,
|
|
32511
|
-
|
|
32798
|
+
MAX_LABEL_LINES3
|
|
32512
32799
|
);
|
|
32513
32800
|
const descLines = [];
|
|
32514
32801
|
let descFontSize = DESC_FONT_SIZE3;
|
|
@@ -32536,14 +32823,14 @@ function computeNodeText(label, description, depth, nodeWidth, hideDescriptions)
|
|
|
32536
32823
|
descFontSize
|
|
32537
32824
|
};
|
|
32538
32825
|
}
|
|
32539
|
-
var
|
|
32826
|
+
var H_PAD2, MAX_LABEL_LINES3, MAX_DESC_LINES3, ROOT_FONT_SIZE, MIN_FONT_SIZE, FONT_STEP, DESC_FONT_SIZE3;
|
|
32540
32827
|
var init_text_wrap = __esm({
|
|
32541
32828
|
"src/mindmap/text-wrap.ts"() {
|
|
32542
32829
|
"use strict";
|
|
32543
32830
|
init_description_helpers();
|
|
32544
32831
|
init_text_measure();
|
|
32545
|
-
|
|
32546
|
-
|
|
32832
|
+
H_PAD2 = 16;
|
|
32833
|
+
MAX_LABEL_LINES3 = 3;
|
|
32547
32834
|
MAX_DESC_LINES3 = 2;
|
|
32548
32835
|
ROOT_FONT_SIZE = 17;
|
|
32549
32836
|
MIN_FONT_SIZE = 9;
|
|
@@ -32930,7 +33217,7 @@ function nodeHeightS(node, hideDescriptions, sc) {
|
|
|
32930
33217
|
hideDescriptions
|
|
32931
33218
|
);
|
|
32932
33219
|
const labelLineCount = text.labelLines.length;
|
|
32933
|
-
const labelH = labelLineCount <= 1 ? SINGLE_LABEL_HEIGHT :
|
|
33220
|
+
const labelH = labelLineCount <= 1 ? SINGLE_LABEL_HEIGHT : LABEL_LINE_HEIGHT3 * labelLineCount;
|
|
32934
33221
|
let h = labelH + NODE_V_PAD;
|
|
32935
33222
|
if (text.descLines.length > 0) {
|
|
32936
33223
|
h += DESC_LINE_HEIGHT3 * text.descLines.length + 4;
|
|
@@ -32950,7 +33237,7 @@ function populateDepthCache(roots) {
|
|
|
32950
33237
|
};
|
|
32951
33238
|
walk(roots, 0);
|
|
32952
33239
|
}
|
|
32953
|
-
var ROOT_WIDTH, DEPTH1_WIDTH, LEAF_WIDTH, SINGLE_LABEL_HEIGHT,
|
|
33240
|
+
var ROOT_WIDTH, DEPTH1_WIDTH, LEAF_WIDTH, SINGLE_LABEL_HEIGHT, LABEL_LINE_HEIGHT3, DESC_LINE_HEIGHT3, NODE_V_PAD, H_GAP2, V_GAP2, MARGIN6, MULTI_ROOT_GAP, nodeDepthCache;
|
|
32954
33241
|
var init_layout6 = __esm({
|
|
32955
33242
|
"src/mindmap/layout.ts"() {
|
|
32956
33243
|
"use strict";
|
|
@@ -32961,7 +33248,7 @@ var init_layout6 = __esm({
|
|
|
32961
33248
|
DEPTH1_WIDTH = 150;
|
|
32962
33249
|
LEAF_WIDTH = 120;
|
|
32963
33250
|
SINGLE_LABEL_HEIGHT = 28;
|
|
32964
|
-
|
|
33251
|
+
LABEL_LINE_HEIGHT3 = 18;
|
|
32965
33252
|
DESC_LINE_HEIGHT3 = 14;
|
|
32966
33253
|
NODE_V_PAD = 10;
|
|
32967
33254
|
H_GAP2 = 40;
|
|
@@ -33253,18 +33540,18 @@ function renderMindmap(container, parsed, layout, palette, isDark, onClickItem,
|
|
|
33253
33540
|
descFontSize
|
|
33254
33541
|
} = textLayout;
|
|
33255
33542
|
const labelLineCount = labelLines.length;
|
|
33256
|
-
const labelZoneH = labelLineCount <= 1 ? SINGLE_LABEL_HEIGHT2 :
|
|
33543
|
+
const labelZoneH = labelLineCount <= 1 ? SINGLE_LABEL_HEIGHT2 : LABEL_LINE_HEIGHT4 * labelLineCount;
|
|
33257
33544
|
const labelZoneHeight = showDesc ? labelZoneH : node.height;
|
|
33258
33545
|
const centerX = node.x + node.width / 2;
|
|
33259
33546
|
if (labelLineCount <= 1) {
|
|
33260
33547
|
const labelY = node.y + labelZoneHeight / 2 + fontSize * 0.35;
|
|
33261
33548
|
nodeG.append("text").attr("x", centerX).attr("y", labelY).attr("text-anchor", "middle").attr("font-size", fontSize).attr("font-weight", isRoot ? "bold" : "normal").attr("fill", onFillText).text(labelLines[0]);
|
|
33262
33549
|
} else {
|
|
33263
|
-
const blockH =
|
|
33550
|
+
const blockH = LABEL_LINE_HEIGHT4 * (labelLineCount - 1);
|
|
33264
33551
|
const firstBaselineY = node.y + labelZoneHeight / 2 - blockH / 2 + fontSize * 0.35;
|
|
33265
33552
|
const textEl = nodeG.append("text").attr("x", centerX).attr("text-anchor", "middle").attr("font-size", fontSize).attr("font-weight", isRoot ? "bold" : "normal").attr("fill", onFillText);
|
|
33266
33553
|
for (let i = 0; i < labelLines.length; i++) {
|
|
33267
|
-
textEl.append("tspan").attr("x", centerX).attr("y", firstBaselineY + i *
|
|
33554
|
+
textEl.append("tspan").attr("x", centerX).attr("y", firstBaselineY + i * LABEL_LINE_HEIGHT4).text(labelLines[i]);
|
|
33268
33555
|
}
|
|
33269
33556
|
}
|
|
33270
33557
|
if (labelLines.length > 1 || labelLines[0] !== node.label) {
|
|
@@ -33339,7 +33626,7 @@ function renderMindmapForExport(content, theme, palette) {
|
|
|
33339
33626
|
return extractExportSvg(container, theme);
|
|
33340
33627
|
});
|
|
33341
33628
|
}
|
|
33342
|
-
var DIAGRAM_PADDING7, TITLE_HEIGHT4, SINGLE_LABEL_HEIGHT2,
|
|
33629
|
+
var DIAGRAM_PADDING7, TITLE_HEIGHT4, SINGLE_LABEL_HEIGHT2, LABEL_LINE_HEIGHT4, DESC_LINE_HEIGHT4, NODE_RADIUS, ROOT_STROKE_WIDTH, DEPTH_COLOR_KEYS;
|
|
33343
33630
|
var init_renderer7 = __esm({
|
|
33344
33631
|
"src/mindmap/renderer.ts"() {
|
|
33345
33632
|
"use strict";
|
|
@@ -33361,7 +33648,7 @@ var init_renderer7 = __esm({
|
|
|
33361
33648
|
DIAGRAM_PADDING7 = 20;
|
|
33362
33649
|
TITLE_HEIGHT4 = 30;
|
|
33363
33650
|
SINGLE_LABEL_HEIGHT2 = 28;
|
|
33364
|
-
|
|
33651
|
+
LABEL_LINE_HEIGHT4 = 18;
|
|
33365
33652
|
DESC_LINE_HEIGHT4 = 14;
|
|
33366
33653
|
NODE_RADIUS = 6;
|
|
33367
33654
|
ROOT_STROKE_WIDTH = 2.5;
|
|
@@ -36030,7 +36317,7 @@ function renderC4Context(container, parsed, layout, palette, isDark, onClickItem
|
|
|
36030
36317
|
const labelText = edge.label ?? "";
|
|
36031
36318
|
const techText = edge.technology ? `[${edge.technology}]` : "";
|
|
36032
36319
|
const textW = Math.max(
|
|
36033
|
-
measureText(labelText,
|
|
36320
|
+
measureText(labelText, EDGE_LABEL_FONT_SIZE7),
|
|
36034
36321
|
measureText(techText, TECH_FONT_SIZE)
|
|
36035
36322
|
);
|
|
36036
36323
|
const bgW = textW + 12;
|
|
@@ -36041,7 +36328,7 @@ function renderC4Context(container, parsed, layout, palette, isDark, onClickItem
|
|
|
36041
36328
|
textY = midPt.y - 4;
|
|
36042
36329
|
}
|
|
36043
36330
|
if (labelText) {
|
|
36044
|
-
edgeG.append("text").attr("x", midPt.x).attr("y", textY + 4).attr("text-anchor", "middle").attr("fill", edgeColor3).attr("font-size",
|
|
36331
|
+
edgeG.append("text").attr("x", midPt.x).attr("y", textY + 4).attr("text-anchor", "middle").attr("fill", edgeColor3).attr("font-size", EDGE_LABEL_FONT_SIZE7).attr("class", "c4-edge-label").text(labelText);
|
|
36045
36332
|
}
|
|
36046
36333
|
if (techText) {
|
|
36047
36334
|
edgeG.append("text").attr("x", midPt.x).attr("y", labelText ? textY + 18 : textY + 4).attr("text-anchor", "middle").attr("fill", edgeColor3).attr("font-size", TECH_FONT_SIZE).attr("font-style", "italic").attr("class", "c4-edge-tech").text(techText);
|
|
@@ -36225,7 +36512,7 @@ function renderEdges(contentG, edges, palette, onClickItem, obstacleRects) {
|
|
|
36225
36512
|
const labelText = edge.label ?? "";
|
|
36226
36513
|
const techText = edge.technology ? `[${edge.technology}]` : "";
|
|
36227
36514
|
const textW = Math.max(
|
|
36228
|
-
measureText(labelText,
|
|
36515
|
+
measureText(labelText, EDGE_LABEL_FONT_SIZE7),
|
|
36229
36516
|
measureText(techText, TECH_FONT_SIZE)
|
|
36230
36517
|
);
|
|
36231
36518
|
const bgW = textW + 12;
|
|
@@ -36243,7 +36530,7 @@ function renderEdges(contentG, edges, palette, onClickItem, obstacleRects) {
|
|
|
36243
36530
|
});
|
|
36244
36531
|
}
|
|
36245
36532
|
}
|
|
36246
|
-
|
|
36533
|
+
placeEdgeLabels2(pendingLabels, edges, obstacleRects);
|
|
36247
36534
|
for (const lbl of pendingLabels) {
|
|
36248
36535
|
lbl.edgeG.append("rect").attr("x", lbl.x - lbl.bgW / 2).attr("y", lbl.y - lbl.bgH / 2).attr("width", lbl.bgW).attr("height", lbl.bgH).attr("rx", 3).attr("fill", palette.bg).attr("opacity", 0.9).attr("class", "c4-edge-label-bg");
|
|
36249
36536
|
let textY = lbl.y;
|
|
@@ -36251,7 +36538,7 @@ function renderEdges(contentG, edges, palette, onClickItem, obstacleRects) {
|
|
|
36251
36538
|
textY = lbl.y - 4;
|
|
36252
36539
|
}
|
|
36253
36540
|
if (lbl.labelText) {
|
|
36254
|
-
lbl.edgeG.append("text").attr("x", lbl.x).attr("y", textY + 4).attr("text-anchor", "middle").attr("fill", lbl.edgeColor).attr("font-size",
|
|
36541
|
+
lbl.edgeG.append("text").attr("x", lbl.x).attr("y", textY + 4).attr("text-anchor", "middle").attr("fill", lbl.edgeColor).attr("font-size", EDGE_LABEL_FONT_SIZE7).attr("class", "c4-edge-label").text(lbl.labelText);
|
|
36255
36542
|
}
|
|
36256
36543
|
if (lbl.techText) {
|
|
36257
36544
|
lbl.edgeG.append("text").attr("x", lbl.x).attr("y", lbl.labelText ? textY + 18 : textY + 4).attr("text-anchor", "middle").attr("fill", lbl.edgeColor).attr("font-size", TECH_FONT_SIZE).attr("font-style", "italic").attr("class", "c4-edge-tech").text(lbl.techText);
|
|
@@ -36332,7 +36619,7 @@ function tangentAt(points, t) {
|
|
|
36332
36619
|
}
|
|
36333
36620
|
return { x: 0, y: 1 };
|
|
36334
36621
|
}
|
|
36335
|
-
function
|
|
36622
|
+
function placeEdgeLabels2(labels, edges, obstacleRects) {
|
|
36336
36623
|
if (labels.length === 0) return;
|
|
36337
36624
|
const allPaths = edges.map((e) => e.points);
|
|
36338
36625
|
const placedRects = [];
|
|
@@ -36870,7 +37157,7 @@ function renderC4DeploymentForExport(content, theme, palette) {
|
|
|
36870
37157
|
document.body.removeChild(el);
|
|
36871
37158
|
}
|
|
36872
37159
|
}
|
|
36873
|
-
var DIAGRAM_PADDING8, MAX_SCALE5, TITLE_HEIGHT6, TYPE_FONT_SIZE, NAME_FONT_SIZE2, DESC_FONT_SIZE5, DESC_LINE_HEIGHT6,
|
|
37160
|
+
var DIAGRAM_PADDING8, MAX_SCALE5, TITLE_HEIGHT6, TYPE_FONT_SIZE, NAME_FONT_SIZE2, DESC_FONT_SIZE5, DESC_LINE_HEIGHT6, EDGE_LABEL_FONT_SIZE7, TECH_FONT_SIZE, CARD_H_PAD4, CARD_V_PAD4, TYPE_LABEL_HEIGHT2, DIVIDER_GAP2, NAME_HEIGHT2, 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, lineGenerator4;
|
|
36874
37161
|
var init_renderer9 = __esm({
|
|
36875
37162
|
"src/c4/renderer.ts"() {
|
|
36876
37163
|
"use strict";
|
|
@@ -36893,7 +37180,7 @@ var init_renderer9 = __esm({
|
|
|
36893
37180
|
NAME_FONT_SIZE2 = 14;
|
|
36894
37181
|
DESC_FONT_SIZE5 = 11;
|
|
36895
37182
|
DESC_LINE_HEIGHT6 = 16;
|
|
36896
|
-
|
|
37183
|
+
EDGE_LABEL_FONT_SIZE7 = 11;
|
|
36897
37184
|
TECH_FONT_SIZE = 10;
|
|
36898
37185
|
CARD_H_PAD4 = 20;
|
|
36899
37186
|
CARD_V_PAD4 = 14;
|
|
@@ -37518,7 +37805,7 @@ function renderFlowchart(container, graph, layout, palette, isDark, onClickItem,
|
|
|
37518
37805
|
const sTitleFontSize = ctx.text(TITLE_FONT_SIZE);
|
|
37519
37806
|
const sTitleY = ctx.structural(TITLE_Y);
|
|
37520
37807
|
const sNodeFontSize = ctx.text(NODE_FONT_SIZE2);
|
|
37521
|
-
const sEdgeLabelFontSize = ctx.text(
|
|
37808
|
+
const sEdgeLabelFontSize = ctx.text(EDGE_LABEL_FONT_SIZE8);
|
|
37522
37809
|
const sEdgeStrokeWidth = ctx.structural(EDGE_STROKE_WIDTH);
|
|
37523
37810
|
const sNodeStrokeWidth = ctx.structural(NODE_STROKE_WIDTH);
|
|
37524
37811
|
const sArrowheadW = ctx.structural(ARROWHEAD_W3);
|
|
@@ -37744,7 +38031,7 @@ function renderFlowchartForExport(content, theme, palette) {
|
|
|
37744
38031
|
document.body.removeChild(container);
|
|
37745
38032
|
}
|
|
37746
38033
|
}
|
|
37747
|
-
var DIAGRAM_PADDING9, MAX_SCALE6, NODE_FONT_SIZE2,
|
|
38034
|
+
var DIAGRAM_PADDING9, MAX_SCALE6, NODE_FONT_SIZE2, EDGE_LABEL_FONT_SIZE8, ARROWHEAD_W3, ARROWHEAD_H3, IO_SKEW, SUBROUTINE_INSET, DOC_WAVE_HEIGHT;
|
|
37748
38035
|
var init_flowchart_renderer = __esm({
|
|
37749
38036
|
"src/graph/flowchart-renderer.ts"() {
|
|
37750
38037
|
"use strict";
|
|
@@ -37763,7 +38050,7 @@ var init_flowchart_renderer = __esm({
|
|
|
37763
38050
|
DIAGRAM_PADDING9 = 20;
|
|
37764
38051
|
MAX_SCALE6 = 3;
|
|
37765
38052
|
NODE_FONT_SIZE2 = 13;
|
|
37766
|
-
|
|
38053
|
+
EDGE_LABEL_FONT_SIZE8 = 11;
|
|
37767
38054
|
ARROWHEAD_W3 = 10;
|
|
37768
38055
|
ARROWHEAD_H3 = 7;
|
|
37769
38056
|
IO_SKEW = 15;
|
|
@@ -39198,7 +39485,7 @@ function layoutInfra(computed, expandedNodeIds, collapsedNodes) {
|
|
|
39198
39485
|
const midIdx = Math.floor(edge.points.length / 2);
|
|
39199
39486
|
const midPt = edge.points[midIdx];
|
|
39200
39487
|
if (midPt) {
|
|
39201
|
-
const halfWidth = (measureText(edge.label,
|
|
39488
|
+
const halfWidth = (measureText(edge.label, EDGE_LABEL_FONT_SIZE9) + 8) / 2;
|
|
39202
39489
|
if (midPt.x - halfWidth < minX) minX = midPt.x - halfWidth;
|
|
39203
39490
|
if (midPt.x + halfWidth > maxX) maxX = midPt.x + halfWidth;
|
|
39204
39491
|
}
|
|
@@ -39232,7 +39519,7 @@ function layoutInfra(computed, expandedNodeIds, collapsedNodes) {
|
|
|
39232
39519
|
height: totalHeight
|
|
39233
39520
|
};
|
|
39234
39521
|
}
|
|
39235
|
-
var MIN_NODE_WIDTH2, NODE_HEADER_HEIGHT, META_LINE_HEIGHT5, NODE_SEPARATOR_GAP, NODE_PAD_BOTTOM, ROLE_DOT_ROW, COLLAPSE_BAR_HEIGHT3, NODE_FONT_SIZE3, META_FONT_SIZE5,
|
|
39522
|
+
var MIN_NODE_WIDTH2, NODE_HEADER_HEIGHT, META_LINE_HEIGHT5, NODE_SEPARATOR_GAP, NODE_PAD_BOTTOM, ROLE_DOT_ROW, COLLAPSE_BAR_HEIGHT3, NODE_FONT_SIZE3, META_FONT_SIZE5, EDGE_LABEL_FONT_SIZE9, PADDING_X3, GROUP_PADDING2, GROUP_HEADER_HEIGHT, EDGE_MARGIN, DISPLAY_KEYS, DISPLAY_NAMES, GROUP_GAP2;
|
|
39236
39523
|
var init_layout10 = __esm({
|
|
39237
39524
|
"src/infra/layout.ts"() {
|
|
39238
39525
|
"use strict";
|
|
@@ -39246,7 +39533,7 @@ var init_layout10 = __esm({
|
|
|
39246
39533
|
COLLAPSE_BAR_HEIGHT3 = 6;
|
|
39247
39534
|
NODE_FONT_SIZE3 = 13;
|
|
39248
39535
|
META_FONT_SIZE5 = 10;
|
|
39249
|
-
|
|
39536
|
+
EDGE_LABEL_FONT_SIZE9 = 11;
|
|
39250
39537
|
PADDING_X3 = 24;
|
|
39251
39538
|
GROUP_PADDING2 = 20;
|
|
39252
39539
|
GROUP_HEADER_HEIGHT = 24;
|
|
@@ -39353,7 +39640,7 @@ function buildScaledConstants(ctx) {
|
|
|
39353
39640
|
sNodeFontSize: ctx.text(NODE_FONT_SIZE4),
|
|
39354
39641
|
sMetaFontSize: ctx.text(META_FONT_SIZE6),
|
|
39355
39642
|
sMetaLineHeight: ctx.structural(META_LINE_HEIGHT6),
|
|
39356
|
-
sEdgeLabelFontSize: ctx.text(
|
|
39643
|
+
sEdgeLabelFontSize: ctx.text(EDGE_LABEL_FONT_SIZE10),
|
|
39357
39644
|
sGroupLabelFontSize: ctx.text(GROUP_LABEL_FONT_SIZE2),
|
|
39358
39645
|
sNodeBorderRadius: ctx.structural(NODE_BORDER_RADIUS),
|
|
39359
39646
|
sEdgeStrokeWidth: ctx.structural(EDGE_STROKE_WIDTH),
|
|
@@ -40082,7 +40369,7 @@ function renderEdgeLabels(svg, edges, nodes, groups, palette, _isDark, animate,
|
|
|
40082
40369
|
if (!midPt) continue;
|
|
40083
40370
|
const labelText = edge.label;
|
|
40084
40371
|
const g = svg.append("g").attr("class", animate ? "infra-edge-label" : "");
|
|
40085
|
-
const textWidth = measureText(labelText,
|
|
40372
|
+
const textWidth = measureText(labelText, EDGE_LABEL_FONT_SIZE10) + 8;
|
|
40086
40373
|
g.append("rect").attr("x", midPt.x - textWidth / 2).attr("y", midPt.y - 8).attr("width", textWidth).attr("height", 16).attr("rx", 3).attr("fill", palette.bg).attr("opacity", 0.9);
|
|
40087
40374
|
g.append("text").attr("x", midPt.x).attr("y", midPt.y + 4).attr("text-anchor", "middle").attr("font-family", FONT_FAMILY).attr("font-size", sc.sEdgeLabelFontSize).attr("fill", palette.textMuted).text(labelText);
|
|
40088
40375
|
if (animate) {
|
|
@@ -40692,7 +40979,7 @@ function parseAndLayoutInfra(content) {
|
|
|
40692
40979
|
const layout = layoutInfra(computed);
|
|
40693
40980
|
return { parsed, computed, layout };
|
|
40694
40981
|
}
|
|
40695
|
-
var NODE_FONT_SIZE4, META_FONT_SIZE6, META_LINE_HEIGHT6,
|
|
40982
|
+
var NODE_FONT_SIZE4, META_FONT_SIZE6, META_LINE_HEIGHT6, EDGE_LABEL_FONT_SIZE10, GROUP_LABEL_FONT_SIZE2, NODE_BORDER_RADIUS, OVERLOAD_STROKE_WIDTH, ROLE_DOT_RADIUS, NODE_HEADER_HEIGHT2, NODE_SEPARATOR_GAP2, NODE_PAD_BOTTOM2, 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_DROP_DISTANCE, REJECT_DURATION_MIN, REJECT_DURATION_MAX, REJECT_COUNT_MIN, REJECT_COUNT_MAX, PROP_DISPLAY, DESC_MAX_CHARS, DESC_MAX_WIDTH, RPS_FORMAT_KEYS, MS_FORMAT_KEYS, PCT_FORMAT_KEYS;
|
|
40696
40983
|
var init_renderer10 = __esm({
|
|
40697
40984
|
"src/infra/renderer.ts"() {
|
|
40698
40985
|
"use strict";
|
|
@@ -40716,7 +41003,7 @@ var init_renderer10 = __esm({
|
|
|
40716
41003
|
NODE_FONT_SIZE4 = 13;
|
|
40717
41004
|
META_FONT_SIZE6 = 10;
|
|
40718
41005
|
META_LINE_HEIGHT6 = 14;
|
|
40719
|
-
|
|
41006
|
+
EDGE_LABEL_FONT_SIZE10 = 11;
|
|
40720
41007
|
GROUP_LABEL_FONT_SIZE2 = 14;
|
|
40721
41008
|
NODE_BORDER_RADIUS = 8;
|
|
40722
41009
|
OVERLOAD_STROKE_WIDTH = 3;
|
|
@@ -47108,7 +47395,7 @@ function renderState(container, graph, layout, palette, isDark, onClickItem, exp
|
|
|
47108
47395
|
const sTitleFontSize = ctx.text(TITLE_FONT_SIZE);
|
|
47109
47396
|
const sTitleY = ctx.structural(TITLE_Y);
|
|
47110
47397
|
const sNodeFontSize = ctx.text(NODE_FONT_SIZE6);
|
|
47111
|
-
const sEdgeLabelFontSize = ctx.text(
|
|
47398
|
+
const sEdgeLabelFontSize = ctx.text(EDGE_LABEL_FONT_SIZE11);
|
|
47112
47399
|
const sGroupLabelFontSize = ctx.text(GROUP_LABEL_FONT_SIZE3);
|
|
47113
47400
|
const sEdgeStrokeWidth = ctx.structural(EDGE_STROKE_WIDTH);
|
|
47114
47401
|
const sNodeStrokeWidth = ctx.structural(NODE_STROKE_WIDTH);
|
|
@@ -47388,7 +47675,7 @@ function renderStateForExport(content, theme, palette) {
|
|
|
47388
47675
|
document.body.removeChild(container);
|
|
47389
47676
|
}
|
|
47390
47677
|
}
|
|
47391
|
-
var DIAGRAM_PADDING12, MAX_SCALE7, NODE_FONT_SIZE6,
|
|
47678
|
+
var DIAGRAM_PADDING12, MAX_SCALE7, NODE_FONT_SIZE6, EDGE_LABEL_FONT_SIZE11, GROUP_LABEL_FONT_SIZE3, ARROWHEAD_W5, ARROWHEAD_H5, PSEUDOSTATE_RADIUS, STATE_CORNER_RADIUS, GROUP_EXTRA_PADDING;
|
|
47392
47679
|
var init_state_renderer = __esm({
|
|
47393
47680
|
"src/graph/state-renderer.ts"() {
|
|
47394
47681
|
"use strict";
|
|
@@ -47407,7 +47694,7 @@ var init_state_renderer = __esm({
|
|
|
47407
47694
|
DIAGRAM_PADDING12 = 20;
|
|
47408
47695
|
MAX_SCALE7 = 3;
|
|
47409
47696
|
NODE_FONT_SIZE6 = 13;
|
|
47410
|
-
|
|
47697
|
+
EDGE_LABEL_FONT_SIZE11 = 11;
|
|
47411
47698
|
GROUP_LABEL_FONT_SIZE3 = 11;
|
|
47412
47699
|
ARROWHEAD_W5 = 10;
|
|
47413
47700
|
ARROWHEAD_H5 = 7;
|
|
@@ -50449,10 +50736,10 @@ function renderedDescNodeHeight(numLines, scale) {
|
|
|
50449
50736
|
return headerH + textBlockH + bottomPad;
|
|
50450
50737
|
}
|
|
50451
50738
|
function wrapEdgeLabelText(label, description, maxWidth = EDGE_LABEL_MAX_WIDTH) {
|
|
50452
|
-
const labelLines = label ? wrapTextToWidth(label,
|
|
50739
|
+
const labelLines = label ? wrapTextToWidth(label, EDGE_LABEL_FONT_SIZE12, maxWidth) : [];
|
|
50453
50740
|
const descLines = [];
|
|
50454
50741
|
for (const d of description) {
|
|
50455
|
-
descLines.push(...wrapTextToWidth(d,
|
|
50742
|
+
descLines.push(...wrapTextToWidth(d, EDGE_LABEL_FONT_SIZE12, maxWidth));
|
|
50456
50743
|
}
|
|
50457
50744
|
return { labelLines, descLines };
|
|
50458
50745
|
}
|
|
@@ -50590,9 +50877,9 @@ function computeEdgePaths(layoutNodes, parsed, cx, cy, radius, isClockwise) {
|
|
|
50590
50877
|
const lineCount = labelLines.length + descLines.length;
|
|
50591
50878
|
let labelPxW = 0;
|
|
50592
50879
|
for (const l of labelLines)
|
|
50593
|
-
labelPxW = Math.max(labelPxW, measureText(l,
|
|
50880
|
+
labelPxW = Math.max(labelPxW, measureText(l, EDGE_LABEL_FONT_SIZE12));
|
|
50594
50881
|
for (const l of descLines)
|
|
50595
|
-
labelPxW = Math.max(labelPxW, measureText(l,
|
|
50882
|
+
labelPxW = Math.max(labelPxW, measureText(l, EDGE_LABEL_FONT_SIZE12));
|
|
50596
50883
|
const { labelX, labelY, labelAngle } = computeEdgeLabelPosition(
|
|
50597
50884
|
midAngle,
|
|
50598
50885
|
radius,
|
|
@@ -50694,9 +50981,9 @@ function fitToCanvas(nodes, edges, parsed, _cx, _cy, radius, width, height, _isC
|
|
|
50694
50981
|
);
|
|
50695
50982
|
let textWidth = 0;
|
|
50696
50983
|
for (const l of labelLines)
|
|
50697
|
-
textWidth = Math.max(textWidth, measureText(l,
|
|
50984
|
+
textWidth = Math.max(textWidth, measureText(l, EDGE_LABEL_FONT_SIZE12));
|
|
50698
50985
|
for (const l of descLines)
|
|
50699
|
-
textWidth = Math.max(textWidth, measureText(l,
|
|
50986
|
+
textWidth = Math.max(textWidth, measureText(l, EDGE_LABEL_FONT_SIZE12));
|
|
50700
50987
|
if (textWidth === 0) continue;
|
|
50701
50988
|
const normAngle = (le.labelAngle % (2 * Math.PI) + 2 * Math.PI) % (2 * Math.PI);
|
|
50702
50989
|
const isRight = normAngle < Math.PI * 0.4 || normAngle > Math.PI * 1.6;
|
|
@@ -50770,7 +51057,7 @@ function buildEdgeArc(src, tgt, cx, cy, radius, isClockwise, arrowLength = 0) {
|
|
|
50770
51057
|
const midAngle = srcExitAngle + dir * visibleSweep / 2;
|
|
50771
51058
|
return { path, midAngle };
|
|
50772
51059
|
}
|
|
50773
|
-
var MIN_ARC_ANGLE, LABEL_FONT_SIZE4, CIRCLE_LABEL_FONT_SIZE, DESC_FONT_SIZE6,
|
|
51060
|
+
var MIN_ARC_ANGLE, LABEL_FONT_SIZE4, CIRCLE_LABEL_FONT_SIZE, DESC_FONT_SIZE6, EDGE_LABEL_FONT_SIZE12, MIN_NODE_WIDTH4, MAX_NODE_WIDTH3, DESC_MIN_WIDTH, DESC_WIDTH_STEP, DESC_TARGET_RATIO, PLAIN_NODE_HEIGHT, HEADER_HEIGHT4, DESC_LINE_HEIGHT7, DESC_PAD_Y, NODE_PAD_X, MIN_CIRCLE_RADIUS, CIRCLE_PAD, RENDERER_DESC_FONT, RENDERER_DESC_FONT_MIN, RENDERER_DESC_LINE_H, RENDERER_DESC_LINE_H_MIN, EDGE_LABEL_MAX_WIDTH;
|
|
50774
51061
|
var init_layout14 = __esm({
|
|
50775
51062
|
"src/cycle/layout.ts"() {
|
|
50776
51063
|
"use strict";
|
|
@@ -50781,7 +51068,7 @@ var init_layout14 = __esm({
|
|
|
50781
51068
|
LABEL_FONT_SIZE4 = 13;
|
|
50782
51069
|
CIRCLE_LABEL_FONT_SIZE = 16;
|
|
50783
51070
|
DESC_FONT_SIZE6 = 11;
|
|
50784
|
-
|
|
51071
|
+
EDGE_LABEL_FONT_SIZE12 = 11;
|
|
50785
51072
|
MIN_NODE_WIDTH4 = 70;
|
|
50786
51073
|
MAX_NODE_WIDTH3 = 260;
|
|
50787
51074
|
DESC_MIN_WIDTH = 140;
|
|
@@ -50927,7 +51214,7 @@ function renderCycle(container, parsed, palette, isDark, onClickItem, exportDims
|
|
|
50927
51214
|
const scaledNodeFont = Math.max(6, Math.round(NODE_FONT_SIZE7 * layout.scale));
|
|
50928
51215
|
const scaledEdgeLabelFont = Math.max(
|
|
50929
51216
|
6,
|
|
50930
|
-
Math.round(
|
|
51217
|
+
Math.round(EDGE_LABEL_FONT_SIZE13 * layout.scale)
|
|
50931
51218
|
);
|
|
50932
51219
|
const CIRCLE_LABEL_FONT_SIZE2 = 16;
|
|
50933
51220
|
const scaledCircleLabelFont = Math.max(
|
|
@@ -51090,7 +51377,7 @@ function ensureArrowMarker(defs, color, strokeWidth) {
|
|
|
51090
51377
|
const mh = Math.max(1.5, mw * 0.5);
|
|
51091
51378
|
defs.append("marker").attr("id", id).attr("viewBox", `0 0 ${mw} ${mh}`).attr("refX", mw * 0.1).attr("refY", mh / 2).attr("markerWidth", mw).attr("markerHeight", mh).attr("orient", "auto").append("polygon").attr("points", `0,0 ${mw},${mh / 2} 0,${mh}`).attr("fill", color);
|
|
51092
51379
|
}
|
|
51093
|
-
var NODE_FONT_SIZE7, DESC_FONT_SIZE7,
|
|
51380
|
+
var NODE_FONT_SIZE7, DESC_FONT_SIZE7, EDGE_LABEL_FONT_SIZE13, DESC_LINE_HEIGHT8, TITLE_AREA_HEIGHT;
|
|
51094
51381
|
var init_renderer15 = __esm({
|
|
51095
51382
|
"src/cycle/renderer.ts"() {
|
|
51096
51383
|
"use strict";
|
|
@@ -51107,7 +51394,7 @@ var init_renderer15 = __esm({
|
|
|
51107
51394
|
init_text_measure();
|
|
51108
51395
|
NODE_FONT_SIZE7 = 13;
|
|
51109
51396
|
DESC_FONT_SIZE7 = 11;
|
|
51110
|
-
|
|
51397
|
+
EDGE_LABEL_FONT_SIZE13 = 11;
|
|
51111
51398
|
DESC_LINE_HEIGHT8 = 15;
|
|
51112
51399
|
TITLE_AREA_HEIGHT = 50;
|
|
51113
51400
|
}
|
|
@@ -51505,7 +51792,7 @@ function resolveMap(parsed, data) {
|
|
|
51505
51792
|
const hint = suggest(r.name, allNames);
|
|
51506
51793
|
err(
|
|
51507
51794
|
r.lineNumber,
|
|
51508
|
-
`Unknown
|
|
51795
|
+
`Unknown region "${r.name}" \u2014 not a known country or US state.${hint ? " " + hint : ""} Search the exact token with \`dgmo map-search "${r.name}"\` (or the lookup_map_location tool), use an ISO code (e.g. FR, US-CA), or coordinates.`,
|
|
51509
51796
|
"E_MAP_UNKNOWN_SUBDIVISION"
|
|
51510
51797
|
);
|
|
51511
51798
|
continue;
|
|
@@ -51585,7 +51872,7 @@ function resolveMap(parsed, data) {
|
|
|
51585
51872
|
const hint = suggest(name, cityNames);
|
|
51586
51873
|
err(
|
|
51587
51874
|
line11,
|
|
51588
|
-
`Unknown place "${name}"
|
|
51875
|
+
`Unknown place "${name}" \u2014 not in the gazetteer.${hint ? " " + hint : ""} Search the exact token with \`dgmo map-search "${name}"\` (or the lookup_map_location tool), or use coordinates \`poi <lat> <lon>\`.`,
|
|
51589
51876
|
"E_MAP_UNKNOWN_PLACE"
|
|
51590
51877
|
);
|
|
51591
51878
|
return { kind: "miss" };
|
|
@@ -52127,6 +52414,21 @@ function mapLegendBand(legend, opts) {
|
|
|
52127
52414
|
if (height <= 0) return 0;
|
|
52128
52415
|
return mapLegendTop(opts.hasTitle, opts.hasSubtitle) + height + LEGEND_BOTTOM_GAP2;
|
|
52129
52416
|
}
|
|
52417
|
+
function mapLegendBox(legend, opts) {
|
|
52418
|
+
if (!legend) return null;
|
|
52419
|
+
const groups = mapLegendGroups(legend);
|
|
52420
|
+
if (groups.length === 0) return null;
|
|
52421
|
+
const config = mapLegendConfig(groups, opts.mode);
|
|
52422
|
+
const state = { activeGroup: legend.activeGroup };
|
|
52423
|
+
const { width, height } = computeLegendLayout(config, state, opts.width);
|
|
52424
|
+
if (height <= 0 || width <= 0) return null;
|
|
52425
|
+
return {
|
|
52426
|
+
x: (opts.width - width) / 2,
|
|
52427
|
+
y: mapLegendTop(opts.hasTitle, opts.hasSubtitle),
|
|
52428
|
+
width,
|
|
52429
|
+
height
|
|
52430
|
+
};
|
|
52431
|
+
}
|
|
52130
52432
|
var LEGEND_TOP_GAP2, LEGEND_BOTTOM_GAP2;
|
|
52131
52433
|
var init_legend_band = __esm({
|
|
52132
52434
|
"src/map/legend-band.ts"() {
|
|
@@ -52251,6 +52553,8 @@ function placeContextLabels(args) {
|
|
|
52251
52553
|
waterBodies,
|
|
52252
52554
|
countries,
|
|
52253
52555
|
palette,
|
|
52556
|
+
countryTone,
|
|
52557
|
+
waterTone,
|
|
52254
52558
|
project,
|
|
52255
52559
|
collides,
|
|
52256
52560
|
contentPoints,
|
|
@@ -52260,8 +52564,8 @@ function placeContextLabels(args) {
|
|
|
52260
52564
|
const band = tierBand(Math.max(dLonSpan, dLatSpan));
|
|
52261
52565
|
const budget = labelBudget(width, height, band);
|
|
52262
52566
|
if (budget <= 0) return [];
|
|
52263
|
-
const waterColor = mix(palette.colors.blue, palette.textMuted, 50);
|
|
52264
|
-
const countryColor = palette.textMuted;
|
|
52567
|
+
const waterColor = waterTone ?? mix(palette.colors.blue, palette.textMuted, 50);
|
|
52568
|
+
const countryColor = countryTone ?? palette.textMuted;
|
|
52265
52569
|
const haloColor = palette.bg;
|
|
52266
52570
|
const candidates = [];
|
|
52267
52571
|
const center = [width / 2, height / 2];
|
|
@@ -52350,8 +52654,7 @@ function placeContextLabels(args) {
|
|
|
52350
52654
|
)
|
|
52351
52655
|
);
|
|
52352
52656
|
const fontSize = Math.round(FONT + t * (COUNTRY_FONT_MAX - FONT));
|
|
52353
|
-
const
|
|
52354
|
-
const color = fade > 0 ? mix(countryColor, palette.bg, 100 - fade) : countryColor;
|
|
52657
|
+
const color = countryColor;
|
|
52355
52658
|
const text = c.name;
|
|
52356
52659
|
const tw = labelWidth(text, 0, fontSize);
|
|
52357
52660
|
if (tw > w || fontSize + 2 * PADY > h) continue;
|
|
@@ -52445,7 +52748,7 @@ function placeContextLabels(args) {
|
|
|
52445
52748
|
}
|
|
52446
52749
|
return placed;
|
|
52447
52750
|
}
|
|
52448
|
-
var FONT, LINE_HEIGHT, PADX, PADY, WATER_LETTER_SPACING, CONTEXT_PAD, EDGE_CLAMP_MARGIN, EDGE_CLAMP_OVERSHOOT, COUNTRY_FONT_MAX, COUNTRY_SIZE_FRAC_MIN, COUNTRY_SIZE_FRAC_MAX,
|
|
52751
|
+
var FONT, LINE_HEIGHT, PADX, PADY, WATER_LETTER_SPACING, CONTEXT_PAD, EDGE_CLAMP_MARGIN, EDGE_CLAMP_OVERSHOOT, COUNTRY_FONT_MAX, COUNTRY_SIZE_FRAC_MIN, COUNTRY_SIZE_FRAC_MAX, MAX_COUNTRY_POSITIONS, COUNTRY_POS_GRID, COUNTRY_POS_TOPN_MARGIN, KIND_ORDER;
|
|
52449
52752
|
var init_context_labels = __esm({
|
|
52450
52753
|
"src/map/context-labels.ts"() {
|
|
52451
52754
|
"use strict";
|
|
@@ -52462,7 +52765,6 @@ var init_context_labels = __esm({
|
|
|
52462
52765
|
COUNTRY_FONT_MAX = 22;
|
|
52463
52766
|
COUNTRY_SIZE_FRAC_MIN = 0.06;
|
|
52464
52767
|
COUNTRY_SIZE_FRAC_MAX = 0.32;
|
|
52465
|
-
COUNTRY_FADE_MAX = 45;
|
|
52466
52768
|
MAX_COUNTRY_POSITIONS = 4;
|
|
52467
52769
|
COUNTRY_POS_GRID = 5;
|
|
52468
52770
|
COUNTRY_POS_TOPN_MARGIN = 3;
|
|
@@ -52600,36 +52902,23 @@ function countryLabelPositions(args) {
|
|
|
52600
52902
|
return n;
|
|
52601
52903
|
};
|
|
52602
52904
|
const dist2ToCentre = (c) => (c.sx - cx) ** 2 + (c.sy - cy) ** 2;
|
|
52603
|
-
const
|
|
52604
|
-
|
|
52605
|
-
|
|
52606
|
-
|
|
52607
|
-
|
|
52608
|
-
|
|
52609
|
-
|
|
52610
|
-
let bestIdx = 0;
|
|
52611
|
-
let bestMin = -1;
|
|
52612
|
-
for (let k = 0; k < pool.length; k++) {
|
|
52613
|
-
const c = pool[k];
|
|
52614
|
-
let minD = Infinity;
|
|
52615
|
-
for (const o of ordered) {
|
|
52616
|
-
const d = (c.sx - o.sx) ** 2 + (c.sy - o.sy) ** 2;
|
|
52617
|
-
if (d < minD) minD = d;
|
|
52618
|
-
}
|
|
52619
|
-
if (minD > bestMin) {
|
|
52620
|
-
bestMin = minD;
|
|
52621
|
-
bestIdx = k;
|
|
52622
|
-
}
|
|
52905
|
+
const centreLon = kept.reduce((s, c) => s + c.lon, 0) / kept.length;
|
|
52906
|
+
const centreLat = kept.reduce((s, c) => s + c.lat, 0) / kept.length;
|
|
52907
|
+
const centreScreen = project(centreLon, centreLat);
|
|
52908
|
+
const lead = pointInGeometry(geometry, centreLon, centreLat) && centreScreen && Number.isFinite(centreScreen[0]) && Number.isFinite(centreScreen[1]) && centreScreen[0] >= 0 && centreScreen[0] <= width && centreScreen[1] >= 0 && centreScreen[1] <= height ? [
|
|
52909
|
+
{
|
|
52910
|
+
lonLat: [centreLon, centreLat],
|
|
52911
|
+
screen: [centreScreen[0], centreScreen[1]]
|
|
52623
52912
|
}
|
|
52624
|
-
|
|
52625
|
-
|
|
52626
|
-
|
|
52913
|
+
] : [];
|
|
52914
|
+
const grid = [...kept].sort(
|
|
52915
|
+
(a, b) => interiorness(b) - interiorness(a) || dist2ToCentre(a) - dist2ToCentre(b)
|
|
52916
|
+
).map((c) => ({
|
|
52627
52917
|
lonLat: [c.lon, c.lat],
|
|
52628
52918
|
screen: [c.sx, c.sy]
|
|
52629
52919
|
}));
|
|
52630
52920
|
const curatedPos = curated ? mkCurated(curated, project) : [];
|
|
52631
|
-
|
|
52632
|
-
return out;
|
|
52921
|
+
return [...curatedPos, ...lead, ...grid].slice(0, MAX_COUNTRY_POSITIONS);
|
|
52633
52922
|
}
|
|
52634
52923
|
function mkCurated(curated, project) {
|
|
52635
52924
|
if (!curated) return [];
|
|
@@ -52895,6 +53184,25 @@ function layoutMap(resolvedIn, data, size, opts) {
|
|
|
52895
53184
|
palette.bg,
|
|
52896
53185
|
mutedBasemap ? isDark ? MUTED_FOREIGN_DARK : MUTED_FOREIGN_LIGHT : isDark ? FOREIGN_TINT_DARK : FOREIGN_TINT_LIGHT
|
|
52897
53186
|
);
|
|
53187
|
+
const contrastFloorTone = (tone, ...substrates) => {
|
|
53188
|
+
const clears = (t) => substrates.every((s) => contrastRatio(t, s) >= REGION_LABEL_HALO_RATIO);
|
|
53189
|
+
if (clears(tone)) return tone;
|
|
53190
|
+
for (let s = 10; s <= 100; s += 10) {
|
|
53191
|
+
const t = mix(palette.text, tone, s);
|
|
53192
|
+
if (clears(t)) return t;
|
|
53193
|
+
}
|
|
53194
|
+
return palette.text;
|
|
53195
|
+
};
|
|
53196
|
+
const backdropLandTone = contrastFloorTone(
|
|
53197
|
+
palette.textMuted,
|
|
53198
|
+
neutralFill,
|
|
53199
|
+
water
|
|
53200
|
+
);
|
|
53201
|
+
const backdropWaterTone = contrastFloorTone(
|
|
53202
|
+
mix(palette.colors.blue, palette.textMuted, 50),
|
|
53203
|
+
water,
|
|
53204
|
+
neutralFill
|
|
53205
|
+
);
|
|
52898
53206
|
const hasDirectColor = resolved.regions.some((r) => r.color !== void 0);
|
|
52899
53207
|
const colorizeActive = resolved.directives.noColorize !== true && !hasRamp && !hasDirectColor && fillGroupNames.size === 0;
|
|
52900
53208
|
const colorByIso = /* @__PURE__ */ new Map();
|
|
@@ -53009,6 +53317,33 @@ function layoutMap(resolvedIn, data, size, opts) {
|
|
|
53009
53317
|
hasSubtitle: Boolean(resolved.subtitle)
|
|
53010
53318
|
});
|
|
53011
53319
|
if (legendBand > topPad) topPad = legendBand;
|
|
53320
|
+
const topReserved = [];
|
|
53321
|
+
if (shownTitle) {
|
|
53322
|
+
const lines = resolved.subtitle ? 2 : 1;
|
|
53323
|
+
const tw = Math.max(
|
|
53324
|
+
measureLegendText(shownTitle, TITLE_FONT_SIZE),
|
|
53325
|
+
resolved.subtitle ? measureLegendText(resolved.subtitle, TITLE_FONT_SIZE) : 0
|
|
53326
|
+
) + 2 * TITLE_FONT_SIZE;
|
|
53327
|
+
topReserved.push({
|
|
53328
|
+
x: width / 2 - tw / 2,
|
|
53329
|
+
y: TITLE_Y - TITLE_FONT_SIZE,
|
|
53330
|
+
w: tw,
|
|
53331
|
+
h: TITLE_FONT_SIZE * (lines + 0.5)
|
|
53332
|
+
});
|
|
53333
|
+
}
|
|
53334
|
+
const legendBox = mapLegendBox(legend, {
|
|
53335
|
+
width,
|
|
53336
|
+
mode: opts.legendMode ?? "preview",
|
|
53337
|
+
hasTitle: Boolean(shownTitle),
|
|
53338
|
+
hasSubtitle: Boolean(resolved.subtitle)
|
|
53339
|
+
});
|
|
53340
|
+
if (legendBox)
|
|
53341
|
+
topReserved.push({
|
|
53342
|
+
x: legendBox.x,
|
|
53343
|
+
y: legendBox.y,
|
|
53344
|
+
w: legendBox.width,
|
|
53345
|
+
h: legendBox.height
|
|
53346
|
+
});
|
|
53012
53347
|
const reserve = opts._calloutReserve;
|
|
53013
53348
|
const fitLeft = FIT_PAD + (reserve?.left ?? 0);
|
|
53014
53349
|
const fitRight = width - FIT_PAD - (reserve?.right ?? 0);
|
|
@@ -53738,6 +54073,19 @@ function layoutMap(resolvedIn, data, size, opts) {
|
|
|
53738
54073
|
const by = b.cy - (b.cy - py) / tb * trimB;
|
|
53739
54074
|
return `M${ax},${ay}Q${px},${py} ${bx},${by}`;
|
|
53740
54075
|
};
|
|
54076
|
+
const legLabelPoint = (a, b, curved, offset) => {
|
|
54077
|
+
const mx = (a.cx + b.cx) / 2;
|
|
54078
|
+
const my = (a.cy + b.cy) / 2;
|
|
54079
|
+
if (!curved && offset === 0) return { x: mx, y: my - 4 };
|
|
54080
|
+
const dx = b.cx - a.cx;
|
|
54081
|
+
const dy = b.cy - a.cy;
|
|
54082
|
+
const len = Math.hypot(dx, dy) || 1;
|
|
54083
|
+
const nx = -dy / len;
|
|
54084
|
+
const ny = dx / len;
|
|
54085
|
+
const bow = offset !== 0 ? offset : len * ARC_CURVE_FRAC;
|
|
54086
|
+
const off = bow * 0.5 + Math.sign(bow || 1) * 8;
|
|
54087
|
+
return { x: mx + nx * off, y: my + ny * off };
|
|
54088
|
+
};
|
|
53741
54089
|
const routeLegVals = resolved.routes.flatMap((rt) => rt.legs).map((l) => Number(l.value)).filter((n) => Number.isFinite(n) && n > 0);
|
|
53742
54090
|
const rlMin = routeLegVals.length ? Math.min(...routeLegVals) : 0;
|
|
53743
54091
|
const rlMax = routeLegVals.length ? Math.max(...routeLegVals) : 0;
|
|
@@ -53751,13 +54099,12 @@ function layoutMap(resolvedIn, data, size, opts) {
|
|
|
53751
54099
|
const a = poiScreen.get(leg.fromId);
|
|
53752
54100
|
const b = poiScreen.get(leg.toId);
|
|
53753
54101
|
if (!a || !b) continue;
|
|
53754
|
-
const
|
|
53755
|
-
const my = (a.cy + b.cy) / 2;
|
|
54102
|
+
const lp = legLabelPoint(a, b, leg.style === "arc", 0);
|
|
53756
54103
|
const bow = {
|
|
53757
54104
|
curved: leg.style === "arc",
|
|
53758
54105
|
offset: 0,
|
|
53759
|
-
labelX:
|
|
53760
|
-
labelY:
|
|
54106
|
+
labelX: lp.x,
|
|
54107
|
+
labelY: lp.y
|
|
53761
54108
|
};
|
|
53762
54109
|
const routeLabelStyle = leg.label !== void 0 ? labelOnFill(fillAt(bow.labelX, bow.labelY)) : void 0;
|
|
53763
54110
|
legs.push({
|
|
@@ -53804,13 +54151,13 @@ function layoutMap(resolvedIn, data, size, opts) {
|
|
|
53804
54151
|
const b = poiScreen.get(e.toId);
|
|
53805
54152
|
if (!a || !b) return;
|
|
53806
54153
|
const fanOffset = n > 1 ? (i - (n - 1) / 2) * FAN_STEP : 0;
|
|
53807
|
-
const
|
|
53808
|
-
const
|
|
54154
|
+
const curved = e.style === "arc" || n > 1;
|
|
54155
|
+
const lp = legLabelPoint(a, b, curved, fanOffset);
|
|
53809
54156
|
const bow = {
|
|
53810
|
-
curved
|
|
54157
|
+
curved,
|
|
53811
54158
|
offset: fanOffset,
|
|
53812
|
-
labelX:
|
|
53813
|
-
labelY:
|
|
54159
|
+
labelX: lp.x,
|
|
54160
|
+
labelY: lp.y
|
|
53814
54161
|
};
|
|
53815
54162
|
const edgeLabelStyle = e.label !== void 0 ? labelOnFill(fillAt(bow.labelX, bow.labelY)) : void 0;
|
|
53816
54163
|
legs.push({
|
|
@@ -53834,7 +54181,7 @@ function layoutMap(resolvedIn, data, size, opts) {
|
|
|
53834
54181
|
});
|
|
53835
54182
|
}
|
|
53836
54183
|
const labels = [];
|
|
53837
|
-
const obstacles = [];
|
|
54184
|
+
const obstacles = [...topReserved];
|
|
53838
54185
|
const regionLabelGuards = [];
|
|
53839
54186
|
const markers = pois.map((p) => ({
|
|
53840
54187
|
cx: p.cx,
|
|
@@ -53872,6 +54219,7 @@ function layoutMap(resolvedIn, data, size, opts) {
|
|
|
53872
54219
|
}
|
|
53873
54220
|
const collides = (rect) => markers.some((m) => rectCircleOverlap(rect, m)) || obstacles.some((o) => rectsOverlap(rect, o)) || legSegments.some((s) => segmentRectOverlap(s[0], s[1], s[2], s[3], rect));
|
|
53874
54221
|
const showRegionLabels = resolved.directives.noRegionLabels !== true;
|
|
54222
|
+
const labeledRegionIds = /* @__PURE__ */ new Set();
|
|
53875
54223
|
const showRegionValues = resolved.directives.noRegionValue !== true && activeIsScore;
|
|
53876
54224
|
const regionValueStr = (value) => showRegionValues && value !== void 0 ? compactNumber(value) : void 0;
|
|
53877
54225
|
const isCompact = width < COMPACT_WIDTH_PX;
|
|
@@ -53892,7 +54240,9 @@ function layoutMap(resolvedIn, data, size, opts) {
|
|
|
53892
54240
|
const REGION_FONT_MAX_ORIENT = 22;
|
|
53893
54241
|
const REGION_SIZE_FRAC_MIN = 0.06;
|
|
53894
54242
|
const REGION_SIZE_FRAC_MAX = 0.32;
|
|
53895
|
-
const
|
|
54243
|
+
const SUBJECT_FONT_MAX = 18;
|
|
54244
|
+
const SUBJECT_MIN_PROMINENCE = 13;
|
|
54245
|
+
const SUBJECT_LEADER_FONT = 15;
|
|
53896
54246
|
const canvasLinear = Math.sqrt(Math.max(1, width * height));
|
|
53897
54247
|
const sizeT = (boxW, boxH) => {
|
|
53898
54248
|
const frac = Math.sqrt(Math.max(0, boxW * boxH)) / canvasLinear;
|
|
@@ -53904,9 +54254,9 @@ function layoutMap(resolvedIn, data, size, opts) {
|
|
|
53904
54254
|
)
|
|
53905
54255
|
);
|
|
53906
54256
|
};
|
|
53907
|
-
const pushRegionLabel = (x, y, text, fill2, lineNumber, valueLine, fontSize = FONT2,
|
|
54257
|
+
const pushRegionLabel = (x, y, text, fill2, lineNumber, valueLine, fontSize = FONT2, colorOverride) => {
|
|
53908
54258
|
const { color: baseColor, haloColor } = labelOnFill(fill2);
|
|
53909
|
-
const color =
|
|
54259
|
+
const color = colorOverride ?? baseColor;
|
|
53910
54260
|
const vf = Math.round(fontSize * 0.82);
|
|
53911
54261
|
const halfW = Math.max(
|
|
53912
54262
|
measureLegendText(text, fontSize),
|
|
@@ -53921,7 +54271,11 @@ function layoutMap(resolvedIn, data, size, opts) {
|
|
|
53921
54271
|
text,
|
|
53922
54272
|
anchor: "middle",
|
|
53923
54273
|
color,
|
|
53924
|
-
|
|
54274
|
+
// A backdrop label (colorOverride) NEVER haloes: the placement gate above
|
|
54275
|
+
// guarantees it sits on a floored-readable substrate (own fill, neutral
|
|
54276
|
+
// land, foreign land, or water), so a halo is pure noise. Data labels keep
|
|
54277
|
+
// the containment-gated halo until the role-tier pass (Phase 3).
|
|
54278
|
+
halo: colorOverride ? false : overflows,
|
|
53925
54279
|
haloColor,
|
|
53926
54280
|
...fontSize !== FONT2 && { fontSize },
|
|
53927
54281
|
...valueLine !== void 0 && { valueLine },
|
|
@@ -53957,7 +54311,7 @@ function layoutMap(resolvedIn, data, size, opts) {
|
|
|
53957
54311
|
if (!c || !Number.isFinite(c[0])) return null;
|
|
53958
54312
|
return { r, c, boxW, boxH, area: boxW * boxH, candidates };
|
|
53959
54313
|
}).filter((e) => e !== null).sort((a, b) => b.area - a.area || a.r.lineNumber - b.r.lineNumber);
|
|
53960
|
-
const placedRegionRects = [];
|
|
54314
|
+
const placedRegionRects = [...topReserved];
|
|
53961
54315
|
const placedLeaders = [];
|
|
53962
54316
|
const isEmptyFill = (f) => f === water || f === neutralFill || f === foreignFill;
|
|
53963
54317
|
const POI_LABEL_PAD = 14;
|
|
@@ -53970,9 +54324,9 @@ function layoutMap(resolvedIn, data, size, opts) {
|
|
|
53970
54324
|
const SHORT_HOP_MAX = Math.max(46, Math.min(width, height) * 0.11);
|
|
53971
54325
|
const STEP = 4;
|
|
53972
54326
|
const HOP_GAP = 9;
|
|
53973
|
-
const tryShortHopCallout = (cx, cy, fill2, name, value) => {
|
|
53974
|
-
const chipW = stackW(name, value);
|
|
53975
|
-
const chipH = stackH(value !== void 0);
|
|
54327
|
+
const tryShortHopCallout = (cx, cy, fill2, name, value, font = FONT2, gap = HOP_GAP, maxLen = SHORT_HOP_MAX) => {
|
|
54328
|
+
const chipW = stackW(name, value, font);
|
|
54329
|
+
const chipH = stackH(value !== void 0, font);
|
|
53976
54330
|
const dirs = [
|
|
53977
54331
|
[0, -1],
|
|
53978
54332
|
// north (over Canada)
|
|
@@ -53988,7 +54342,7 @@ function layoutMap(resolvedIn, data, size, opts) {
|
|
|
53988
54342
|
let ex = cx;
|
|
53989
54343
|
let ey = cy;
|
|
53990
54344
|
let steps = 0;
|
|
53991
|
-
const maxSteps = Math.ceil(
|
|
54345
|
+
const maxSteps = Math.ceil(maxLen / STEP) + 1;
|
|
53992
54346
|
while (steps < maxSteps && fillAt(ex, ey) === fill2) {
|
|
53993
54347
|
ex += dx * STEP;
|
|
53994
54348
|
ey += dy * STEP;
|
|
@@ -53996,8 +54350,8 @@ function layoutMap(resolvedIn, data, size, opts) {
|
|
|
53996
54350
|
}
|
|
53997
54351
|
if (fillAt(ex, ey) === fill2) continue;
|
|
53998
54352
|
const halfAlong = (Math.abs(dx) * chipW + Math.abs(dy) * chipH) / 2;
|
|
53999
|
-
const ccx = ex + dx * (
|
|
54000
|
-
const ccy = ey + dy * (
|
|
54353
|
+
const ccx = ex + dx * (gap + halfAlong);
|
|
54354
|
+
const ccy = ey + dy * (gap + halfAlong);
|
|
54001
54355
|
const rect = {
|
|
54002
54356
|
x: ccx - chipW / 2,
|
|
54003
54357
|
y: ccy - chipH / 2,
|
|
@@ -54022,7 +54376,7 @@ function layoutMap(resolvedIn, data, size, opts) {
|
|
|
54022
54376
|
const innerX = ccx - dx * (chipW / 2);
|
|
54023
54377
|
const innerY = ccy - dy * (chipH / 2);
|
|
54024
54378
|
const len = Math.hypot(innerX - cx, innerY - cy);
|
|
54025
|
-
if (len >
|
|
54379
|
+
if (len > maxLen) continue;
|
|
54026
54380
|
if (placedLeaders.some(
|
|
54027
54381
|
(l) => segmentsCross(cx, cy, innerX, innerY, l[0], l[1], l[2], l[3])
|
|
54028
54382
|
))
|
|
@@ -54046,6 +54400,78 @@ function layoutMap(resolvedIn, data, size, opts) {
|
|
|
54046
54400
|
const valStr = regionValueStr(r.value);
|
|
54047
54401
|
const fitsRegions = (rect) => !placedRegionRects.some((p) => rectsOverlap(rect, p));
|
|
54048
54402
|
const fitsPois = (rect) => !poiObstacles.some((o) => rectsOverlap(rect, o));
|
|
54403
|
+
const isSubject = regionById.has(r.id);
|
|
54404
|
+
const extremesOnFill = (ax, ay, text) => {
|
|
54405
|
+
const halfW = measureLegendText(text, FONT2) / 2;
|
|
54406
|
+
return fillAt(ax - halfW, ay) === r.fill && fillAt(ax + halfW, ay) === r.fill;
|
|
54407
|
+
};
|
|
54408
|
+
if (isSubject && valStr === void 0 && r.label !== void 0) {
|
|
54409
|
+
const name = candidates[0];
|
|
54410
|
+
let best = -1;
|
|
54411
|
+
for (let f = SUBJECT_FONT_MAX; f >= FONT2; f--) {
|
|
54412
|
+
if (measureLegendText(name, f) > boxW || f + 2 * LABEL_PADY > boxH)
|
|
54413
|
+
continue;
|
|
54414
|
+
const rect = regionLabelRect(c[0], c[1], name, void 0, f);
|
|
54415
|
+
if (!fitsRegions(rect) || !fitsPois(rect) || collides(rect)) continue;
|
|
54416
|
+
const halfW = measureLegendText(name, f) / 2;
|
|
54417
|
+
if (fillAt(c[0] - halfW, c[1]) !== r.fill || fillAt(c[0] + halfW, c[1]) !== r.fill)
|
|
54418
|
+
continue;
|
|
54419
|
+
best = f;
|
|
54420
|
+
break;
|
|
54421
|
+
}
|
|
54422
|
+
if (best >= SUBJECT_MIN_PROMINENCE) {
|
|
54423
|
+
const rect = regionLabelRect(c[0], c[1], name, void 0, best);
|
|
54424
|
+
placedRegionRects.push(rect);
|
|
54425
|
+
pushRegionLabel(
|
|
54426
|
+
c[0],
|
|
54427
|
+
c[1],
|
|
54428
|
+
name,
|
|
54429
|
+
r.fill,
|
|
54430
|
+
r.lineNumber,
|
|
54431
|
+
void 0,
|
|
54432
|
+
best
|
|
54433
|
+
);
|
|
54434
|
+
labeledRegionIds.add(r.id);
|
|
54435
|
+
regionLabelGuards.push({ label: labels[labels.length - 1], rect });
|
|
54436
|
+
} else {
|
|
54437
|
+
const hop = tryShortHopCallout(
|
|
54438
|
+
c[0],
|
|
54439
|
+
c[1],
|
|
54440
|
+
r.fill,
|
|
54441
|
+
r.label,
|
|
54442
|
+
void 0,
|
|
54443
|
+
SUBJECT_LEADER_FONT,
|
|
54444
|
+
HOP_GAP + SUBJECT_LEADER_FONT,
|
|
54445
|
+
SHORT_HOP_MAX * 2.2
|
|
54446
|
+
);
|
|
54447
|
+
if (hop) {
|
|
54448
|
+
placedRegionRects.push(hop.rect);
|
|
54449
|
+
placedLeaders.push(hop.leader);
|
|
54450
|
+
const dark = mix(r.fill, palette.text, 60);
|
|
54451
|
+
labels.push({
|
|
54452
|
+
x: hop.x,
|
|
54453
|
+
y: hop.y,
|
|
54454
|
+
text: r.label,
|
|
54455
|
+
anchor: "middle",
|
|
54456
|
+
color: palette.text,
|
|
54457
|
+
halo: false,
|
|
54458
|
+
haloColor: palette.bg,
|
|
54459
|
+
fontSize: SUBJECT_LEADER_FONT,
|
|
54460
|
+
leader: {
|
|
54461
|
+
x1: hop.leader[0],
|
|
54462
|
+
y1: hop.leader[1],
|
|
54463
|
+
x2: hop.leader[2],
|
|
54464
|
+
y2: hop.leader[3]
|
|
54465
|
+
},
|
|
54466
|
+
leaderColor: dark,
|
|
54467
|
+
calloutDot: { x: c[0], y: c[1], color: dark },
|
|
54468
|
+
lineNumber: r.lineNumber
|
|
54469
|
+
});
|
|
54470
|
+
labeledRegionIds.add(r.id);
|
|
54471
|
+
}
|
|
54472
|
+
}
|
|
54473
|
+
continue;
|
|
54474
|
+
}
|
|
54049
54475
|
const seekAnchors = [
|
|
54050
54476
|
{ x: c[0], y: c[1], guard: false }
|
|
54051
54477
|
];
|
|
@@ -54068,13 +54494,13 @@ function layoutMap(resolvedIn, data, size, opts) {
|
|
|
54068
54494
|
const nameRect = regionLabelRect(a.x, a.y, t);
|
|
54069
54495
|
if (valStr && stackW(t, valStr) <= boxW && stackH(true) <= boxH) {
|
|
54070
54496
|
const stackRect = regionLabelRect(a.x, a.y, t, valStr);
|
|
54071
|
-
if (fitsRegions(stackRect) && fitsPois(nameRect)) {
|
|
54497
|
+
if (fitsRegions(stackRect) && fitsPois(nameRect) && extremesOnFill(a.x, a.y, t)) {
|
|
54072
54498
|
chosen = { text: t, valueLine: valStr, ax: a.x, ay: a.y };
|
|
54073
54499
|
break;
|
|
54074
54500
|
}
|
|
54075
54501
|
}
|
|
54076
54502
|
if (labelW(t) <= boxW && labelH <= boxH) {
|
|
54077
|
-
if (fitsRegions(nameRect) && fitsPois(nameRect)) {
|
|
54503
|
+
if (fitsRegions(nameRect) && fitsPois(nameRect) && (valStr === void 0 || extremesOnFill(a.x, a.y, t))) {
|
|
54078
54504
|
chosen = { text: t, ax: a.x, ay: a.y };
|
|
54079
54505
|
break;
|
|
54080
54506
|
}
|
|
@@ -54082,7 +54508,7 @@ function layoutMap(resolvedIn, data, size, opts) {
|
|
|
54082
54508
|
}
|
|
54083
54509
|
if (chosen) break;
|
|
54084
54510
|
}
|
|
54085
|
-
if (chosen === void 0 &&
|
|
54511
|
+
if (chosen === void 0 && r.label !== void 0 && isSubject) {
|
|
54086
54512
|
const hop = tryShortHopCallout(c[0], c[1], r.fill, r.label, valStr);
|
|
54087
54513
|
if (hop) {
|
|
54088
54514
|
placedRegionRects.push(hop.rect);
|
|
@@ -54094,9 +54520,9 @@ function layoutMap(resolvedIn, data, size, opts) {
|
|
|
54094
54520
|
text: r.label,
|
|
54095
54521
|
anchor: "middle",
|
|
54096
54522
|
color: palette.text,
|
|
54097
|
-
halo:
|
|
54523
|
+
halo: false,
|
|
54098
54524
|
haloColor: palette.bg,
|
|
54099
|
-
valueLine: valStr,
|
|
54525
|
+
...valStr !== void 0 && { valueLine: valStr },
|
|
54100
54526
|
leader: {
|
|
54101
54527
|
x1: hop.leader[0],
|
|
54102
54528
|
y1: hop.leader[1],
|
|
@@ -54107,20 +54533,28 @@ function layoutMap(resolvedIn, data, size, opts) {
|
|
|
54107
54533
|
calloutDot: { x: c[0], y: c[1], color: dark },
|
|
54108
54534
|
lineNumber: r.lineNumber
|
|
54109
54535
|
});
|
|
54536
|
+
labeledRegionIds.add(r.id);
|
|
54110
54537
|
}
|
|
54111
54538
|
continue;
|
|
54112
54539
|
}
|
|
54113
54540
|
if (chosen === void 0) continue;
|
|
54114
54541
|
const isOrient = r.value === void 0 && r.layer === "base";
|
|
54115
54542
|
let font = FONT2;
|
|
54116
|
-
let fade = 0;
|
|
54117
54543
|
if (isOrient) {
|
|
54118
54544
|
const growT = sizeT(boxW, boxH);
|
|
54119
54545
|
const desiredFont = Math.round(
|
|
54120
54546
|
FONT2 + growT * (REGION_FONT_MAX_ORIENT - FONT2)
|
|
54121
54547
|
);
|
|
54122
54548
|
const hasVal = chosen.valueLine !== void 0;
|
|
54123
|
-
|
|
54549
|
+
const extremesClean = (f) => {
|
|
54550
|
+
const halfW = measureLegendText(chosen.text, f) / 2;
|
|
54551
|
+
return [chosen.ax - halfW, chosen.ax + halfW].every((sx) => {
|
|
54552
|
+
const fAt = fillAt(sx, chosen.ay);
|
|
54553
|
+
return fAt === r.fill || isEmptyFill(fAt);
|
|
54554
|
+
});
|
|
54555
|
+
};
|
|
54556
|
+
let fit = -1;
|
|
54557
|
+
for (let f = desiredFont; f >= FONT2; f--) {
|
|
54124
54558
|
if (stackW(chosen.text, chosen.valueLine, f) > boxW || stackH(hasVal, f) > boxH)
|
|
54125
54559
|
continue;
|
|
54126
54560
|
const gRect = regionLabelRect(
|
|
@@ -54137,14 +54571,18 @@ function layoutMap(resolvedIn, data, size, opts) {
|
|
|
54137
54571
|
void 0,
|
|
54138
54572
|
f
|
|
54139
54573
|
);
|
|
54140
|
-
if (!fitsRegions(gRect) || !fitsPois(gName))
|
|
54141
|
-
const halfW = measureLegendText(chosen.text, f) / 2;
|
|
54142
|
-
if (fillAt(chosen.ax - halfW, chosen.ay) !== r.fill || fillAt(chosen.ax + halfW, chosen.ay) !== r.fill)
|
|
54574
|
+
if (!fitsRegions(gRect) || !fitsPois(gName) || collides(gName))
|
|
54143
54575
|
continue;
|
|
54144
|
-
|
|
54576
|
+
if (!extremesClean(f)) continue;
|
|
54577
|
+
fit = f;
|
|
54145
54578
|
break;
|
|
54146
54579
|
}
|
|
54147
|
-
|
|
54580
|
+
if (fit < 0) {
|
|
54581
|
+
if (!frameContainers.has(r.id)) continue;
|
|
54582
|
+
font = FONT2;
|
|
54583
|
+
} else {
|
|
54584
|
+
font = fit;
|
|
54585
|
+
}
|
|
54148
54586
|
}
|
|
54149
54587
|
const rRect = regionLabelRect(
|
|
54150
54588
|
chosen.ax,
|
|
@@ -54162,8 +54600,9 @@ function layoutMap(resolvedIn, data, size, opts) {
|
|
|
54162
54600
|
r.lineNumber,
|
|
54163
54601
|
chosen.valueLine,
|
|
54164
54602
|
font,
|
|
54165
|
-
|
|
54603
|
+
isOrient ? backdropLandTone : void 0
|
|
54166
54604
|
);
|
|
54605
|
+
labeledRegionIds.add(r.id);
|
|
54167
54606
|
regionLabelGuards.push({
|
|
54168
54607
|
label: labels[labels.length - 1],
|
|
54169
54608
|
rect: rRect
|
|
@@ -54181,6 +54620,7 @@ function layoutMap(resolvedIn, data, size, opts) {
|
|
|
54181
54620
|
seed.lineNumber,
|
|
54182
54621
|
valStr
|
|
54183
54622
|
);
|
|
54623
|
+
labeledRegionIds.add(seed.iso);
|
|
54184
54624
|
regionLabelGuards.push({
|
|
54185
54625
|
label: labels[labels.length - 1],
|
|
54186
54626
|
rect: regionLabelRect(seed.x, seed.y, text, valStr)
|
|
@@ -54612,13 +55052,30 @@ function layoutMap(resolvedIn, data, size, opts) {
|
|
|
54612
55052
|
const nx = -dy / len;
|
|
54613
55053
|
const ny = dx / len;
|
|
54614
55054
|
const perp = labelH + 2;
|
|
55055
|
+
const pm = /^M(-?[\d.]+),(-?[\d.]+)(?:L(-?[\d.]+),(-?[\d.]+)|Q(-?[\d.]+),(-?[\d.]+) (-?[\d.]+),(-?[\d.]+))$/.exec(
|
|
55056
|
+
lg.d
|
|
55057
|
+
);
|
|
55058
|
+
const pointAt = (t) => {
|
|
55059
|
+
if (pm?.[5] !== void 0) {
|
|
55060
|
+
const u = 1 - t;
|
|
55061
|
+
return [
|
|
55062
|
+
u * u * +pm[1] + 2 * u * t * +pm[5] + t * t * +pm[7],
|
|
55063
|
+
u * u * +pm[2] + 2 * u * t * +pm[6] + t * t * +pm[8]
|
|
55064
|
+
];
|
|
55065
|
+
}
|
|
55066
|
+
if (pm?.[3] !== void 0)
|
|
55067
|
+
return [
|
|
55068
|
+
+pm[1] + (+pm[3] - +pm[1]) * t,
|
|
55069
|
+
+pm[2] + (+pm[4] - +pm[2]) * t
|
|
55070
|
+
];
|
|
55071
|
+
return [a.cx + dx * t, a.cy + dy * t];
|
|
55072
|
+
};
|
|
54615
55073
|
const candidates = [];
|
|
54616
55074
|
for (const off of [0, perp, -perp, 2 * perp, -2 * perp])
|
|
54617
|
-
for (const t of T_LIST)
|
|
54618
|
-
|
|
54619
|
-
|
|
54620
|
-
|
|
54621
|
-
]);
|
|
55075
|
+
for (const t of T_LIST) {
|
|
55076
|
+
const [bx, by] = pointAt(t);
|
|
55077
|
+
candidates.push([bx + nx * off, by + ny * off - 4]);
|
|
55078
|
+
}
|
|
54622
55079
|
const clean = ([cx2, cy2]) => {
|
|
54623
55080
|
const rect2 = { x: cx2 - w / 2, y: cy2 - labelH / 2, w, h: labelH };
|
|
54624
55081
|
if (rect2.x < 0 || rect2.x + w > width || rect2.y < 0 || rect2.y + rect2.h > height)
|
|
@@ -54628,10 +55085,8 @@ function layoutMap(resolvedIn, data, size, opts) {
|
|
|
54628
55085
|
if (placedEdge.some((o) => rectsOverlap(o, rect2))) return false;
|
|
54629
55086
|
return true;
|
|
54630
55087
|
};
|
|
54631
|
-
const
|
|
54632
|
-
|
|
54633
|
-
a.cy + dy * 0.5 - 4
|
|
54634
|
-
];
|
|
55088
|
+
const mid = pointAt(0.5);
|
|
55089
|
+
const [cx, cy] = candidates.find(clean) ?? [mid[0], mid[1] - 4];
|
|
54635
55090
|
const style = labelOnFill(fillAt(cx, cy));
|
|
54636
55091
|
legs[i] = {
|
|
54637
55092
|
...lg,
|
|
@@ -54659,7 +55114,7 @@ function layoutMap(resolvedIn, data, size, opts) {
|
|
|
54659
55114
|
const rawCountries = [];
|
|
54660
55115
|
for (const f of worldLayer.values()) {
|
|
54661
55116
|
const iso = typeof f.id === "string" ? f.id : String(f.id ?? "");
|
|
54662
|
-
if (!iso || regionById.has(iso)) continue;
|
|
55117
|
+
if (!iso || regionById.has(iso) || labeledRegionIds.has(iso)) continue;
|
|
54663
55118
|
let hasReferencedSub = false;
|
|
54664
55119
|
for (const k of regionById.keys())
|
|
54665
55120
|
if (k.startsWith(iso + "-")) {
|
|
@@ -54733,7 +55188,7 @@ function layoutMap(resolvedIn, data, size, opts) {
|
|
|
54733
55188
|
);
|
|
54734
55189
|
if (usLayer && framedStateContainers) {
|
|
54735
55190
|
for (const [iso, f] of usLayer) {
|
|
54736
|
-
if (regionById.has(iso)) continue;
|
|
55191
|
+
if (regionById.has(iso) || labeledRegionIds.has(iso)) continue;
|
|
54737
55192
|
const viewF = cullFeatureToView(f);
|
|
54738
55193
|
if (!viewF) continue;
|
|
54739
55194
|
const b = path.bounds(viewF);
|
|
@@ -54757,6 +55212,11 @@ function layoutMap(resolvedIn, data, size, opts) {
|
|
|
54757
55212
|
waterBodies: data.waterBodies,
|
|
54758
55213
|
countries: countryCandidates,
|
|
54759
55214
|
palette,
|
|
55215
|
+
// One muted, contrast-floored tone shared with the orientation backdrop
|
|
55216
|
+
// (region pass) so a context country (Canada) and an orientation region
|
|
55217
|
+
// (Minnesota) read identically — never below the WCAG-AA floor, no fade.
|
|
55218
|
+
countryTone: backdropLandTone,
|
|
55219
|
+
waterTone: backdropWaterTone,
|
|
54760
55220
|
project,
|
|
54761
55221
|
collides,
|
|
54762
55222
|
contentPoints,
|
|
@@ -55310,19 +55770,60 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
55310
55770
|
sel.style("cursor", "pointer").on("click", () => onClickItem(lineNumber));
|
|
55311
55771
|
};
|
|
55312
55772
|
const gLegs = svg.append("g").attr("class", "dgmo-map-legs").attr("fill", "none");
|
|
55313
|
-
|
|
55314
|
-
const
|
|
55773
|
+
const legEnd = (d) => {
|
|
55774
|
+
const m = /^M(-?[\d.]+),(-?[\d.]+)(?:L(-?[\d.]+),(-?[\d.]+)|Q(-?[\d.]+),(-?[\d.]+) (-?[\d.]+),(-?[\d.]+))$/.exec(
|
|
55775
|
+
d
|
|
55776
|
+
);
|
|
55777
|
+
if (!m) return null;
|
|
55778
|
+
const x0 = +m[1];
|
|
55779
|
+
const y0 = +m[2];
|
|
55780
|
+
let ex;
|
|
55781
|
+
let ey;
|
|
55782
|
+
let fromX;
|
|
55783
|
+
let fromY;
|
|
55784
|
+
if (m[3] !== void 0) {
|
|
55785
|
+
ex = +m[3];
|
|
55786
|
+
ey = +m[4];
|
|
55787
|
+
fromX = x0;
|
|
55788
|
+
fromY = y0;
|
|
55789
|
+
} else {
|
|
55790
|
+
ex = +m[7];
|
|
55791
|
+
ey = +m[8];
|
|
55792
|
+
fromX = +m[5];
|
|
55793
|
+
fromY = +m[6];
|
|
55794
|
+
}
|
|
55795
|
+
const dx = ex - fromX;
|
|
55796
|
+
const dy = ey - fromY;
|
|
55797
|
+
const len = Math.hypot(dx, dy);
|
|
55798
|
+
if (!(len > 0)) return null;
|
|
55799
|
+
return { ex, ey, tx: dx / len, ty: dy / len };
|
|
55800
|
+
};
|
|
55801
|
+
layout.legs.forEach((leg) => {
|
|
55802
|
+
const end = leg.arrow ? legEnd(leg.d) : null;
|
|
55803
|
+
let drawD = leg.d;
|
|
55804
|
+
let arrowTri = null;
|
|
55805
|
+
if (end) {
|
|
55806
|
+
const aLen = arrowSize(leg.width);
|
|
55807
|
+
const aHalf = Math.max(aLen * 0.5, leg.width * 0.6 + 1);
|
|
55808
|
+
const bx = end.ex - end.tx * aLen;
|
|
55809
|
+
const by = end.ey - end.ty * aLen;
|
|
55810
|
+
const px = -end.ty;
|
|
55811
|
+
const py = end.tx;
|
|
55812
|
+
arrowTri = `M${bx + px * aHalf},${by + py * aHalf}L${end.ex},${end.ey}L${bx - px * aHalf},${by - py * aHalf}z`;
|
|
55813
|
+
drawD = leg.d.replace(
|
|
55814
|
+
/(-?[\d.]+),(-?[\d.]+)$/,
|
|
55815
|
+
`${bx.toFixed(2)},${by.toFixed(2)}`
|
|
55816
|
+
);
|
|
55817
|
+
}
|
|
55818
|
+
const p = gLegs.append("path").attr("d", drawD).attr("stroke", leg.color).attr("stroke-width", leg.width).attr("stroke-linecap", "round").attr("data-from-id", leg.fromId).attr("data-to-id", leg.toId);
|
|
55315
55819
|
if (leg.tags) {
|
|
55316
55820
|
for (const [group, value] of Object.entries(leg.tags)) {
|
|
55317
55821
|
p.attr(`data-tag-${group.toLowerCase()}`, value.toLowerCase());
|
|
55318
55822
|
}
|
|
55319
55823
|
}
|
|
55320
55824
|
wireSync(p, leg.lineNumber);
|
|
55321
|
-
if (
|
|
55322
|
-
|
|
55323
|
-
const s = arrowSize(leg.width);
|
|
55324
|
-
defs.append("marker").attr("id", id).attr("viewBox", "0 0 10 10").attr("refX", 10).attr("refY", 5).attr("markerUnits", "userSpaceOnUse").attr("markerWidth", s).attr("markerHeight", s).attr("orient", "auto-start-reverse").append("path").attr("d", "M0,0L10,5L0,10z").attr("fill", leg.color);
|
|
55325
|
-
p.attr("marker-end", `url(#${id})`);
|
|
55825
|
+
if (arrowTri) {
|
|
55826
|
+
gLegs.append("path").attr("d", arrowTri).attr("fill", leg.color).attr("stroke", leg.color).attr("stroke-width", 1).attr("stroke-linejoin", "round").attr("data-from-id", leg.fromId).attr("data-to-id", leg.toId);
|
|
55326
55827
|
}
|
|
55327
55828
|
if (leg.label !== void 0 && leg.labelX !== void 0) {
|
|
55328
55829
|
const lt = emitText(
|
|
@@ -58949,9 +59450,9 @@ var init_renderer20 = __esm({
|
|
|
58949
59450
|
}
|
|
58950
59451
|
});
|
|
58951
59452
|
|
|
58952
|
-
// node_modules/.pnpm/lz-string@1.5.0/node_modules/lz-string/libs/lz-string.js
|
|
59453
|
+
// ../../diagrammo/dgmo/node_modules/.pnpm/lz-string@1.5.0/node_modules/lz-string/libs/lz-string.js
|
|
58953
59454
|
var require_lz_string = __commonJS({
|
|
58954
|
-
"node_modules/.pnpm/lz-string@1.5.0/node_modules/lz-string/libs/lz-string.js"(exports, module) {
|
|
59455
|
+
"../../diagrammo/dgmo/node_modules/.pnpm/lz-string@1.5.0/node_modules/lz-string/libs/lz-string.js"(exports, module) {
|
|
58955
59456
|
"use strict";
|
|
58956
59457
|
var LZString = (function() {
|
|
58957
59458
|
var f = String.fromCharCode;
|
|
@@ -65237,326 +65738,6 @@ var themes = {
|
|
|
65237
65738
|
|
|
65238
65739
|
// src/advanced.ts
|
|
65239
65740
|
init_dgmo_router();
|
|
65240
|
-
|
|
65241
|
-
// src/migrate/index.ts
|
|
65242
|
-
init_dgmo_router();
|
|
65243
|
-
import {
|
|
65244
|
-
readFileSync,
|
|
65245
|
-
writeFileSync,
|
|
65246
|
-
existsSync,
|
|
65247
|
-
statSync,
|
|
65248
|
-
readdirSync
|
|
65249
|
-
} from "fs";
|
|
65250
|
-
import { join, extname } from "path";
|
|
65251
|
-
|
|
65252
|
-
// src/migrate/line-classifier.ts
|
|
65253
|
-
function findUnsafePipePositions(line11) {
|
|
65254
|
-
const positions = [];
|
|
65255
|
-
let i = 0;
|
|
65256
|
-
let inDouble = false;
|
|
65257
|
-
let inSingle = false;
|
|
65258
|
-
let braceDepth = 0;
|
|
65259
|
-
let inArrow = false;
|
|
65260
|
-
let arrowOpenChar = null;
|
|
65261
|
-
while (i < line11.length) {
|
|
65262
|
-
const ch = line11[i];
|
|
65263
|
-
const ch2 = i + 1 < line11.length ? line11[i + 1] : "";
|
|
65264
|
-
if (inDouble) {
|
|
65265
|
-
if (ch === '"') inDouble = false;
|
|
65266
|
-
i++;
|
|
65267
|
-
continue;
|
|
65268
|
-
}
|
|
65269
|
-
if (inSingle) {
|
|
65270
|
-
if (ch === "'") inSingle = false;
|
|
65271
|
-
i++;
|
|
65272
|
-
continue;
|
|
65273
|
-
}
|
|
65274
|
-
if (inArrow) {
|
|
65275
|
-
if (arrowOpenChar === "-" && ch === "-" && ch2 === ">" || arrowOpenChar === "~" && ch === "~" && ch2 === ">") {
|
|
65276
|
-
inArrow = false;
|
|
65277
|
-
arrowOpenChar = null;
|
|
65278
|
-
i += 2;
|
|
65279
|
-
continue;
|
|
65280
|
-
}
|
|
65281
|
-
i++;
|
|
65282
|
-
continue;
|
|
65283
|
-
}
|
|
65284
|
-
if (ch === '"') {
|
|
65285
|
-
inDouble = true;
|
|
65286
|
-
i++;
|
|
65287
|
-
continue;
|
|
65288
|
-
}
|
|
65289
|
-
if (ch === "'") {
|
|
65290
|
-
inSingle = true;
|
|
65291
|
-
i++;
|
|
65292
|
-
continue;
|
|
65293
|
-
}
|
|
65294
|
-
if (ch === "{") {
|
|
65295
|
-
braceDepth++;
|
|
65296
|
-
i++;
|
|
65297
|
-
continue;
|
|
65298
|
-
}
|
|
65299
|
-
if (ch === "}") {
|
|
65300
|
-
if (braceDepth > 0) braceDepth--;
|
|
65301
|
-
i++;
|
|
65302
|
-
continue;
|
|
65303
|
-
}
|
|
65304
|
-
if ((ch === "-" || ch === "~") && i > 0) {
|
|
65305
|
-
const prev = line11[i - 1];
|
|
65306
|
-
const onBoundary = prev === " " || prev === " ";
|
|
65307
|
-
const nextIsLabelChar = ch2 !== "" && ch2 !== ch && ch2 !== ">" && ch2 !== " " && ch2 !== " ";
|
|
65308
|
-
if (onBoundary && nextIsLabelChar) {
|
|
65309
|
-
const closer = ch + ">";
|
|
65310
|
-
const closeIdx = line11.indexOf(closer, i + 1);
|
|
65311
|
-
if (closeIdx > i) {
|
|
65312
|
-
const labelRegion = line11.substring(i + 1, closeIdx);
|
|
65313
|
-
if (!labelRegion.includes("->") && !labelRegion.includes("~>")) {
|
|
65314
|
-
inArrow = true;
|
|
65315
|
-
arrowOpenChar = ch;
|
|
65316
|
-
i++;
|
|
65317
|
-
continue;
|
|
65318
|
-
}
|
|
65319
|
-
}
|
|
65320
|
-
}
|
|
65321
|
-
}
|
|
65322
|
-
if (ch === "|" && braceDepth === 0) {
|
|
65323
|
-
positions.push(i);
|
|
65324
|
-
}
|
|
65325
|
-
i++;
|
|
65326
|
-
}
|
|
65327
|
-
return positions;
|
|
65328
|
-
}
|
|
65329
|
-
function isLegacyMetadataLine(line11) {
|
|
65330
|
-
return findUnsafePipePositions(line11).length > 0;
|
|
65331
|
-
}
|
|
65332
|
-
|
|
65333
|
-
// src/migrate/line-transformer.ts
|
|
65334
|
-
function replaceUnsafePipesWithCommas(s) {
|
|
65335
|
-
const positions = findUnsafePipePositions(s);
|
|
65336
|
-
if (positions.length === 0) return s;
|
|
65337
|
-
const chars = s.split("");
|
|
65338
|
-
for (const pos of positions) {
|
|
65339
|
-
chars[pos] = ",";
|
|
65340
|
-
}
|
|
65341
|
-
return chars.join("");
|
|
65342
|
-
}
|
|
65343
|
-
var GANTT_PERCENT = {
|
|
65344
|
-
match: (t) => /^\d+(?:\.\d+)?\s*%$/.test(t.trim()),
|
|
65345
|
-
promote: (t) => `progress: ${t.trim().replace(/\s*%$/, "")}`
|
|
65346
|
-
};
|
|
65347
|
-
var JOURNEY_SCORE = {
|
|
65348
|
-
match: (t) => /^\d+(?:\s+[A-Za-z][A-Za-z0-9_-]*)?$/.test(t.trim()),
|
|
65349
|
-
promote: (t) => {
|
|
65350
|
-
const m = t.trim().match(/^(\d+)(?:\s+([A-Za-z][A-Za-z0-9_-]*))?$/);
|
|
65351
|
-
if (!m) return t;
|
|
65352
|
-
return m[2] ? `score: ${m[1]}, emotion: ${m[2]}` : `score: ${m[1]}`;
|
|
65353
|
-
}
|
|
65354
|
-
};
|
|
65355
|
-
var PROMOTIONS_BY_CHART = {
|
|
65356
|
-
gantt: [GANTT_PERCENT],
|
|
65357
|
-
"journey-map": [JOURNEY_SCORE]
|
|
65358
|
-
};
|
|
65359
|
-
var BARE_DESCRIPTION_CHARTS = /* @__PURE__ */ new Set(["pyramid", "ring"]);
|
|
65360
|
-
function tokenizeMetaRegion(region) {
|
|
65361
|
-
const tokens = [];
|
|
65362
|
-
let i = 0;
|
|
65363
|
-
let buf = "";
|
|
65364
|
-
let inQuote = null;
|
|
65365
|
-
while (i < region.length) {
|
|
65366
|
-
const ch = region[i];
|
|
65367
|
-
if (inQuote) {
|
|
65368
|
-
buf += ch;
|
|
65369
|
-
if (ch === inQuote) inQuote = null;
|
|
65370
|
-
i++;
|
|
65371
|
-
continue;
|
|
65372
|
-
}
|
|
65373
|
-
if (ch === '"' || ch === "'") {
|
|
65374
|
-
inQuote = ch;
|
|
65375
|
-
buf += ch;
|
|
65376
|
-
i++;
|
|
65377
|
-
continue;
|
|
65378
|
-
}
|
|
65379
|
-
if (ch === ",") {
|
|
65380
|
-
const t = buf.trim();
|
|
65381
|
-
if (t) tokens.push(t);
|
|
65382
|
-
buf = "";
|
|
65383
|
-
i++;
|
|
65384
|
-
continue;
|
|
65385
|
-
}
|
|
65386
|
-
buf += ch;
|
|
65387
|
-
i++;
|
|
65388
|
-
}
|
|
65389
|
-
const tail = buf.trim();
|
|
65390
|
-
if (tail) tokens.push(tail);
|
|
65391
|
-
return tokens;
|
|
65392
|
-
}
|
|
65393
|
-
function transformLine(line11, chartType) {
|
|
65394
|
-
const indentMatch = line11.match(/^[ \t]*/);
|
|
65395
|
-
const indent = indentMatch ? indentMatch[0] : "";
|
|
65396
|
-
const body = line11.substring(indent.length);
|
|
65397
|
-
const pipePositions = findUnsafePipePositions(body);
|
|
65398
|
-
if (pipePositions.length === 0) {
|
|
65399
|
-
return { line: line11, changed: false };
|
|
65400
|
-
}
|
|
65401
|
-
const cut = pipePositions[0];
|
|
65402
|
-
const nameRegion = body.substring(0, cut).trimEnd();
|
|
65403
|
-
let metaRegion = body.substring(cut + 1).trimStart();
|
|
65404
|
-
if (pipePositions.length > 1) {
|
|
65405
|
-
metaRegion = replaceUnsafePipesWithCommas(metaRegion);
|
|
65406
|
-
}
|
|
65407
|
-
if (chartType !== null && BARE_DESCRIPTION_CHARTS.has(chartType) && !metaRegion.includes(":")) {
|
|
65408
|
-
const text = metaRegion.trim();
|
|
65409
|
-
if (!text) {
|
|
65410
|
-
return {
|
|
65411
|
-
line: indent + nameRegion,
|
|
65412
|
-
changed: true
|
|
65413
|
-
};
|
|
65414
|
-
}
|
|
65415
|
-
const value = text.includes(",") ? `"${text}"` : text;
|
|
65416
|
-
return {
|
|
65417
|
-
line: `${indent}${nameRegion} description: ${value}`,
|
|
65418
|
-
changed: true
|
|
65419
|
-
};
|
|
65420
|
-
}
|
|
65421
|
-
const tokens = tokenizeMetaRegion(metaRegion);
|
|
65422
|
-
const promotions = chartType ? PROMOTIONS_BY_CHART[chartType] ?? [] : [];
|
|
65423
|
-
const emitted = [];
|
|
65424
|
-
for (const raw of tokens) {
|
|
65425
|
-
if (raw.includes(":")) {
|
|
65426
|
-
emitted.push(raw);
|
|
65427
|
-
continue;
|
|
65428
|
-
}
|
|
65429
|
-
const promo = promotions.find((p) => p.match(raw));
|
|
65430
|
-
if (promo) {
|
|
65431
|
-
emitted.push(promo.promote(raw));
|
|
65432
|
-
continue;
|
|
65433
|
-
}
|
|
65434
|
-
emitted.push(raw);
|
|
65435
|
-
}
|
|
65436
|
-
if (emitted.length === 0) {
|
|
65437
|
-
return {
|
|
65438
|
-
line: indent + nameRegion,
|
|
65439
|
-
changed: true
|
|
65440
|
-
};
|
|
65441
|
-
}
|
|
65442
|
-
return {
|
|
65443
|
-
line: `${indent}${nameRegion} ${emitted.join(", ")}`,
|
|
65444
|
-
changed: true
|
|
65445
|
-
};
|
|
65446
|
-
}
|
|
65447
|
-
|
|
65448
|
-
// src/migrate/data-comma.ts
|
|
65449
|
-
init_colors();
|
|
65450
|
-
var DATA_COMMA_CHART_TYPES = /* @__PURE__ */ new Set([
|
|
65451
|
-
// Simple charts (chart.ts)
|
|
65452
|
-
"bar",
|
|
65453
|
-
"line",
|
|
65454
|
-
"multi-line",
|
|
65455
|
-
"pie",
|
|
65456
|
-
"doughnut",
|
|
65457
|
-
"area",
|
|
65458
|
-
"polar-area",
|
|
65459
|
-
"radar",
|
|
65460
|
-
"bar-stacked",
|
|
65461
|
-
// Extended charts (echarts.ts)
|
|
65462
|
-
"scatter",
|
|
65463
|
-
"heatmap",
|
|
65464
|
-
"sankey",
|
|
65465
|
-
"chord",
|
|
65466
|
-
"funnel",
|
|
65467
|
-
// Visualizations (d3 / visualizations/parse.ts)
|
|
65468
|
-
"quadrant",
|
|
65469
|
-
"slope",
|
|
65470
|
-
"arc",
|
|
65471
|
-
"wordcloud"
|
|
65472
|
-
]);
|
|
65473
|
-
var COLOR_SET = new Set(RECOGNIZED_COLOR_NAMES);
|
|
65474
|
-
var NUMERIC_VALUE_RE = /^-?\d[\d,_]*(?:\.\d+)?,?$/;
|
|
65475
|
-
function isNumericValueToken(tok) {
|
|
65476
|
-
if (!NUMERIC_VALUE_RE.test(tok)) return false;
|
|
65477
|
-
return /\d/.test(tok);
|
|
65478
|
-
}
|
|
65479
|
-
function migrateDataRowCommaLine(line11) {
|
|
65480
|
-
const indentMatch = line11.match(/^[ \t]*/);
|
|
65481
|
-
const indent = indentMatch ? indentMatch[0] : "";
|
|
65482
|
-
const body = line11.substring(indent.length);
|
|
65483
|
-
if (!body || body.startsWith("//")) return { line: line11, changed: false };
|
|
65484
|
-
const tokens = body.split(/\s+/);
|
|
65485
|
-
if (tokens.length < 2) return { line: line11, changed: false };
|
|
65486
|
-
let i = tokens.length - 1;
|
|
65487
|
-
if (i >= 1 && COLOR_SET.has(tokens[i])) {
|
|
65488
|
-
i--;
|
|
65489
|
-
}
|
|
65490
|
-
const valueStart = (() => {
|
|
65491
|
-
let j = i;
|
|
65492
|
-
while (j >= 1 && isNumericValueToken(tokens[j])) j--;
|
|
65493
|
-
return j + 1;
|
|
65494
|
-
})();
|
|
65495
|
-
if (valueStart > i || valueStart < 1) return { line: line11, changed: false };
|
|
65496
|
-
const valueTokens = tokens.slice(valueStart, i + 1);
|
|
65497
|
-
const hasComma = valueTokens.some((t) => t.includes(","));
|
|
65498
|
-
if (!hasComma) return { line: line11, changed: false };
|
|
65499
|
-
const cleaned = valueTokens.map((t) => t.replace(/,/g, ""));
|
|
65500
|
-
const labelPart = tokens.slice(0, valueStart);
|
|
65501
|
-
const tail = tokens.slice(i + 1);
|
|
65502
|
-
const rebuiltBody = [...labelPart, ...cleaned, ...tail].join(" ");
|
|
65503
|
-
return { line: indent + rebuiltBody, changed: rebuiltBody !== body };
|
|
65504
|
-
}
|
|
65505
|
-
|
|
65506
|
-
// src/migrate/index.ts
|
|
65507
|
-
function migrateContent(source) {
|
|
65508
|
-
const chartType = parseDgmoChartType(source);
|
|
65509
|
-
const lines = source.split("\n");
|
|
65510
|
-
const out = [];
|
|
65511
|
-
const changedLines = [];
|
|
65512
|
-
let changed = false;
|
|
65513
|
-
const migrateDataCommas = chartType !== null && DATA_COMMA_CHART_TYPES.has(chartType);
|
|
65514
|
-
let firstContentSeen = false;
|
|
65515
|
-
for (let i = 0; i < lines.length; i++) {
|
|
65516
|
-
let line11 = lines[i];
|
|
65517
|
-
const trimmed = line11.trim();
|
|
65518
|
-
if (migrateDataCommas && firstContentSeen && trimmed && !trimmed.startsWith("//")) {
|
|
65519
|
-
const dc = migrateDataRowCommaLine(line11);
|
|
65520
|
-
if (dc.changed) {
|
|
65521
|
-
line11 = dc.line;
|
|
65522
|
-
changed = true;
|
|
65523
|
-
changedLines.push(i + 1);
|
|
65524
|
-
}
|
|
65525
|
-
}
|
|
65526
|
-
if (trimmed && !trimmed.startsWith("//")) firstContentSeen = true;
|
|
65527
|
-
if (!isLegacyMetadataLine(line11)) {
|
|
65528
|
-
out.push(line11);
|
|
65529
|
-
continue;
|
|
65530
|
-
}
|
|
65531
|
-
const result = transformLine(line11, chartType);
|
|
65532
|
-
if (result.changed) {
|
|
65533
|
-
changed = true;
|
|
65534
|
-
if (!changedLines.includes(i + 1)) changedLines.push(i + 1);
|
|
65535
|
-
}
|
|
65536
|
-
out.push(result.line);
|
|
65537
|
-
}
|
|
65538
|
-
return {
|
|
65539
|
-
migrated: out.join("\n"),
|
|
65540
|
-
changed,
|
|
65541
|
-
chartType,
|
|
65542
|
-
changedLines
|
|
65543
|
-
};
|
|
65544
|
-
}
|
|
65545
|
-
function formatLineDiff(path, original, migrated) {
|
|
65546
|
-
const origLines = original.split("\n");
|
|
65547
|
-
const newLines = migrated.split("\n");
|
|
65548
|
-
const lines = [`--- ${path}`, `+++ ${path}`];
|
|
65549
|
-
const max = Math.max(origLines.length, newLines.length);
|
|
65550
|
-
for (let i = 0; i < max; i++) {
|
|
65551
|
-
const a = origLines[i];
|
|
65552
|
-
const b = newLines[i];
|
|
65553
|
-
if (a === b) continue;
|
|
65554
|
-
if (a !== void 0) lines.push(`@@ line ${i + 1}
|
|
65555
|
-
- ${a}`);
|
|
65556
|
-
if (b !== void 0) lines.push(`+ ${b}`);
|
|
65557
|
-
}
|
|
65558
|
-
return lines.join("\n");
|
|
65559
|
-
}
|
|
65560
65741
|
export {
|
|
65561
65742
|
ALL_CHART_TYPES,
|
|
65562
65743
|
ARROW_DIAGNOSTIC_CODES,
|
|
@@ -65625,12 +65806,10 @@ export {
|
|
|
65625
65806
|
extractSymbols as extractFlowchartSymbols,
|
|
65626
65807
|
extractSymbols4 as extractInfraSymbols,
|
|
65627
65808
|
extractPertSymbols,
|
|
65628
|
-
findUnsafePipePositions,
|
|
65629
65809
|
focusBoxesAndLines,
|
|
65630
65810
|
focusOrgTree,
|
|
65631
65811
|
formatDateLabel,
|
|
65632
65812
|
formatDgmoError,
|
|
65633
|
-
formatLineDiff,
|
|
65634
65813
|
getAllChartTypes,
|
|
65635
65814
|
getAvailablePalettes,
|
|
65636
65815
|
getExtendedChartLegendGroups,
|
|
@@ -65651,7 +65830,6 @@ export {
|
|
|
65651
65830
|
isArchiveColumn,
|
|
65652
65831
|
isExtendedChartType,
|
|
65653
65832
|
isInvalidColorToken,
|
|
65654
|
-
isLegacyMetadataLine,
|
|
65655
65833
|
isRecognizedColorName,
|
|
65656
65834
|
isSequenceBlock,
|
|
65657
65835
|
isSequenceNote,
|
|
@@ -65688,7 +65866,6 @@ export {
|
|
|
65688
65866
|
mapExportDimensions,
|
|
65689
65867
|
mapNeutralLandColor,
|
|
65690
65868
|
measurePertAnalysisBlock,
|
|
65691
|
-
migrateContent,
|
|
65692
65869
|
mix,
|
|
65693
65870
|
mulberry32,
|
|
65694
65871
|
nearestNamedColor,
|
|
@@ -65816,7 +65993,6 @@ export {
|
|
|
65816
65993
|
tidewaterPalette,
|
|
65817
65994
|
tint,
|
|
65818
65995
|
tokyoNightPalette,
|
|
65819
|
-
transformLine,
|
|
65820
65996
|
truncateBareUrl,
|
|
65821
65997
|
parseDgmo as validate,
|
|
65822
65998
|
validateComputed,
|