@diagrammo/dgmo 0.39.0 → 0.41.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/dist/advanced.cjs +372 -162
- package/dist/advanced.js +372 -162
- package/dist/auto.cjs +373 -163
- package/dist/auto.js +92 -92
- package/dist/auto.mjs +373 -163
- package/dist/cli.cjs +115 -115
- package/dist/index.cjs +550 -217
- package/dist/index.js +550 -217
- package/docs/language-reference.md +17 -0
- package/gallery/fixtures/block.dgmo +16 -0
- package/gallery/fixtures/event-line.dgmo +26 -0
- package/package.json +1 -1
- package/src/diagnostics.ts +0 -0
- package/src/echarts.ts +5 -0
- package/src/error-card.ts +200 -0
- package/src/event-line/parser.ts +155 -55
- package/src/event-line/renderer.ts +350 -139
- package/src/index.ts +7 -30
- package/src/journey-map/renderer.ts +50 -18
package/dist/index.js
CHANGED
|
@@ -103,7 +103,7 @@ function vennAliasKeywordRemovedMessage(args) {
|
|
|
103
103
|
return `Venn 'alias' keyword was removed. Use 'as' instead \u2014 '${args.name} as ${args.alias}'.`;
|
|
104
104
|
}
|
|
105
105
|
function pipeOperatorRemovedMessage() {
|
|
106
|
-
return `'|'
|
|
106
|
+
return `'|' is no longer metadata syntax \u2014 write metadata inline as 'key: value' (e.g. "Name color: red"), or remove the '|'.`;
|
|
107
107
|
}
|
|
108
108
|
function ganttBarePercentRemovedMessage(percent) {
|
|
109
109
|
return `Bare-percent progress shorthand '| ${percent}' was removed. Use 'progress: ${percent.replace(/%$/, "")}' (integer 0\u2013100, no '%').`;
|
|
@@ -13629,7 +13629,8 @@ function buildScatterOption(parsed, palette, isDark, textColor, axisLineColor, g
|
|
|
13629
13629
|
solid: parsed.solidFill === true
|
|
13630
13630
|
}),
|
|
13631
13631
|
borderColor: catColor,
|
|
13632
|
-
borderWidth: CHART_BORDER_WIDTH
|
|
13632
|
+
borderWidth: CHART_BORDER_WIDTH,
|
|
13633
|
+
opacity: SCATTER_FILL_OPACITY
|
|
13633
13634
|
},
|
|
13634
13635
|
label: labelConfig,
|
|
13635
13636
|
emphasis: emphasisConfig,
|
|
@@ -13656,6 +13657,7 @@ function buildScatterOption(parsed, palette, isDark, textColor, axisLineColor, g
|
|
|
13656
13657
|
{
|
|
13657
13658
|
type: "scatter",
|
|
13658
13659
|
data,
|
|
13660
|
+
itemStyle: { opacity: SCATTER_FILL_OPACITY },
|
|
13659
13661
|
label: labelConfig,
|
|
13660
13662
|
emphasis: emphasisConfig,
|
|
13661
13663
|
blur: blurConfig
|
|
@@ -14961,7 +14963,7 @@ async function renderExtendedChartForExport(content, theme, palette) {
|
|
|
14961
14963
|
chart.dispose();
|
|
14962
14964
|
}
|
|
14963
14965
|
}
|
|
14964
|
-
var EMPHASIS_SELF, EMPHASIS_SERIES, BLUR_DIM, EMPHASIS_LINE, CHART_BASE, CHART_BORDER_WIDTH, VALID_EXTENDED_TYPES, KNOWN_EXTENDED_OPTIONS, EXTENDED_CHART_DOORS, FIT_PADDING, OFFSCREEN, fitStackedLabelToSegment, ECHART_EXPORT_WIDTH, ECHART_EXPORT_HEIGHT, STANDARD_CHART_TYPES;
|
|
14966
|
+
var EMPHASIS_SELF, EMPHASIS_SERIES, BLUR_DIM, EMPHASIS_LINE, CHART_BASE, CHART_BORDER_WIDTH, SCATTER_FILL_OPACITY, VALID_EXTENDED_TYPES, KNOWN_EXTENDED_OPTIONS, EXTENDED_CHART_DOORS, FIT_PADDING, OFFSCREEN, fitStackedLabelToSegment, ECHART_EXPORT_WIDTH, ECHART_EXPORT_HEIGHT, STANDARD_CHART_TYPES;
|
|
14965
14967
|
var init_echarts = __esm({
|
|
14966
14968
|
"src/echarts.ts"() {
|
|
14967
14969
|
"use strict";
|
|
@@ -15015,6 +15017,7 @@ var init_echarts = __esm({
|
|
|
15015
15017
|
tooltip: { show: false }
|
|
15016
15018
|
};
|
|
15017
15019
|
CHART_BORDER_WIDTH = 2;
|
|
15020
|
+
SCATTER_FILL_OPACITY = 0.65;
|
|
15018
15021
|
VALID_EXTENDED_TYPES = /* @__PURE__ */ new Set([
|
|
15019
15022
|
"sankey",
|
|
15020
15023
|
"chord",
|
|
@@ -15112,6 +15115,8 @@ function parseEventLine(content, palette) {
|
|
|
15112
15115
|
let currentTagGroup = null;
|
|
15113
15116
|
let currentEvent = null;
|
|
15114
15117
|
let currentEra = null;
|
|
15118
|
+
let eraIndent = -1;
|
|
15119
|
+
let currentEventIndent = 0;
|
|
15115
15120
|
const aliasMap = /* @__PURE__ */ new Map();
|
|
15116
15121
|
for (let i = 0; i < lines.length; i++) {
|
|
15117
15122
|
const line11 = lines[i];
|
|
@@ -15186,52 +15191,15 @@ function parseEventLine(content, palette) {
|
|
|
15186
15191
|
});
|
|
15187
15192
|
continue;
|
|
15188
15193
|
}
|
|
15189
|
-
if (indent >
|
|
15190
|
-
if (!currentEvent) {
|
|
15191
|
-
pushWarning(
|
|
15192
|
-
lineNumber,
|
|
15193
|
-
`Indented description "${trimmed}" has no event above it \u2014 add an event line first. (\xA728)`
|
|
15194
|
-
);
|
|
15195
|
-
continue;
|
|
15196
|
-
}
|
|
15194
|
+
if (currentEvent && indent > currentEventIndent) {
|
|
15197
15195
|
const descLine = trimmed.startsWith("- ") ? `\u2022 ${trimmed.substring(2)}` : trimmed;
|
|
15198
15196
|
currentEvent.description.push(descLine);
|
|
15199
15197
|
continue;
|
|
15200
15198
|
}
|
|
15201
|
-
currentTagGroup = null;
|
|
15202
|
-
if (trimmed.toLowerCase() === "no-scale") {
|
|
15203
|
-
options.scale = false;
|
|
15204
|
-
continue;
|
|
15205
|
-
}
|
|
15206
|
-
const sideMatch = trimmed.match(SIDE_RE);
|
|
15207
|
-
if (sideMatch) {
|
|
15208
|
-
options.side = sideMatch[1].toLowerCase();
|
|
15209
|
-
continue;
|
|
15210
|
-
}
|
|
15211
|
-
if (trimmed.toLowerCase() === "no-box") {
|
|
15212
|
-
options.noBox = true;
|
|
15213
|
-
continue;
|
|
15214
|
-
}
|
|
15215
|
-
if (trimmed.toLowerCase() === "no-legend") {
|
|
15216
|
-
options.noLegend = true;
|
|
15217
|
-
continue;
|
|
15218
|
-
}
|
|
15219
|
-
const dirMatch = trimmed.match(DIRECTION_RE);
|
|
15220
|
-
if (dirMatch) {
|
|
15221
|
-
const dir = dirMatch[1].toUpperCase();
|
|
15222
|
-
if (dir !== "LR") {
|
|
15223
|
-
pushWarning(
|
|
15224
|
-
lineNumber,
|
|
15225
|
-
`event-line is horizontal-only in v1; \`direction ${dir}\` (vertical orientation) is a fast-follow.`,
|
|
15226
|
-
EVENT_LINE_DIAGNOSTIC_CODES.UNSUPPORTED
|
|
15227
|
-
);
|
|
15228
|
-
}
|
|
15229
|
-
continue;
|
|
15230
|
-
}
|
|
15231
|
-
if (tryParseSharedOption(trimmed, sharedOptions)) continue;
|
|
15232
15199
|
const eraMatch = trimmed.match(ERA_RE);
|
|
15233
15200
|
if (eraMatch) {
|
|
15234
15201
|
contentStarted = true;
|
|
15202
|
+
currentTagGroup = null;
|
|
15235
15203
|
currentEvent = null;
|
|
15236
15204
|
const name = eraMatch[1].trim();
|
|
15237
15205
|
let rest = (eraMatch[2] ?? "").trim();
|
|
@@ -15255,16 +15223,52 @@ function parseEventLine(content, palette) {
|
|
|
15255
15223
|
const era = { name, color, collapsed, lineNumber };
|
|
15256
15224
|
result.eras.push(era);
|
|
15257
15225
|
currentEra = name;
|
|
15226
|
+
eraIndent = indent;
|
|
15258
15227
|
continue;
|
|
15259
15228
|
}
|
|
15260
|
-
if (
|
|
15261
|
-
|
|
15262
|
-
|
|
15263
|
-
|
|
15264
|
-
|
|
15265
|
-
|
|
15266
|
-
|
|
15229
|
+
if (indent === 0) {
|
|
15230
|
+
currentTagGroup = null;
|
|
15231
|
+
if (trimmed.toLowerCase() === "no-scale") {
|
|
15232
|
+
options.scale = false;
|
|
15233
|
+
continue;
|
|
15234
|
+
}
|
|
15235
|
+
const sideMatch = trimmed.match(SIDE_RE);
|
|
15236
|
+
if (sideMatch) {
|
|
15237
|
+
options.side = sideMatch[1].toLowerCase();
|
|
15238
|
+
continue;
|
|
15239
|
+
}
|
|
15240
|
+
if (trimmed.toLowerCase() === "no-box") {
|
|
15241
|
+
options.noBox = true;
|
|
15242
|
+
continue;
|
|
15243
|
+
}
|
|
15244
|
+
if (trimmed.toLowerCase() === "no-legend") {
|
|
15245
|
+
options.noLegend = true;
|
|
15246
|
+
continue;
|
|
15247
|
+
}
|
|
15248
|
+
const dirMatch = trimmed.match(DIRECTION_RE);
|
|
15249
|
+
if (dirMatch) {
|
|
15250
|
+
const dir = dirMatch[1].toUpperCase();
|
|
15251
|
+
if (dir !== "LR") {
|
|
15252
|
+
pushWarning(
|
|
15253
|
+
lineNumber,
|
|
15254
|
+
`event-line is horizontal-only in v1; \`direction ${dir}\` (vertical orientation) is a fast-follow.`,
|
|
15255
|
+
EVENT_LINE_DIAGNOSTIC_CODES.UNSUPPORTED
|
|
15256
|
+
);
|
|
15257
|
+
}
|
|
15258
|
+
continue;
|
|
15259
|
+
}
|
|
15260
|
+
if (tryParseSharedOption(trimmed, sharedOptions)) continue;
|
|
15261
|
+
if (SECTION_SEAM_RE.test(trimmed)) {
|
|
15262
|
+
pushWarning(
|
|
15263
|
+
lineNumber,
|
|
15264
|
+
"Group events with `[Name]` era brackets (\xA728.6a), not `section`.",
|
|
15265
|
+
EVENT_LINE_DIAGNOSTIC_CODES.UNSUPPORTED
|
|
15266
|
+
);
|
|
15267
|
+
continue;
|
|
15268
|
+
}
|
|
15267
15269
|
}
|
|
15270
|
+
const inEra = currentEra !== null && indent > eraIndent;
|
|
15271
|
+
if (!inEra) currentEra = null;
|
|
15268
15272
|
contentStarted = true;
|
|
15269
15273
|
const event = parseEventHeader(
|
|
15270
15274
|
trimmed,
|
|
@@ -15276,6 +15280,7 @@ function parseEventLine(content, palette) {
|
|
|
15276
15280
|
);
|
|
15277
15281
|
result.events.push(event);
|
|
15278
15282
|
currentEvent = event;
|
|
15283
|
+
currentEventIndent = indent;
|
|
15279
15284
|
}
|
|
15280
15285
|
options.noTitle = sharedOptions["no-title"] === "on";
|
|
15281
15286
|
finalizeAutoTagColors(result.tagGroups, palette);
|
|
@@ -15290,8 +15295,61 @@ function parseEventLine(content, palette) {
|
|
|
15290
15295
|
EVENT_LINE_DIAGNOSTIC_CODES.NO_EVENTS
|
|
15291
15296
|
);
|
|
15292
15297
|
}
|
|
15298
|
+
if (options.scale) {
|
|
15299
|
+
validateEraDateOrder(result.events, result.eras, pushWarning);
|
|
15300
|
+
}
|
|
15293
15301
|
return result;
|
|
15294
15302
|
}
|
|
15303
|
+
function validateEraDateOrder(events, eras, pushWarning) {
|
|
15304
|
+
if (eras.length < 2) return;
|
|
15305
|
+
const order = new Map(eras.map((e, i) => [e.name, i]));
|
|
15306
|
+
const dated = events.filter(
|
|
15307
|
+
(e) => e.dateValue !== null && e.era !== null && order.has(e.era)
|
|
15308
|
+
);
|
|
15309
|
+
if (dated.length === 0) return;
|
|
15310
|
+
const perEra = /* @__PURE__ */ new Map();
|
|
15311
|
+
for (const ev of dated) {
|
|
15312
|
+
const idx = order.get(ev.era);
|
|
15313
|
+
const cur = perEra.get(idx);
|
|
15314
|
+
if (!cur) {
|
|
15315
|
+
perEra.set(idx, { min: ev, max: ev });
|
|
15316
|
+
} else {
|
|
15317
|
+
if (ev.dateValue < cur.min.dateValue) cur.min = ev;
|
|
15318
|
+
if (ev.dateValue > cur.max.dateValue) cur.max = ev;
|
|
15319
|
+
}
|
|
15320
|
+
}
|
|
15321
|
+
const n = eras.length;
|
|
15322
|
+
const prefixMax = new Array(n).fill(null);
|
|
15323
|
+
const suffixMin = new Array(n).fill(null);
|
|
15324
|
+
for (let k = 1; k < n; k++) {
|
|
15325
|
+
const prev = perEra.get(k - 1)?.max ?? null;
|
|
15326
|
+
const carried = prefixMax[k - 1] ?? null;
|
|
15327
|
+
prefixMax[k] = prev && (!carried || prev.dateValue > carried.dateValue) ? prev : carried;
|
|
15328
|
+
}
|
|
15329
|
+
for (let k = n - 2; k >= 0; k--) {
|
|
15330
|
+
const next = perEra.get(k + 1)?.min ?? null;
|
|
15331
|
+
const carried = suffixMin[k + 1] ?? null;
|
|
15332
|
+
suffixMin[k] = next && (!carried || next.dateValue < carried.dateValue) ? next : carried;
|
|
15333
|
+
}
|
|
15334
|
+
for (const ev of dated) {
|
|
15335
|
+
const k = order.get(ev.era);
|
|
15336
|
+
const ahead = suffixMin[k];
|
|
15337
|
+
const behind = prefixMax[k];
|
|
15338
|
+
if (ahead && ev.dateValue > ahead.dateValue) {
|
|
15339
|
+
pushWarning(
|
|
15340
|
+
ev.lineNumber,
|
|
15341
|
+
`"${ev.label}" (${ev.date}) is in era "${ev.era}" but dated after era "${ahead.era}" begins (${ahead.date}). event-line eras run left-to-right by date \u2014 fix the date or move it to the right era, or their brackets will overlap.`,
|
|
15342
|
+
EVENT_LINE_DIAGNOSTIC_CODES.ERA_DATE_ORDER
|
|
15343
|
+
);
|
|
15344
|
+
} else if (behind && ev.dateValue < behind.dateValue) {
|
|
15345
|
+
pushWarning(
|
|
15346
|
+
ev.lineNumber,
|
|
15347
|
+
`"${ev.label}" (${ev.date}) is in era "${ev.era}" but dated before era "${behind.era}" ends (${behind.date}). event-line eras run left-to-right by date \u2014 fix the date or move it to the right era, or their brackets will overlap.`,
|
|
15348
|
+
EVENT_LINE_DIAGNOSTIC_CODES.ERA_DATE_ORDER
|
|
15349
|
+
);
|
|
15350
|
+
}
|
|
15351
|
+
}
|
|
15352
|
+
}
|
|
15295
15353
|
function parseEventHeader(trimmed, lineNumber, era, aliasMap, diagnostics, pushWarning) {
|
|
15296
15354
|
let date = null;
|
|
15297
15355
|
let dateValue = null;
|
|
@@ -15358,7 +15416,8 @@ var init_parser13 = __esm({
|
|
|
15358
15416
|
EVENT_LINE_DIAGNOSTIC_CODES = {
|
|
15359
15417
|
NO_EVENTS: "E_EVENT_LINE_NO_EVENTS",
|
|
15360
15418
|
BAD_DATE: "E_EVENT_LINE_BAD_DATE",
|
|
15361
|
-
UNSUPPORTED: "E_EVENT_LINE_UNSUPPORTED"
|
|
15419
|
+
UNSUPPORTED: "E_EVENT_LINE_UNSUPPORTED",
|
|
15420
|
+
ERA_DATE_ORDER: "E_EVENT_LINE_ERA_DATE_ORDER"
|
|
15362
15421
|
};
|
|
15363
15422
|
NON_ISO_DATE_RE = /^\d{1,4}[/.]\d/;
|
|
15364
15423
|
SIDE_RE = /^side\s+(above|below|alternate)\b/i;
|
|
@@ -26295,9 +26354,6 @@ function renderEventLine(container, parsed, palette, isDark, onClickItem, export
|
|
|
26295
26354
|
const hasExpandedEra = parsed.events.some(
|
|
26296
26355
|
(e) => e.era && eraByName.has(e.era) && !collapsedSet.has(e.era)
|
|
26297
26356
|
);
|
|
26298
|
-
const anyCollapsed = parsed.events.some(
|
|
26299
|
-
(e) => e.era && collapsedSet.has(e.era)
|
|
26300
|
-
);
|
|
26301
26357
|
const sideOpt = parsed.options.side;
|
|
26302
26358
|
const alternate = sideOpt === "alternate";
|
|
26303
26359
|
const eraSide = alternate ? "below" : sideOpt === "above" ? "below" : "above";
|
|
@@ -26364,7 +26420,8 @@ function renderEventLine(container, parsed, palette, isDark, onClickItem, export
|
|
|
26364
26420
|
x: 0,
|
|
26365
26421
|
side,
|
|
26366
26422
|
lane: 0,
|
|
26367
|
-
left: 0
|
|
26423
|
+
left: 0,
|
|
26424
|
+
spanHalf: 0
|
|
26368
26425
|
};
|
|
26369
26426
|
}
|
|
26370
26427
|
const era = slot.era;
|
|
@@ -26377,19 +26434,19 @@ function renderEventLine(container, parsed, palette, isDark, onClickItem, export
|
|
|
26377
26434
|
palette.textOnFillLight,
|
|
26378
26435
|
palette.textOnFillDark
|
|
26379
26436
|
);
|
|
26380
|
-
|
|
26381
|
-
|
|
26382
|
-
const
|
|
26437
|
+
let spanLo = null;
|
|
26438
|
+
let spanHi = null;
|
|
26439
|
+
for (const m of slot.members) {
|
|
26440
|
+
if (m.dateValue === null) continue;
|
|
26441
|
+
if (spanLo === null || m.dateValue < spanLo) spanLo = m.dateValue;
|
|
26442
|
+
if (spanHi === null || m.dateValue > spanHi) spanHi = m.dateValue;
|
|
26443
|
+
}
|
|
26444
|
+
const repDateValue = spanLo !== null && spanHi !== null ? (spanLo + spanHi) / 2 : null;
|
|
26445
|
+
const memberStrs = slot.members.map(
|
|
26383
26446
|
(m) => `\u2022 ${m.date ? `${m.date} ` : ""}${m.label}`
|
|
26384
26447
|
);
|
|
26385
|
-
const bulletColors =
|
|
26448
|
+
const bulletColors = slot.members.map(eventColor);
|
|
26386
26449
|
const lines = wrapDescription(memberStrs, charsPerLine);
|
|
26387
|
-
if (overflow) {
|
|
26388
|
-
lines.push({
|
|
26389
|
-
text: `+${slot.members.length - (ERA_MEMBER_MAX - 1)} more`,
|
|
26390
|
-
kind: "plain"
|
|
26391
|
-
});
|
|
26392
|
-
}
|
|
26393
26450
|
return {
|
|
26394
26451
|
kind: "era",
|
|
26395
26452
|
event: null,
|
|
@@ -26397,7 +26454,7 @@ function renderEventLine(container, parsed, palette, isDark, onClickItem, export
|
|
|
26397
26454
|
members: slot.members,
|
|
26398
26455
|
label: era.name,
|
|
26399
26456
|
date: null,
|
|
26400
|
-
dateValue:
|
|
26457
|
+
dateValue: repDateValue,
|
|
26401
26458
|
lineNumber: era.lineNumber,
|
|
26402
26459
|
eraName: era.name,
|
|
26403
26460
|
color: solid,
|
|
@@ -26409,87 +26466,189 @@ function renderEventLine(container, parsed, palette, isDark, onClickItem, export
|
|
|
26409
26466
|
x: 0,
|
|
26410
26467
|
side,
|
|
26411
26468
|
lane: 0,
|
|
26412
|
-
left: 0
|
|
26469
|
+
left: 0,
|
|
26470
|
+
spanHalf: 0
|
|
26413
26471
|
};
|
|
26414
26472
|
});
|
|
26415
|
-
const scaled = parsed.options.scale &&
|
|
26473
|
+
const scaled = parsed.options.scale && placed.every((p) => p.dateValue !== null);
|
|
26416
26474
|
const innerW = width - H_MARGIN * 2;
|
|
26417
|
-
|
|
26418
|
-
|
|
26419
|
-
|
|
26420
|
-
|
|
26421
|
-
|
|
26422
|
-
|
|
26475
|
+
const MIN_DOT_GAP = 16;
|
|
26476
|
+
const STRETCH_CAP = 8;
|
|
26477
|
+
const COLLAPSE_W = 64;
|
|
26478
|
+
const SEG_GAP = 16;
|
|
26479
|
+
const segments = [];
|
|
26480
|
+
let run = [];
|
|
26481
|
+
const flushRun = () => {
|
|
26482
|
+
if (!run.length) return;
|
|
26483
|
+
const ds = run.map((e) => e.dateValue);
|
|
26484
|
+
segments.push({
|
|
26485
|
+
kind: "run",
|
|
26486
|
+
events: run,
|
|
26487
|
+
lo: Math.min(...ds),
|
|
26488
|
+
hi: Math.max(...ds)
|
|
26423
26489
|
});
|
|
26424
|
-
|
|
26425
|
-
|
|
26426
|
-
|
|
26427
|
-
|
|
26428
|
-
|
|
26429
|
-
|
|
26430
|
-
|
|
26490
|
+
run = [];
|
|
26491
|
+
};
|
|
26492
|
+
for (const p of placed) {
|
|
26493
|
+
if (p.kind === "era") {
|
|
26494
|
+
flushRun();
|
|
26495
|
+
segments.push({ kind: "capsule", p });
|
|
26496
|
+
} else {
|
|
26497
|
+
run.push(p);
|
|
26498
|
+
}
|
|
26499
|
+
}
|
|
26500
|
+
flushRun();
|
|
26501
|
+
const totalRunTime = segments.reduce(
|
|
26502
|
+
(s, seg) => s + (seg.kind === "run" ? seg.hi - seg.lo : 0),
|
|
26503
|
+
0
|
|
26504
|
+
);
|
|
26505
|
+
const place = (stretch) => {
|
|
26506
|
+
if (scaled) {
|
|
26507
|
+
const pxPerUnit = totalRunTime > 0 ? innerW * stretch / totalRunTime : 0;
|
|
26508
|
+
let cursor = H_MARGIN;
|
|
26509
|
+
for (const seg of segments) {
|
|
26510
|
+
if (seg.kind === "capsule") {
|
|
26511
|
+
seg.p.x = cursor + COLLAPSE_W / 2;
|
|
26512
|
+
seg.p.spanHalf = COLLAPSE_W / 2;
|
|
26513
|
+
cursor += COLLAPSE_W + SEG_GAP;
|
|
26514
|
+
} else {
|
|
26515
|
+
for (const e of seg.events) {
|
|
26516
|
+
e.x = cursor + (e.dateValue - seg.lo) * pxPerUnit;
|
|
26517
|
+
e.spanHalf = 0;
|
|
26518
|
+
}
|
|
26519
|
+
cursor += (seg.hi - seg.lo) * pxPerUnit + SEG_GAP;
|
|
26520
|
+
}
|
|
26521
|
+
}
|
|
26522
|
+
let prevX = -Infinity;
|
|
26523
|
+
let prevVal = null;
|
|
26524
|
+
for (const p of [...placed].sort((a, b) => a.x - b.x)) {
|
|
26525
|
+
if (p.kind === "era") {
|
|
26526
|
+
prevX = p.x + p.spanHalf;
|
|
26527
|
+
prevVal = null;
|
|
26528
|
+
continue;
|
|
26529
|
+
}
|
|
26530
|
+
if (p.dateValue === prevVal) {
|
|
26531
|
+
p.x = prevX;
|
|
26532
|
+
continue;
|
|
26533
|
+
}
|
|
26534
|
+
if (p.x < prevX + MIN_DOT_GAP) p.x = prevX + MIN_DOT_GAP;
|
|
26535
|
+
prevX = p.x;
|
|
26536
|
+
prevVal = p.dateValue;
|
|
26431
26537
|
}
|
|
26432
|
-
|
|
26433
|
-
|
|
26434
|
-
|
|
26538
|
+
} else {
|
|
26539
|
+
placed.forEach((p) => {
|
|
26540
|
+
p.spanHalf = 0;
|
|
26541
|
+
});
|
|
26542
|
+
const n = placed.length;
|
|
26543
|
+
const spacing = n > 1 ? Math.max(MIN_SPACING, innerW / (n - 1)) : 0;
|
|
26544
|
+
placed.forEach((p, i) => {
|
|
26545
|
+
p.x = H_MARGIN + i * spacing;
|
|
26546
|
+
});
|
|
26435
26547
|
}
|
|
26548
|
+
for (const side of ["above", "below"]) {
|
|
26549
|
+
const arr = placed.filter((p) => p.side === side).sort((a, b) => a.x - b.x);
|
|
26550
|
+
const laneRight = [];
|
|
26551
|
+
for (let i = 0; i < arr.length; i++) {
|
|
26552
|
+
const p = arr[i];
|
|
26553
|
+
const next = arr[i + 1];
|
|
26554
|
+
const crowdedRight = !!next && next.x - p.x < CARD_W + FAN_GAP;
|
|
26555
|
+
const preferred = crowdedRight ? p.x - CARD_W + CARD_INSET : p.x - CARD_W / 2;
|
|
26556
|
+
const maxLeft = p.x - CARD_INSET;
|
|
26557
|
+
const minLeft = p.x - CARD_W + CARD_INSET;
|
|
26558
|
+
let lane = laneRight.length;
|
|
26559
|
+
let left = Math.max(preferred, minLeft);
|
|
26560
|
+
for (let l = 0; l < laneRight.length; l++) {
|
|
26561
|
+
const want = Math.max(preferred, laneRight[l] + FAN_GAP, minLeft);
|
|
26562
|
+
if (want <= maxLeft) {
|
|
26563
|
+
lane = l;
|
|
26564
|
+
left = want;
|
|
26565
|
+
break;
|
|
26566
|
+
}
|
|
26567
|
+
}
|
|
26568
|
+
p.lane = lane;
|
|
26569
|
+
p.left = Math.max(6, left);
|
|
26570
|
+
laneRight[lane] = p.left + CARD_W;
|
|
26571
|
+
}
|
|
26572
|
+
}
|
|
26573
|
+
};
|
|
26574
|
+
const derive = () => {
|
|
26575
|
+
const contentW2 = Math.max(
|
|
26576
|
+
width,
|
|
26577
|
+
Math.max(...placed.map((p) => p.x + p.spanHalf)) + H_MARGIN,
|
|
26578
|
+
Math.max(...placed.map((p) => p.left + CARD_W)) + 6
|
|
26579
|
+
);
|
|
26580
|
+
const laneOffset = { above: [], below: [] };
|
|
26581
|
+
for (const side of ["above", "below"]) {
|
|
26582
|
+
const laneH = [];
|
|
26583
|
+
for (const p of placed) {
|
|
26584
|
+
if (p.side !== side) continue;
|
|
26585
|
+
laneH[p.lane] = Math.max(laneH[p.lane] ?? 0, p.cardH);
|
|
26586
|
+
}
|
|
26587
|
+
const off = [];
|
|
26588
|
+
let acc = 0;
|
|
26589
|
+
for (let l = 0; l < laneH.length; l++) {
|
|
26590
|
+
off[l] = acc;
|
|
26591
|
+
acc += (laneH[l] ?? 0) + LANE_GAP;
|
|
26592
|
+
}
|
|
26593
|
+
laneOffset[side] = off;
|
|
26594
|
+
}
|
|
26595
|
+
const laneNear2 = (p) => (p.side === "above" ? LEADER_ABOVE : LEADER_BELOW) + (laneOffset[p.side][p.lane] ?? 0);
|
|
26596
|
+
const ext = (side) => Math.max(
|
|
26597
|
+
0,
|
|
26598
|
+
...placed.filter((p) => p.side === side).map((p) => laneNear2(p) + p.cardH)
|
|
26599
|
+
);
|
|
26600
|
+
const dateAbove = placed.some((p) => p.side === "below" && p.date);
|
|
26601
|
+
const dateBelow = placed.some((p) => p.side === "above" && p.date);
|
|
26602
|
+
const contentAbove = Math.max(
|
|
26603
|
+
ext("above"),
|
|
26604
|
+
dateAbove ? DATE_OFFSET + 10 : 0
|
|
26605
|
+
);
|
|
26606
|
+
const contentBelow = Math.max(
|
|
26607
|
+
ext("below"),
|
|
26608
|
+
dateBelow ? DATE_OFFSET + 10 : 0
|
|
26609
|
+
);
|
|
26610
|
+
const aboveExt = contentAbove + (hasExpandedEra && eraSide === "above" ? ERA_BLOCK : 0);
|
|
26611
|
+
const belowExt = contentBelow + (hasExpandedEra && eraSide === "below" ? ERA_BLOCK : 0);
|
|
26612
|
+
const TOP_PAD = 14;
|
|
26613
|
+
const BOT_PAD = 14;
|
|
26614
|
+
const spineY2 = topUsed + TOP_PAD + aboveExt;
|
|
26615
|
+
const eraBaseY2 = eraSide === "above" ? spineY2 - (contentAbove + 14) : spineY2 + (contentBelow + 14);
|
|
26616
|
+
const contentH = spineY2 + belowExt + BOT_PAD;
|
|
26617
|
+
const totalH2 = Math.max(heightHint, contentH);
|
|
26618
|
+
return { contentW: contentW2, contentH, totalH: totalH2, spineY: spineY2, eraBaseY: eraBaseY2, laneNear: laneNear2 };
|
|
26619
|
+
};
|
|
26620
|
+
const envStretch = Number(
|
|
26621
|
+
globalThis.process?.env?.["DGMO_EVT_STRETCH"]
|
|
26622
|
+
);
|
|
26623
|
+
let layout;
|
|
26624
|
+
if (Number.isFinite(envStretch) && envStretch > 0) {
|
|
26625
|
+
place(envStretch);
|
|
26626
|
+
layout = derive();
|
|
26436
26627
|
} else {
|
|
26437
|
-
|
|
26438
|
-
|
|
26439
|
-
|
|
26440
|
-
|
|
26441
|
-
|
|
26442
|
-
|
|
26443
|
-
|
|
26444
|
-
|
|
26445
|
-
|
|
26446
|
-
|
|
26447
|
-
|
|
26448
|
-
|
|
26449
|
-
|
|
26450
|
-
|
|
26451
|
-
|
|
26452
|
-
|
|
26453
|
-
|
|
26454
|
-
let left = Math.max(preferred, minLeft);
|
|
26455
|
-
for (let l = 0; l < laneRight.length; l++) {
|
|
26456
|
-
const want = Math.max(preferred, laneRight[l] + FAN_GAP, minLeft);
|
|
26457
|
-
if (want <= maxLeft) {
|
|
26458
|
-
lane = l;
|
|
26459
|
-
left = want;
|
|
26460
|
-
break;
|
|
26628
|
+
place(1);
|
|
26629
|
+
layout = derive();
|
|
26630
|
+
const panelAspect = width / heightHint;
|
|
26631
|
+
const aspectOf = (l) => l.contentW / l.contentH;
|
|
26632
|
+
if (scaled && layout.contentH > heightHint && aspectOf(layout) < panelAspect) {
|
|
26633
|
+
place(STRETCH_CAP);
|
|
26634
|
+
const capped = derive();
|
|
26635
|
+
if (aspectOf(capped) <= panelAspect) {
|
|
26636
|
+
layout = capped;
|
|
26637
|
+
} else {
|
|
26638
|
+
let loF = 1;
|
|
26639
|
+
let hiF = STRETCH_CAP;
|
|
26640
|
+
for (let it = 0; it < 8; it++) {
|
|
26641
|
+
const mid = (loF + hiF) / 2;
|
|
26642
|
+
place(mid);
|
|
26643
|
+
if (aspectOf(derive()) >= panelAspect) hiF = mid;
|
|
26644
|
+
else loF = mid;
|
|
26461
26645
|
}
|
|
26646
|
+
place(hiF);
|
|
26647
|
+
layout = derive();
|
|
26462
26648
|
}
|
|
26463
|
-
p.lane = lane;
|
|
26464
|
-
p.left = Math.max(6, left);
|
|
26465
|
-
laneRight[lane] = p.left + CARD_W;
|
|
26466
26649
|
}
|
|
26467
26650
|
}
|
|
26468
|
-
const contentW =
|
|
26469
|
-
width,
|
|
26470
|
-
Math.max(...placed.map((p) => p.x)) + H_MARGIN,
|
|
26471
|
-
Math.max(...placed.map((p) => p.left + CARD_W)) + 6
|
|
26472
|
-
);
|
|
26473
|
-
const rowGap = (side) => Math.max(0, ...placed.filter((p) => p.side === side).map((p) => p.cardH)) + LANE_GAP;
|
|
26474
|
-
const rowGapA = rowGap("above");
|
|
26475
|
-
const rowGapB = rowGap("below");
|
|
26476
|
-
const ext = (side) => Math.max(
|
|
26477
|
-
0,
|
|
26478
|
-
...placed.filter((p) => p.side === side).map(
|
|
26479
|
-
(p) => (side === "above" ? LEADER_ABOVE : LEADER_BELOW) + p.lane * (side === "above" ? rowGapA : rowGapB) + p.cardH
|
|
26480
|
-
)
|
|
26481
|
-
);
|
|
26482
|
-
const dateAbove = placed.some((p) => p.side === "below" && p.date);
|
|
26483
|
-
const dateBelow = placed.some((p) => p.side === "above" && p.date);
|
|
26484
|
-
const contentAbove = Math.max(ext("above"), dateAbove ? DATE_OFFSET + 10 : 0);
|
|
26485
|
-
const contentBelow = Math.max(ext("below"), dateBelow ? DATE_OFFSET + 10 : 0);
|
|
26486
|
-
const aboveExt = contentAbove + (hasExpandedEra && eraSide === "above" ? ERA_BLOCK : 0);
|
|
26487
|
-
const belowExt = contentBelow + (hasExpandedEra && eraSide === "below" ? ERA_BLOCK : 0);
|
|
26488
|
-
const TOP_PAD = 14;
|
|
26489
|
-
const BOT_PAD = 14;
|
|
26490
|
-
const spineY = topUsed + TOP_PAD + aboveExt;
|
|
26491
|
-
const eraBaseY = eraSide === "above" ? spineY - (contentAbove + 14) : spineY + (contentBelow + 14);
|
|
26492
|
-
const totalH = Math.max(heightHint, spineY + belowExt + BOT_PAD);
|
|
26651
|
+
const { contentW, totalH, spineY, eraBaseY, laneNear } = layout;
|
|
26493
26652
|
const svg = d3Selection6.select(container).append("svg").attr("width", contentW).attr("height", totalH).attr("viewBox", `0 0 ${contentW} ${totalH}`).attr("preserveAspectRatio", "xMidYMin meet").attr("xmlns", "http://www.w3.org/2000/svg").style("font-family", FONT_FAMILY);
|
|
26494
26653
|
svg.append("rect").attr("width", contentW).attr("height", totalH).attr("fill", palette.bg);
|
|
26495
26654
|
if (showTitle) {
|
|
@@ -26517,12 +26676,11 @@ function renderEventLine(container, parsed, palette, isDark, onClickItem, export
|
|
|
26517
26676
|
activeGroup
|
|
26518
26677
|
});
|
|
26519
26678
|
}
|
|
26520
|
-
const
|
|
26521
|
-
const
|
|
26522
|
-
const x1 = Math.max(...xs);
|
|
26679
|
+
const x0 = Math.min(...placed.map((p) => p.x - p.spanHalf));
|
|
26680
|
+
const x1 = Math.max(...placed.map((p) => p.x + p.spanHalf));
|
|
26523
26681
|
svg.append("line").attr("x1", x0 - 20).attr("y1", spineY).attr("x2", x1 + 20).attr("y2", spineY).attr("stroke", palette.text).attr("stroke-width", 2.5).attr("stroke-linecap", "round");
|
|
26524
26682
|
const geo = placed.map((p) => {
|
|
26525
|
-
const near = p.side === "above" ? spineY -
|
|
26683
|
+
const near = p.side === "above" ? spineY - laneNear(p) : spineY + laneNear(p);
|
|
26526
26684
|
const top = p.side === "above" ? near - p.cardH : near;
|
|
26527
26685
|
return { p, near, top };
|
|
26528
26686
|
});
|
|
@@ -26634,7 +26792,7 @@ function renderEventLine(container, parsed, palette, isDark, onClickItem, export
|
|
|
26634
26792
|
for (const p of placed) {
|
|
26635
26793
|
if (p.kind === "era") {
|
|
26636
26794
|
const col = p.color;
|
|
26637
|
-
const half = Math.
|
|
26795
|
+
const half = Math.max(16, p.spanHalf);
|
|
26638
26796
|
const spineLeft = x0 - 20;
|
|
26639
26797
|
const spineRight = x1 + 20;
|
|
26640
26798
|
const bx0 = Math.max(spineLeft, p.x - half);
|
|
@@ -26645,6 +26803,11 @@ function renderEventLine(container, parsed, palette, isDark, onClickItem, export
|
|
|
26645
26803
|
"d",
|
|
26646
26804
|
`M${bx0},${spineY} L${bx0},${barY} L${bx1},${barY} L${bx1},${spineY}`
|
|
26647
26805
|
).attr("fill", "none").attr("stroke", col).attr("stroke-width", 1.5).attr("stroke-linecap", "round").attr("stroke-linejoin", "round");
|
|
26806
|
+
const breakCx = (bx0 + bx1) / 2;
|
|
26807
|
+
eg.append("line").attr("x1", breakCx - BREAK_GAP / 2).attr("y1", spineY).attr("x2", breakCx + BREAK_GAP / 2).attr("y2", spineY).attr("stroke", palette.bg).attr("stroke-width", 4).attr("stroke-linecap", "butt");
|
|
26808
|
+
for (const d of axisBreakPaths(breakCx, spineY)) {
|
|
26809
|
+
eg.append("path").attr("d", d).attr("fill", "none").attr("stroke", col).attr("stroke-width", 1.25).attr("stroke-linecap", "round").attr("stroke-linejoin", "round").attr("stroke-opacity", 0.85);
|
|
26810
|
+
}
|
|
26648
26811
|
if (onClickItem) {
|
|
26649
26812
|
const ln = p.lineNumber;
|
|
26650
26813
|
eg.style("cursor", "pointer").on("click", () => onClickItem(ln));
|
|
@@ -26678,13 +26841,23 @@ function renderEventLine(container, parsed, palette, isDark, onClickItem, export
|
|
|
26678
26841
|
}
|
|
26679
26842
|
const clampX = (v) => Math.max(4, Math.min(contentW - 4, v));
|
|
26680
26843
|
const cap = eraSide === "above" ? 1 : -1;
|
|
26681
|
-
|
|
26682
|
-
|
|
26844
|
+
const drawn = runs.filter((r) => !r.collapsed).map((r) => ({
|
|
26845
|
+
run: r,
|
|
26846
|
+
x0: clampX(r.firstX - ERA_BRACKET_PAD),
|
|
26847
|
+
x1: clampX(r.lastX + ERA_BRACKET_PAD)
|
|
26848
|
+
})).sort((a, b) => a.run.firstX - b.run.firstX);
|
|
26849
|
+
for (let i = 1; i < drawn.length; i++) {
|
|
26850
|
+
const prev = drawn[i - 1];
|
|
26851
|
+
const cur = drawn[i];
|
|
26852
|
+
if (prev.x1 <= cur.x0) continue;
|
|
26853
|
+
const mid = (prev.run.lastX + cur.run.firstX) / 2;
|
|
26854
|
+
prev.x1 = Math.max(prev.run.lastX, Math.min(prev.x1, mid - ERA_SEAM_GAP));
|
|
26855
|
+
cur.x0 = Math.min(cur.run.firstX, Math.max(cur.x0, mid + ERA_SEAM_GAP));
|
|
26856
|
+
}
|
|
26857
|
+
for (const { run: r, x0: x02, x1: x12 } of drawn) {
|
|
26683
26858
|
const neutral = !r.era.color;
|
|
26684
26859
|
const col = neutral ? palette.text : resolveColor(r.era.color, palette) ?? palette.text;
|
|
26685
26860
|
const op = neutral ? 0.5 : 0.85;
|
|
26686
|
-
const x02 = clampX(r.firstX - 14);
|
|
26687
|
-
const x12 = clampX(r.lastX + 14);
|
|
26688
26861
|
const y = eraBaseY;
|
|
26689
26862
|
const eg = svg.append("g").attr("data-era", r.era.name).attr("data-era-collapsed", String(r.collapsed)).attr("data-line-number", r.era.lineNumber);
|
|
26690
26863
|
eg.append("path").attr(
|
|
@@ -26710,6 +26883,22 @@ function renderEventLineForExport(container, parsed, palette, isDark, exportDims
|
|
|
26710
26883
|
tagOverride
|
|
26711
26884
|
);
|
|
26712
26885
|
}
|
|
26886
|
+
function axisBreakPaths(cx, cy) {
|
|
26887
|
+
const HUMPS = 2;
|
|
26888
|
+
const STEPS = 14;
|
|
26889
|
+
const wave = (x0) => {
|
|
26890
|
+
let d = "";
|
|
26891
|
+
for (let i = 0; i <= STEPS; i++) {
|
|
26892
|
+
const t = i / STEPS;
|
|
26893
|
+
const y = cy - BREAK_HALF_H + t * 2 * BREAK_HALF_H;
|
|
26894
|
+
const x = x0 + BREAK_AMP * Math.sin(t * Math.PI * HUMPS);
|
|
26895
|
+
d += `${i === 0 ? "M" : "L"}${x.toFixed(2)},${y.toFixed(2)}`;
|
|
26896
|
+
if (i < STEPS) d += " ";
|
|
26897
|
+
}
|
|
26898
|
+
return d;
|
|
26899
|
+
};
|
|
26900
|
+
return [wave(cx - BREAK_GAP / 2), wave(cx + BREAK_GAP / 2)];
|
|
26901
|
+
}
|
|
26713
26902
|
function wrapDescription(lines, charsPerLine) {
|
|
26714
26903
|
const out = [];
|
|
26715
26904
|
for (const line11 of lines) {
|
|
@@ -26739,7 +26928,7 @@ function renderBody(cardG, lines, bodyColor, palette, startBaseline = CARD_BODY_
|
|
|
26739
26928
|
y += DESC_LINE_H;
|
|
26740
26929
|
}
|
|
26741
26930
|
}
|
|
26742
|
-
var CARD_W, H_MARGIN, TITLE_AREA, LEGEND_BAND, LEADER_ABOVE, LEADER_BELOW, DESC_FONT, DESC_LINE_H, CARD_PAD, CARD_BODY_TOP, DOT_R, MIN_SPACING, LANE_GAP, NEUTRAL_TAG, CARD_INSET, FAN_GAP, DATE_OFFSET, ERA_BLOCK, ERA_BRACKET_CAP, ERA_LEG, ERA_LABEL_FONT
|
|
26931
|
+
var CARD_W, H_MARGIN, TITLE_AREA, LEGEND_BAND, LEADER_ABOVE, LEADER_BELOW, DESC_FONT, DESC_LINE_H, CARD_PAD, CARD_BODY_TOP, DOT_R, MIN_SPACING, LANE_GAP, NEUTRAL_TAG, CARD_INSET, FAN_GAP, DATE_OFFSET, ERA_BLOCK, ERA_BRACKET_CAP, ERA_BRACKET_PAD, ERA_SEAM_GAP, BREAK_HALF_H, BREAK_AMP, BREAK_GAP, ERA_LEG, ERA_LABEL_FONT;
|
|
26743
26932
|
var init_renderer = __esm({
|
|
26744
26933
|
"src/event-line/renderer.ts"() {
|
|
26745
26934
|
"use strict";
|
|
@@ -26773,9 +26962,13 @@ var init_renderer = __esm({
|
|
|
26773
26962
|
DATE_OFFSET = 28;
|
|
26774
26963
|
ERA_BLOCK = 30;
|
|
26775
26964
|
ERA_BRACKET_CAP = 8;
|
|
26965
|
+
ERA_BRACKET_PAD = 14;
|
|
26966
|
+
ERA_SEAM_GAP = 3;
|
|
26967
|
+
BREAK_HALF_H = 6;
|
|
26968
|
+
BREAK_AMP = 2.2;
|
|
26969
|
+
BREAK_GAP = 5;
|
|
26776
26970
|
ERA_LEG = 13;
|
|
26777
26971
|
ERA_LABEL_FONT = 11.5;
|
|
26778
|
-
ERA_MEMBER_MAX = 6;
|
|
26779
26972
|
}
|
|
26780
26973
|
});
|
|
26781
26974
|
|
|
@@ -26918,13 +27111,13 @@ function renderVersionControl(container, parsed, palette, isDark, onClickItem, e
|
|
|
26918
27111
|
}
|
|
26919
27112
|
const showTitle = !!parsed.title;
|
|
26920
27113
|
const titleH = showTitle ? TITLE_AREA2 : 0;
|
|
26921
|
-
const
|
|
27114
|
+
const W3 = Math.round(contentW);
|
|
26922
27115
|
const H2 = Math.round(contentH + titleH);
|
|
26923
27116
|
const exportMode = !!exportDims;
|
|
26924
|
-
const svg = d3Selection7.select(container).append("svg").attr("width",
|
|
26925
|
-
svg.append("rect").attr("width",
|
|
27117
|
+
const svg = d3Selection7.select(container).append("svg").attr("width", W3).attr("height", H2).attr("viewBox", `0 0 ${W3} ${H2}`).attr("preserveAspectRatio", "xMidYMin meet").attr("xmlns", "http://www.w3.org/2000/svg").style("font-family", FONT_FAMILY);
|
|
27118
|
+
svg.append("rect").attr("width", W3).attr("height", H2).attr("fill", palette.bg);
|
|
26926
27119
|
if (showTitle) {
|
|
26927
|
-
const t = svg.append("text").attr("class", "chart-title").attr("x",
|
|
27120
|
+
const t = svg.append("text").attr("class", "chart-title").attr("x", W3 / 2).attr("y", TITLE_Y).attr("text-anchor", "middle").attr("fill", palette.text).attr("font-family", FONT_FAMILY).attr("font-size", TITLE_FONT_SIZE).attr("font-weight", TITLE_FONT_WEIGHT).attr("data-line-number", parsed.titleLineNumber ?? 1).text(parsed.title);
|
|
26928
27121
|
if (onClickItem && parsed.titleLineNumber && !exportMode) {
|
|
26929
27122
|
const ln = parsed.titleLineNumber;
|
|
26930
27123
|
t.style("cursor", "pointer").on("click", () => onClickItem(ln));
|
|
@@ -32705,7 +32898,7 @@ function findClearPosition(w, h, points, obstacles) {
|
|
|
32705
32898
|
}
|
|
32706
32899
|
function resolveLabelOverlaps(boxes) {
|
|
32707
32900
|
const MAX_PASSES = 8;
|
|
32708
|
-
const
|
|
32901
|
+
const PAD2 = 4;
|
|
32709
32902
|
for (let pass = 0; pass < MAX_PASSES; pass++) {
|
|
32710
32903
|
let moved = false;
|
|
32711
32904
|
for (let i = 0; i < boxes.length; i++) {
|
|
@@ -32714,8 +32907,8 @@ function resolveLabelOverlaps(boxes) {
|
|
|
32714
32907
|
const b = boxes[j];
|
|
32715
32908
|
const dx = Math.abs(a.cx - b.cx);
|
|
32716
32909
|
const dy = Math.abs(a.cy - b.cy);
|
|
32717
|
-
const overlapX = (a.w + b.w) / 2 +
|
|
32718
|
-
const overlapY = (a.h + b.h) / 2 +
|
|
32910
|
+
const overlapX = (a.w + b.w) / 2 + PAD2 - dx;
|
|
32911
|
+
const overlapY = (a.h + b.h) / 2 + PAD2 - dy;
|
|
32719
32912
|
if (overlapX > 0 && overlapY > 0) {
|
|
32720
32913
|
const shift = overlapY / 2 + 1;
|
|
32721
32914
|
if (a.cy < b.cy) {
|
|
@@ -43096,7 +43289,7 @@ function buildPathD(pts, direction) {
|
|
|
43096
43289
|
function computePortPts(edges, nodeMap, direction) {
|
|
43097
43290
|
const srcPts = /* @__PURE__ */ new Map();
|
|
43098
43291
|
const tgtPts = /* @__PURE__ */ new Map();
|
|
43099
|
-
const
|
|
43292
|
+
const PAD2 = 0.1;
|
|
43100
43293
|
const activeEdges = edges.filter((e) => e.points.length > 0);
|
|
43101
43294
|
const bySource = /* @__PURE__ */ new Map();
|
|
43102
43295
|
for (const e of activeEdges) {
|
|
@@ -43112,7 +43305,7 @@ function computePortPts(edges, nodeMap, direction) {
|
|
|
43112
43305
|
).sort((a, b) => direction === "LR" ? a.t.y - b.t.y : a.t.x - b.t.x);
|
|
43113
43306
|
const n = sorted.length;
|
|
43114
43307
|
for (let i = 0; i < n; i++) {
|
|
43115
|
-
const frac = n === 1 ? 0.5 :
|
|
43308
|
+
const frac = n === 1 ? 0.5 : PAD2 + (1 - 2 * PAD2) * i / (n - 1);
|
|
43116
43309
|
const { e, t } = sorted[i];
|
|
43117
43310
|
const isBackward = direction === "LR" ? t.x < source.x : t.y < source.y;
|
|
43118
43311
|
if (direction === "LR") {
|
|
@@ -43142,7 +43335,7 @@ function computePortPts(edges, nodeMap, direction) {
|
|
|
43142
43335
|
).sort((a, b) => direction === "LR" ? a.s.y - b.s.y : a.s.x - b.s.x);
|
|
43143
43336
|
const n = sorted.length;
|
|
43144
43337
|
for (let i = 0; i < n; i++) {
|
|
43145
|
-
const frac = n === 1 ? 0.5 :
|
|
43338
|
+
const frac = n === 1 ? 0.5 : PAD2 + (1 - 2 * PAD2) * i / (n - 1);
|
|
43146
43339
|
const { e, s } = sorted[i];
|
|
43147
43340
|
const isBackward = direction === "LR" ? target.x < s.x : target.y < s.y;
|
|
43148
43341
|
if (direction === "LR") {
|
|
@@ -52935,6 +53128,7 @@ function renderJourneyMap(container, parsed, palette, isDark, options) {
|
|
|
52935
53128
|
y,
|
|
52936
53129
|
score,
|
|
52937
53130
|
palette,
|
|
53131
|
+
isDark,
|
|
52938
53132
|
SCORE_LABEL_R
|
|
52939
53133
|
);
|
|
52940
53134
|
if (!exportDims) {
|
|
@@ -52966,7 +53160,14 @@ function renderJourneyMap(container, parsed, palette, isDark, options) {
|
|
|
52966
53160
|
const allSteps = parsed.phases.length > 0 ? parsed.phases.flatMap((p) => p.steps) : parsed.steps;
|
|
52967
53161
|
for (const pt of layout.curvePoints) {
|
|
52968
53162
|
const step = allSteps[pt.stepIndex];
|
|
52969
|
-
const faceG = renderScoreFace(
|
|
53163
|
+
const faceG = renderScoreFace(
|
|
53164
|
+
curveG,
|
|
53165
|
+
pt.x,
|
|
53166
|
+
pt.y,
|
|
53167
|
+
pt.score,
|
|
53168
|
+
palette,
|
|
53169
|
+
isDark
|
|
53170
|
+
);
|
|
52970
53171
|
addEmotionLabel(faceG, pt, palette);
|
|
52971
53172
|
if (step) {
|
|
52972
53173
|
faceG.attr("data-line-number", step.lineNumber);
|
|
@@ -52992,7 +53193,14 @@ function renderJourneyMap(container, parsed, palette, isDark, options) {
|
|
|
52992
53193
|
const pt = layout.curvePoints[0];
|
|
52993
53194
|
const allSteps = parsed.phases.length > 0 ? parsed.phases.flatMap((p) => p.steps) : parsed.steps;
|
|
52994
53195
|
const step = allSteps[pt.stepIndex];
|
|
52995
|
-
const faceG = renderScoreFace(
|
|
53196
|
+
const faceG = renderScoreFace(
|
|
53197
|
+
curveG,
|
|
53198
|
+
pt.x,
|
|
53199
|
+
pt.y,
|
|
53200
|
+
pt.score,
|
|
53201
|
+
palette,
|
|
53202
|
+
isDark
|
|
53203
|
+
);
|
|
52996
53204
|
addEmotionLabel(faceG, pt, palette);
|
|
52997
53205
|
if (step) {
|
|
52998
53206
|
faceG.attr("data-line-number", step.lineNumber);
|
|
@@ -53089,6 +53297,7 @@ function renderJourneyMap(container, parsed, palette, isDark, options) {
|
|
|
53089
53297
|
faceCy,
|
|
53090
53298
|
step.score,
|
|
53091
53299
|
palette,
|
|
53300
|
+
isDark,
|
|
53092
53301
|
COLLAPSED_FACE_R
|
|
53093
53302
|
);
|
|
53094
53303
|
faceG.attr("data-line-number", step.lineNumber);
|
|
@@ -53192,7 +53401,7 @@ function renderJourneyMap(container, parsed, palette, isDark, options) {
|
|
|
53192
53401
|
const fcy = parseFloat(el.attr("data-cy") ?? "0");
|
|
53193
53402
|
el.attr(
|
|
53194
53403
|
"transform",
|
|
53195
|
-
`translate(${fcx},${fcy}) scale(
|
|
53404
|
+
`translate(${fcx},${fcy}) scale(${FACE_HOVER_SCALE}) translate(${-fcx},${-fcy})`
|
|
53196
53405
|
);
|
|
53197
53406
|
} else {
|
|
53198
53407
|
el.attr("transform", null);
|
|
@@ -53238,12 +53447,12 @@ function renderJourneyMap(container, parsed, palette, isDark, options) {
|
|
|
53238
53447
|
PADDING2,
|
|
53239
53448
|
Math.min(fcx - bw / 2, layout.totalWidth - PADDING2 - bw)
|
|
53240
53449
|
);
|
|
53241
|
-
const by = Math.max(PADDING2, fcy -
|
|
53450
|
+
const by = Math.max(PADDING2, fcy - FACE_HOVER_R - THOUGHT_GAP - bh);
|
|
53242
53451
|
const scoreColor = scoreToColor(score, palette);
|
|
53243
53452
|
const tintedBg = mix(scoreColor, palette.surface, 20);
|
|
53244
53453
|
const g = overlayG.append("g").attr("class", "journey-thought-hover");
|
|
53245
53454
|
g.append("rect").attr("x", bx).attr("y", by).attr("width", bw).attr("height", bh).attr("rx", CARD_RADIUS).attr("fill", tintedBg).attr("stroke", scoreColor).attr("stroke-width", CARD_STROKE_WIDTH2);
|
|
53246
|
-
g.append("line").attr("x1", fcx).attr("y1", by + bh).attr("x2", fcx).attr("y2", fcy -
|
|
53455
|
+
g.append("line").attr("x1", fcx).attr("y1", by + bh).attr("x2", fcx).attr("y2", fcy - FACE_HOVER_R - 1).attr("stroke", scoreColor).attr("stroke-width", CARD_STROKE_WIDTH2);
|
|
53247
53456
|
const centerX = bx + bw / 2;
|
|
53248
53457
|
for (let i = 0; i < lines.length; i++) {
|
|
53249
53458
|
g.append("text").attr("x", centerX).attr("y", by + THOUGHT_PAD_Y + (i + 1) * THOUGHT_LINE_H - 2).attr("text-anchor", "middle").attr("font-size", THOUGHT_FONT).attr("font-style", "italic").attr("fill", palette.textMuted).text(lines[i]);
|
|
@@ -53486,24 +53695,23 @@ function renderPersonaSilhouette(parent, cx, cy, color, palette, scale = 1) {
|
|
|
53486
53695
|
`M ${cx} ${cy - 12 * s} C ${cx + 10 * s} ${cy - 12 * s}, ${cx + 9 * s} ${cy + 2 * s}, ${cx + 6 * s} ${cy + 6 * s} Q ${cx} ${cy + 9 * s}, ${cx - 6 * s} ${cy + 6 * s} C ${cx - 9 * s} ${cy + 2 * s}, ${cx - 10 * s} ${cy - 12 * s}, ${cx} ${cy - 12 * s} Z`
|
|
53487
53696
|
).attr("fill", fill2).attr("stroke", stroke2).attr("stroke-width", 1.2);
|
|
53488
53697
|
}
|
|
53489
|
-
function renderScoreFace(parent, cx, cy, score, palette, radius) {
|
|
53698
|
+
function renderScoreFace(parent, cx, cy, score, palette, isDark, radius) {
|
|
53490
53699
|
const r = radius ?? FACE_RADIUS;
|
|
53491
53700
|
const color = scoreToColor(score, palette);
|
|
53492
53701
|
const g = parent.append("g").attr("class", "journey-face").attr("data-cx", cx).attr("data-cy", cy);
|
|
53493
|
-
|
|
53494
|
-
|
|
53495
|
-
|
|
53496
|
-
|
|
53497
|
-
palette.textOnFillDark
|
|
53498
|
-
);
|
|
53702
|
+
const faceFill = shapeFill(palette, color, isDark);
|
|
53703
|
+
g.append("circle").attr("cx", cx).attr("cy", cy).attr("r", r + 1).attr("fill", palette.bg);
|
|
53704
|
+
g.append("circle").attr("cx", cx).attr("cy", cy).attr("r", r).attr("fill", faceFill).attr("stroke", color).attr("stroke-width", 2);
|
|
53705
|
+
const eyeColor = color;
|
|
53499
53706
|
const eyeY = cy - r * 0.15;
|
|
53500
53707
|
const eyeSpacing = r * 0.32;
|
|
53501
53708
|
const eyeR = r * 0.12;
|
|
53502
53709
|
g.append("circle").attr("cx", cx - eyeSpacing).attr("cy", eyeY).attr("r", eyeR).attr("fill", eyeColor);
|
|
53503
53710
|
g.append("circle").attr("cx", cx + eyeSpacing).attr("cy", eyeY).attr("r", eyeR).attr("fill", eyeColor);
|
|
53504
|
-
const
|
|
53505
|
-
const
|
|
53506
|
-
const
|
|
53711
|
+
const mouthW = r * 0.46;
|
|
53712
|
+
const curve = (score - 3) / 2 * r * 0.42;
|
|
53713
|
+
const apexY = cy + r * 0.32;
|
|
53714
|
+
const mouthY = apexY - curve / 2;
|
|
53507
53715
|
g.append("path").attr(
|
|
53508
53716
|
"d",
|
|
53509
53717
|
`M ${cx - mouthW} ${mouthY} Q ${cx} ${mouthY + curve} ${cx + mouthW} ${mouthY}`
|
|
@@ -53574,7 +53782,7 @@ function renderJourneyMapForExport(content, theme, palette) {
|
|
|
53574
53782
|
}
|
|
53575
53783
|
return svgEl.outerHTML;
|
|
53576
53784
|
}
|
|
53577
|
-
var DIAGRAM_PADDING13, PADDING2, CARD_PADDING_X3, CARD_PADDING_Y3, CARD_HEADER_HEIGHT3, CARD_STROKE_WIDTH2, CARD_META_LINE_HEIGHT3, CARD_GAP_INTERNAL, COLUMN_RADIUS2, COLUMN_HEADER_HEIGHT2, COLUMN_PADDING3, FONT_SIZE_TITLE, FONT_SIZE_PHASE, FONT_SIZE_STEP, FONT_SIZE_META, GRID_LINE_OPACITY, CURVE_STROKE_WIDTH, FACE_RADIUS, DIM_HOVER, TITLE_LINE_HEIGHT, EMOTION_LABEL_MAX_WIDTH, EMOTION_LABEL_FONT_SIZE, ICON_THUMBS_DOWN, ICON_THUMBS_UP, ICON_THOUGHT;
|
|
53785
|
+
var DIAGRAM_PADDING13, PADDING2, CARD_PADDING_X3, CARD_PADDING_Y3, CARD_HEADER_HEIGHT3, CARD_STROKE_WIDTH2, CARD_META_LINE_HEIGHT3, CARD_GAP_INTERNAL, COLUMN_RADIUS2, COLUMN_HEADER_HEIGHT2, COLUMN_PADDING3, FONT_SIZE_TITLE, FONT_SIZE_PHASE, FONT_SIZE_STEP, FONT_SIZE_META, GRID_LINE_OPACITY, CURVE_STROKE_WIDTH, FACE_RADIUS, FACE_HOVER_SCALE, FACE_HOVER_R, DIM_HOVER, TITLE_LINE_HEIGHT, EMOTION_LABEL_MAX_WIDTH, EMOTION_LABEL_FONT_SIZE, ICON_THUMBS_DOWN, ICON_THUMBS_UP, ICON_THOUGHT;
|
|
53578
53786
|
var init_renderer17 = __esm({
|
|
53579
53787
|
"src/journey-map/renderer.ts"() {
|
|
53580
53788
|
"use strict";
|
|
@@ -53608,6 +53816,8 @@ var init_renderer17 = __esm({
|
|
|
53608
53816
|
GRID_LINE_OPACITY = 0.15;
|
|
53609
53817
|
CURVE_STROKE_WIDTH = 2.5;
|
|
53610
53818
|
FACE_RADIUS = 14;
|
|
53819
|
+
FACE_HOVER_SCALE = 1.5;
|
|
53820
|
+
FACE_HOVER_R = (FACE_RADIUS + 1) * FACE_HOVER_SCALE;
|
|
53611
53821
|
DIM_HOVER = 0.25;
|
|
53612
53822
|
TITLE_LINE_HEIGHT = 16;
|
|
53613
53823
|
EMOTION_LABEL_MAX_WIDTH = 180;
|
|
@@ -56657,7 +56867,7 @@ function layoutMap(resolvedIn, data, size, opts) {
|
|
|
56657
56867
|
const akRef = resolved.regions.some((r) => r.iso === "US-AK") || resolved.pois.some((p) => inAlaska(p.lon, p.lat));
|
|
56658
56868
|
const hiRef = resolved.regions.some((r) => r.iso === "US-HI") || resolved.pois.some((p) => inHawaii(p.lon, p.lat));
|
|
56659
56869
|
if (resolved.projection === "albers-usa" && usLayer && (akRef || hiRef)) {
|
|
56660
|
-
const
|
|
56870
|
+
const PAD2 = 8;
|
|
56661
56871
|
const GAP = 12;
|
|
56662
56872
|
const yB = height - FIT_PAD;
|
|
56663
56873
|
const BW = 8;
|
|
@@ -56700,22 +56910,22 @@ function layoutMap(resolvedIn, data, size, opts) {
|
|
|
56700
56910
|
const f = usLayer.get(iso);
|
|
56701
56911
|
if (!f) return boxX;
|
|
56702
56912
|
const x0 = boxX;
|
|
56703
|
-
const iw = Math.min(iwReq, width - FIT_PAD - x0 - 2 *
|
|
56913
|
+
const iw = Math.min(iwReq, width - FIT_PAD - x0 - 2 * PAD2);
|
|
56704
56914
|
if (iw < 24) return boxX;
|
|
56705
|
-
const xr = x0 + iw + 2 *
|
|
56915
|
+
const xr = x0 + iw + 2 * PAD2;
|
|
56706
56916
|
const floor = coastFloor(x0, xr);
|
|
56707
56917
|
const topGuess = floor > -Infinity ? floor + GAP : yB - height * 0.42;
|
|
56708
56918
|
proj.fitWidth(iw, f);
|
|
56709
56919
|
const bb = geoPath(proj).bounds(f);
|
|
56710
56920
|
const sh = Number.isFinite(bb[0][0]) ? bb[1][1] - bb[0][1] : iw;
|
|
56711
|
-
const needH = sh + 2 *
|
|
56921
|
+
const needH = sh + 2 * PAD2;
|
|
56712
56922
|
let topFit = topGuess;
|
|
56713
56923
|
const bottom = Math.min(topFit + needH, yB);
|
|
56714
56924
|
if (bottom - topFit < needH) topFit = bottom - needH;
|
|
56715
56925
|
proj.fitExtent(
|
|
56716
56926
|
[
|
|
56717
|
-
[x0 +
|
|
56718
|
-
[xr -
|
|
56927
|
+
[x0 + PAD2, topFit + PAD2],
|
|
56928
|
+
[xr - PAD2, bottom - PAD2]
|
|
56719
56929
|
],
|
|
56720
56930
|
f
|
|
56721
56931
|
);
|
|
@@ -58239,15 +58449,15 @@ function layoutMap(resolvedIn, data, size, opts) {
|
|
|
58239
58449
|
}
|
|
58240
58450
|
}
|
|
58241
58451
|
if (regionLabelGuards.length > 0) {
|
|
58242
|
-
const
|
|
58452
|
+
const PAD2 = 2;
|
|
58243
58453
|
const poiRects = labels.filter((l) => l.poiId !== void 0 && l.hidden !== true).map((l) => {
|
|
58244
58454
|
const w = measureLegendText(l.text, FONT2);
|
|
58245
58455
|
const x = l.anchor === "start" ? l.x : l.anchor === "end" ? l.x - w : l.x - w / 2;
|
|
58246
58456
|
return {
|
|
58247
|
-
x: x -
|
|
58457
|
+
x: x - PAD2,
|
|
58248
58458
|
y: l.y - FONT2,
|
|
58249
|
-
w: w + 2 *
|
|
58250
|
-
h: FONT2 * 1.4 + 2 *
|
|
58459
|
+
w: w + 2 * PAD2,
|
|
58460
|
+
h: FONT2 * 1.4 + 2 * PAD2
|
|
58251
58461
|
};
|
|
58252
58462
|
});
|
|
58253
58463
|
for (const g of regionLabelGuards) {
|
|
@@ -58871,7 +59081,7 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
58871
59081
|
if (poiLabels.length) {
|
|
58872
59082
|
const patchBlurId = nid("dgmo-map-label-patch-blur");
|
|
58873
59083
|
defs.append("filter").attr("id", patchBlurId).attr("x", "-50%").attr("y", "-50%").attr("width", "200%").attr("height", "200%").append("feGaussianBlur").attr("in", "SourceGraphic").attr("stdDeviation", 2.5);
|
|
58874
|
-
const
|
|
59084
|
+
const PAD2 = 8;
|
|
58875
59085
|
const buildPatch = (labels, maskId, decoCluster) => {
|
|
58876
59086
|
if (!labels.length) return;
|
|
58877
59087
|
const patchMask = defs.append("mask").attr("id", maskId).attr("maskUnits", "userSpaceOnUse").attr("x", 0).attr("y", 0).attr("width", width).attr("height", height);
|
|
@@ -58887,10 +59097,10 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
58887
59097
|
const h = th + 6;
|
|
58888
59098
|
blobs.append("rect").attr("x", cx - w / 2).attr("y", cy - h / 2).attr("width", w).attr("height", h).attr("rx", h / 2).attr("fill", "white");
|
|
58889
59099
|
blobRects.push({
|
|
58890
|
-
x0: cx - w / 2 -
|
|
58891
|
-
y0: cy - h / 2 -
|
|
58892
|
-
x1: cx + w / 2 +
|
|
58893
|
-
y1: cy + h / 2 +
|
|
59100
|
+
x0: cx - w / 2 - PAD2,
|
|
59101
|
+
y0: cy - h / 2 - PAD2,
|
|
59102
|
+
x1: cx + w / 2 + PAD2,
|
|
59103
|
+
y1: cy + h / 2 + PAD2
|
|
58894
59104
|
});
|
|
58895
59105
|
}
|
|
58896
59106
|
const gPatch = svg.append("g").attr("class", "dgmo-map-label-patch").attr("mask", `url(#${maskId})`).style("pointer-events", "none");
|
|
@@ -60311,13 +60521,13 @@ function renderTreemap(container, parsed, palette, isDark, exportDims, options =
|
|
|
60311
60521
|
g.append("text").attr("class", "dgmo-treemap-header-value").attr("x", w - ICON_RESERVE - 4).attr("y", 13).attr("text-anchor", "end").attr("font-size", 10.5).attr("fill", ink).attr("opacity", 0.75).text(valStr);
|
|
60312
60522
|
}
|
|
60313
60523
|
}
|
|
60314
|
-
const
|
|
60524
|
+
const PAD2 = Math.max(4, Math.min(14, Math.floor(Math.min(w, h) / 5)));
|
|
60315
60525
|
const MIN_FS = 7;
|
|
60316
|
-
if (!cell.isContainer && w >= 2 *
|
|
60317
|
-
const maxW = w - 2 *
|
|
60526
|
+
if (!cell.isContainer && w >= 2 * PAD2 + 8 && h >= 2 * PAD2 + 8) {
|
|
60527
|
+
const maxW = w - 2 * PAD2;
|
|
60318
60528
|
const horizMinW = measureText(cell.label, MIN_FS) * 1.06;
|
|
60319
|
-
if (horizMinW > maxW && h > w * 1.25 && h - 2 *
|
|
60320
|
-
drawVerticalLabel(g, cell.label, w, h,
|
|
60529
|
+
if (horizMinW > maxW && h > w * 1.25 && h - 2 * PAD2 > maxW) {
|
|
60530
|
+
drawVerticalLabel(g, cell.label, w, h, PAD2, ink);
|
|
60321
60531
|
if (drillable && w > 30 && h > 22) drawFocusIcon(g, w, ink, 9);
|
|
60322
60532
|
continue;
|
|
60323
60533
|
}
|
|
@@ -60328,8 +60538,8 @@ function renderTreemap(container, parsed, palette, isDark, exportDims, options =
|
|
|
60328
60538
|
const nameOpacity = 0.95 - tg * 0.5;
|
|
60329
60539
|
const vfs = clamp3(Math.round(fs * 0.42), 11, 28);
|
|
60330
60540
|
const valOpacity = Math.max(0.45, nameOpacity - 0.1);
|
|
60331
|
-
let y =
|
|
60332
|
-
g.append("text").attr("class", "dgmo-treemap-label").attr("x",
|
|
60541
|
+
let y = PAD2 + Math.round(fs * 0.78);
|
|
60542
|
+
g.append("text").attr("class", "dgmo-treemap-label").attr("x", PAD2).attr("y", y).attr("font-size", fs).attr("font-weight", 600).attr("fill", ink).attr("opacity", nameOpacity).text(clipLabel(cell.label, maxW, fs));
|
|
60333
60543
|
const valParts = [
|
|
60334
60544
|
opts.noValues ? "" : compactNumber2(cell.value),
|
|
60335
60545
|
opts.noPercent ? "" : formatPct(cell.pctOfRoot)
|
|
@@ -60337,12 +60547,12 @@ function renderTreemap(container, parsed, palette, isDark, exportDims, options =
|
|
|
60337
60547
|
const combined = valParts.join(" \xB7 ");
|
|
60338
60548
|
const nameBaseY = y;
|
|
60339
60549
|
const addLineAt = (text, yy, size, opacity) => {
|
|
60340
|
-
g.append("text").attr("class", "dgmo-treemap-value").attr("x",
|
|
60550
|
+
g.append("text").attr("class", "dgmo-treemap-value").attr("x", PAD2).attr("y", yy).attr("font-size", size).attr("fill", ink).attr("opacity", opacity).text(text);
|
|
60341
60551
|
};
|
|
60342
60552
|
if (combined) {
|
|
60343
60553
|
const fitsW = measureText(combined, vfs) <= maxW;
|
|
60344
60554
|
const valY = y + lineDrop(fs, vfs);
|
|
60345
|
-
const roomBelow = valY + descent(vfs) <= h -
|
|
60555
|
+
const roomBelow = valY + descent(vfs) <= h - PAD2;
|
|
60346
60556
|
if (fitsW && roomBelow) {
|
|
60347
60557
|
addLineAt(combined, valY, vfs, valOpacity);
|
|
60348
60558
|
} else if (fitsW) {
|
|
@@ -60350,24 +60560,24 @@ function renderTreemap(container, parsed, palette, isDark, exportDims, options =
|
|
|
60350
60560
|
const rendered = clipLabel(cell.label, maxW, fs);
|
|
60351
60561
|
const nW = measureText(rendered, fs) * 1.12;
|
|
60352
60562
|
const gap = Math.max(12, Math.round(fs * 0.25));
|
|
60353
|
-
if (
|
|
60354
|
-
g.append("text").attr("class", "dgmo-treemap-value").attr("x",
|
|
60563
|
+
if (PAD2 + nW + gap + measureText(combined, ivfs) <= w - PAD2) {
|
|
60564
|
+
g.append("text").attr("class", "dgmo-treemap-value").attr("x", PAD2 + nW + gap).attr("y", nameBaseY).attr("font-size", ivfs).attr("fill", ink).attr("opacity", valOpacity).text(combined);
|
|
60355
60565
|
}
|
|
60356
60566
|
} else if (valParts.length === 2) {
|
|
60357
60567
|
const d1 = lineDrop(fs, vfs);
|
|
60358
|
-
if (y + d1 + descent(vfs) <= h -
|
|
60568
|
+
if (y + d1 + descent(vfs) <= h - PAD2) {
|
|
60359
60569
|
y += d1;
|
|
60360
60570
|
addLineAt(valParts[0], y, vfs, valOpacity);
|
|
60361
60571
|
}
|
|
60362
60572
|
const pfs = Math.max(10, Math.round(vfs * 0.9));
|
|
60363
60573
|
const d2 = lineDrop(vfs, pfs);
|
|
60364
|
-
if (y + d2 + descent(pfs) <= h -
|
|
60574
|
+
if (y + d2 + descent(pfs) <= h - PAD2) {
|
|
60365
60575
|
y += d2;
|
|
60366
60576
|
addLineAt(valParts[1], y, pfs, valOpacity);
|
|
60367
60577
|
}
|
|
60368
60578
|
} else {
|
|
60369
60579
|
const onlyY = y + lineDrop(fs, vfs);
|
|
60370
|
-
if (onlyY + descent(vfs) <= h -
|
|
60580
|
+
if (onlyY + descent(vfs) <= h - PAD2) {
|
|
60371
60581
|
addLineAt(combined, onlyY, vfs, valOpacity);
|
|
60372
60582
|
}
|
|
60373
60583
|
}
|
|
@@ -68490,6 +68700,144 @@ function decodeDiagramUrl(hash) {
|
|
|
68490
68700
|
init_dgmo_router();
|
|
68491
68701
|
init_palettes();
|
|
68492
68702
|
init_diagnostics();
|
|
68703
|
+
|
|
68704
|
+
// src/error-card.ts
|
|
68705
|
+
init_text_measure();
|
|
68706
|
+
init_fonts();
|
|
68707
|
+
var MONO_FAMILY = "ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace";
|
|
68708
|
+
var W2 = 660;
|
|
68709
|
+
var PAD = 24;
|
|
68710
|
+
var CONTENT_W = W2 - PAD * 2;
|
|
68711
|
+
var MAX_ERRORS = 4;
|
|
68712
|
+
var MONO_CH = 0.6;
|
|
68713
|
+
var CODE_FS = 12.5;
|
|
68714
|
+
function renderErrorCard(errors, source, palette, theme) {
|
|
68715
|
+
const c = palette[theme === "dark" ? "dark" : "light"];
|
|
68716
|
+
const isTransparent = theme === "transparent";
|
|
68717
|
+
const card = c.surface;
|
|
68718
|
+
const codeBg = c.bg;
|
|
68719
|
+
const border = c.border;
|
|
68720
|
+
const danger = c.destructive ?? c.colors.red;
|
|
68721
|
+
const text = c.text;
|
|
68722
|
+
const muted = c.textMuted;
|
|
68723
|
+
const srcLines = source.split("\n");
|
|
68724
|
+
const shown = errors.slice(0, MAX_ERRORS);
|
|
68725
|
+
const overflow = errors.length - shown.length;
|
|
68726
|
+
const parts = [];
|
|
68727
|
+
let y = PAD + 8;
|
|
68728
|
+
parts.push(frownMark(PAD + 14, y + 12, danger));
|
|
68729
|
+
parts.push(
|
|
68730
|
+
`<text x="${PAD + 38}" y="${y + 11}" fill="${text}" font-family="${FONT_FAMILY}" font-size="16" font-weight="700">Couldn't render this diagram</text>`,
|
|
68731
|
+
`<text x="${W2 - PAD}" y="${y + 10}" text-anchor="end" fill="${muted}" font-family="${FONT_FAMILY}" font-size="12" font-weight="600" letter-spacing="0.5">dgmo</text>`
|
|
68732
|
+
);
|
|
68733
|
+
y += 24;
|
|
68734
|
+
const errLabel = errors.length === 1 ? "1 error" : `${errors.length} errors`;
|
|
68735
|
+
parts.push(
|
|
68736
|
+
`<text x="${PAD + 38}" y="${y + 4}" fill="${muted}" font-family="${FONT_FAMILY}" font-size="12.5">${errLabel} \u2014 fix the lines below and re-render</text>`
|
|
68737
|
+
);
|
|
68738
|
+
y += 22;
|
|
68739
|
+
parts.push(
|
|
68740
|
+
`<line x1="${PAD}" y1="${y}" x2="${W2 - PAD}" y2="${y}" stroke="${border}" stroke-width="1"/>`
|
|
68741
|
+
);
|
|
68742
|
+
y += 24;
|
|
68743
|
+
for (const e of shown) {
|
|
68744
|
+
const hasLine = e.line > 0;
|
|
68745
|
+
let msgX = PAD;
|
|
68746
|
+
if (hasLine) {
|
|
68747
|
+
const label = e.column ? `Line ${e.line}:${e.column}` : `Line ${e.line}`;
|
|
68748
|
+
const badgeW = 14 + label.length * 7;
|
|
68749
|
+
parts.push(
|
|
68750
|
+
`<rect x="${PAD}" y="${y - 13}" width="${badgeW}" height="19" rx="4" fill="${danger}"/>`,
|
|
68751
|
+
`<text x="${PAD + badgeW / 2}" y="${y + 1}" text-anchor="middle" fill="${c.bg}" font-family="${FONT_FAMILY}" font-size="11.5" font-weight="700">${escapeXml(label)}</text>`
|
|
68752
|
+
);
|
|
68753
|
+
msgX = PAD + badgeW + 12;
|
|
68754
|
+
}
|
|
68755
|
+
const lines = wrapMessage(e.message, CONTENT_W - (msgX - PAD), CONTENT_W);
|
|
68756
|
+
lines.forEach((line11, i) => {
|
|
68757
|
+
parts.push(
|
|
68758
|
+
`<text x="${i === 0 ? msgX : PAD}" y="${y + 1}" fill="${text}" font-family="${FONT_FAMILY}" font-size="13">${escapeXml(line11)}</text>`
|
|
68759
|
+
);
|
|
68760
|
+
if (i < lines.length - 1) y += 18;
|
|
68761
|
+
});
|
|
68762
|
+
y += 24;
|
|
68763
|
+
const raw = hasLine ? srcLines[e.line - 1] : void 0;
|
|
68764
|
+
if (raw !== void 0 && raw.trim().length > 0) {
|
|
68765
|
+
const gutter = `${e.line}`;
|
|
68766
|
+
const gutterW = gutter.length * CODE_FS * MONO_CH + 16;
|
|
68767
|
+
const codeX = PAD + gutterW;
|
|
68768
|
+
const codeMaxW = CONTENT_W - gutterW - 12;
|
|
68769
|
+
const codeText = truncateText(
|
|
68770
|
+
raw.replace(/\t/g, " "),
|
|
68771
|
+
CODE_FS,
|
|
68772
|
+
codeMaxW
|
|
68773
|
+
);
|
|
68774
|
+
const hasCaret = e.column !== void 0 && e.column > 0;
|
|
68775
|
+
const blockH = hasCaret ? 40 : 26;
|
|
68776
|
+
parts.push(
|
|
68777
|
+
`<rect x="${PAD}" y="${y - 14}" width="${CONTENT_W}" height="${blockH}" rx="5" fill="${codeBg}" stroke="${border}" stroke-width="1"/>`,
|
|
68778
|
+
`<line x1="${codeX - 8}" y1="${y - 14}" x2="${codeX - 8}" y2="${y - 14 + blockH}" stroke="${border}" stroke-width="1"/>`,
|
|
68779
|
+
`<text x="${PAD + 8}" y="${y + 3}" fill="${muted}" font-family="${MONO_FAMILY}" font-size="${CODE_FS}">${escapeXml(gutter)}</text>`,
|
|
68780
|
+
`<text x="${codeX}" y="${y + 3}" fill="${text}" font-family="${MONO_FAMILY}" font-size="${CODE_FS}" xml:space="preserve">${escapeXml(codeText)}</text>`
|
|
68781
|
+
);
|
|
68782
|
+
if (hasCaret) {
|
|
68783
|
+
const caretX = codeX + (e.column - 1) * CODE_FS * MONO_CH;
|
|
68784
|
+
parts.push(
|
|
68785
|
+
`<text x="${caretX}" y="${y + 17}" fill="${danger}" font-family="${MONO_FAMILY}" font-size="${CODE_FS}" font-weight="700">^</text>`
|
|
68786
|
+
);
|
|
68787
|
+
y += 14;
|
|
68788
|
+
}
|
|
68789
|
+
y += 24;
|
|
68790
|
+
}
|
|
68791
|
+
y += 14;
|
|
68792
|
+
}
|
|
68793
|
+
if (overflow > 0) {
|
|
68794
|
+
parts.push(
|
|
68795
|
+
`<text x="${PAD}" y="${y}" fill="${muted}" font-family="${FONT_FAMILY}" font-size="12.5" font-style="italic">+ ${overflow} more error${overflow === 1 ? "" : "s"}</text>`
|
|
68796
|
+
);
|
|
68797
|
+
y += 22;
|
|
68798
|
+
}
|
|
68799
|
+
const height = Math.round(y + PAD - 14);
|
|
68800
|
+
const pageBg = isTransparent ? "" : `<rect width="100%" height="100%" fill="${c.bg}"/>`;
|
|
68801
|
+
return [
|
|
68802
|
+
`<svg xmlns="http://www.w3.org/2000/svg" width="${W2}" height="${height}" viewBox="0 0 ${W2} ${height}" font-family="${FONT_FAMILY}">`,
|
|
68803
|
+
pageBg,
|
|
68804
|
+
`<rect x="0.5" y="0.5" width="${W2 - 1}" height="${height - 1}" rx="10" fill="${card}" stroke="${border}" stroke-width="1"/>`,
|
|
68805
|
+
parts.join(""),
|
|
68806
|
+
`</svg>`
|
|
68807
|
+
].join("");
|
|
68808
|
+
}
|
|
68809
|
+
function wrapMessage(message, firstWidth, fullWidth) {
|
|
68810
|
+
const words = message.split(/\s+/).filter(Boolean);
|
|
68811
|
+
if (words.length === 0) return [""];
|
|
68812
|
+
const lines = [];
|
|
68813
|
+
let cur = "";
|
|
68814
|
+
for (const word of words) {
|
|
68815
|
+
const limit = lines.length === 0 ? firstWidth : fullWidth;
|
|
68816
|
+
const test = cur ? `${cur} ${word}` : word;
|
|
68817
|
+
if (measureText(test, 13) <= limit || !cur) {
|
|
68818
|
+
cur = test;
|
|
68819
|
+
} else {
|
|
68820
|
+
lines.push(cur);
|
|
68821
|
+
cur = word;
|
|
68822
|
+
}
|
|
68823
|
+
}
|
|
68824
|
+
if (cur) lines.push(cur);
|
|
68825
|
+
return lines;
|
|
68826
|
+
}
|
|
68827
|
+
function frownMark(cx, cy, color) {
|
|
68828
|
+
const r = 12;
|
|
68829
|
+
return [
|
|
68830
|
+
`<circle cx="${cx}" cy="${cy}" r="${r}" fill="none" stroke="${color}" stroke-width="2"/>`,
|
|
68831
|
+
`<circle cx="${cx - 4.5}" cy="${cy - 3}" r="1.6" fill="${color}"/>`,
|
|
68832
|
+
`<circle cx="${cx + 4.5}" cy="${cy - 3}" r="1.6" fill="${color}"/>`,
|
|
68833
|
+
`<path d="M ${cx - 5} ${cy + 6} Q ${cx} ${cy + 1} ${cx + 5} ${cy + 6}" fill="none" stroke="${color}" stroke-width="2" stroke-linecap="round"/>`
|
|
68834
|
+
].join("");
|
|
68835
|
+
}
|
|
68836
|
+
function escapeXml(s) {
|
|
68837
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
68838
|
+
}
|
|
68839
|
+
|
|
68840
|
+
// src/index.ts
|
|
68493
68841
|
init_palettes();
|
|
68494
68842
|
|
|
68495
68843
|
// src/themes.ts
|
|
@@ -68829,25 +69177,10 @@ async function render2(text, options) {
|
|
|
68829
69177
|
return result;
|
|
68830
69178
|
}
|
|
68831
69179
|
return {
|
|
68832
|
-
svg:
|
|
69180
|
+
svg: renderErrorCard(errors, text, palette, options?.theme),
|
|
68833
69181
|
diagnostics: result.diagnostics
|
|
68834
69182
|
};
|
|
68835
69183
|
}
|
|
68836
|
-
function renderErrorSvg(errors, palette, theme) {
|
|
68837
|
-
const colors = palette[theme === "dark" ? "dark" : "light"];
|
|
68838
|
-
const bg = theme === "transparent" ? "transparent" : colors.bg;
|
|
68839
|
-
const fg = colors.destructive ?? colors.text;
|
|
68840
|
-
const muted = colors.textMuted ?? colors.text;
|
|
68841
|
-
const lines = errors.slice(0, 5).map((e) => formatDgmoError(e));
|
|
68842
|
-
const height = 60 + lines.length * 20;
|
|
68843
|
-
const body = lines.map(
|
|
68844
|
-
(line11, i) => `<text x="20" y="${60 + i * 20}" fill="${fg}" font-family="ui-monospace, monospace" font-size="12">${escapeXml(line11)}</text>`
|
|
68845
|
-
).join("");
|
|
68846
|
-
return `<svg xmlns="http://www.w3.org/2000/svg" width="640" height="${height}" viewBox="0 0 640 ${height}"><rect width="100%" height="100%" fill="${bg}"/><text x="20" y="34" fill="${muted}" font-family="system-ui, sans-serif" font-size="13" font-weight="600">DGMO parse error</text>${body}</svg>`;
|
|
68847
|
-
}
|
|
68848
|
-
function escapeXml(s) {
|
|
68849
|
-
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
68850
|
-
}
|
|
68851
69184
|
function encodeDiagramUrl2(text, options) {
|
|
68852
69185
|
const internalTheme = options?.theme === "light" || options?.theme === "dark" ? options.theme : void 0;
|
|
68853
69186
|
const result = encodeDiagramUrl(text, {
|