@diagrammo/dgmo 0.22.0 → 0.23.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 +238 -48
- package/dist/advanced.d.cts +17 -0
- package/dist/advanced.d.ts +17 -0
- package/dist/advanced.js +238 -48
- package/dist/auto.cjs +236 -42
- package/dist/auto.js +115 -115
- package/dist/auto.mjs +236 -42
- package/dist/cli.cjs +153 -153
- package/dist/editor.cjs +3 -0
- package/dist/editor.js +3 -0
- package/dist/highlight.cjs +3 -0
- package/dist/highlight.js +3 -0
- package/dist/index.cjs +232 -41
- package/dist/index.js +232 -41
- package/dist/internal.cjs +238 -48
- package/dist/internal.d.cts +17 -0
- package/dist/internal.d.ts +17 -0
- package/dist/internal.js +238 -48
- package/dist/map-data/PROVENANCE.json +1 -1
- package/dist/map-data/gazetteer.json +1 -1
- package/dist/map-data/mountain-ranges.json +1 -1
- package/dist/map-data/water-bodies.json +1 -1
- package/dist/map-data/world-coarse.json +1 -1
- package/dist/map-data/world-detail.json +1 -1
- package/docs/language-reference.md +35 -0
- package/gallery/fixtures/boxes-and-lines.dgmo +6 -4
- package/package.json +1 -1
- package/src/boxes-and-lines/parser.ts +39 -0
- package/src/boxes-and-lines/renderer.ts +171 -13
- package/src/boxes-and-lines/types.ts +9 -0
- package/src/completion.ts +4 -5
- package/src/d3.ts +12 -4
- package/src/editor/keywords.ts +3 -0
- package/src/map/data/PROVENANCE.json +1 -1
- package/src/map/data/README.md +6 -0
- package/src/map/data/gazetteer.json +1 -1
- package/src/map/data/mountain-ranges.json +1 -1
- package/src/map/data/water-bodies.json +1 -1
- package/src/map/data/world-coarse.json +1 -1
- package/src/map/data/world-detail.json +1 -1
- package/src/map/layout.ts +111 -18
- package/src/map/renderer.ts +95 -4
- package/src/utils/reserved-key-registry.ts +5 -3
package/dist/internal.cjs
CHANGED
|
@@ -917,9 +917,7 @@ var init_reserved_key_registry = __esm({
|
|
|
917
917
|
BOXES_AND_LINES_REGISTRY = staticRegistry([
|
|
918
918
|
"color",
|
|
919
919
|
"description",
|
|
920
|
-
"
|
|
921
|
-
"split",
|
|
922
|
-
"fanout"
|
|
920
|
+
"value"
|
|
923
921
|
]);
|
|
924
922
|
TIMELINE_REGISTRY = staticRegistry([
|
|
925
923
|
"color",
|
|
@@ -16873,6 +16871,21 @@ function parseBoxesAndLines(content) {
|
|
|
16873
16871
|
}
|
|
16874
16872
|
continue;
|
|
16875
16873
|
}
|
|
16874
|
+
if (!contentStarted) {
|
|
16875
|
+
const metricMatch = trimmed.match(/^box-metric\s+(.+)$/i);
|
|
16876
|
+
if (metricMatch) {
|
|
16877
|
+
const { label, colorName } = peelTrailingColorName(
|
|
16878
|
+
metricMatch[1].trim()
|
|
16879
|
+
);
|
|
16880
|
+
result.boxMetric = label;
|
|
16881
|
+
if (colorName !== void 0) result.boxMetricColor = colorName;
|
|
16882
|
+
continue;
|
|
16883
|
+
}
|
|
16884
|
+
if (/^show-values$/i.test(trimmed)) {
|
|
16885
|
+
result.showValues = true;
|
|
16886
|
+
continue;
|
|
16887
|
+
}
|
|
16888
|
+
}
|
|
16876
16889
|
if (!contentStarted) {
|
|
16877
16890
|
const optMatch = trimmed.match(OPTION_NOCOLON_RE);
|
|
16878
16891
|
if (optMatch) {
|
|
@@ -17251,6 +17264,19 @@ function parseNodeLine(trimmed, lineNum, metaAliasMap, diagnostics, nameAliasMap
|
|
|
17251
17264
|
description = [metadata["description"]];
|
|
17252
17265
|
delete metadata["description"];
|
|
17253
17266
|
}
|
|
17267
|
+
let value;
|
|
17268
|
+
if (metadata["value"] !== void 0) {
|
|
17269
|
+
const raw = metadata["value"];
|
|
17270
|
+
const num = Number(raw);
|
|
17271
|
+
if (Number.isFinite(num)) {
|
|
17272
|
+
value = num;
|
|
17273
|
+
} else {
|
|
17274
|
+
diagnostics.push(
|
|
17275
|
+
makeDgmoError(lineNum, `value must be a number (got "${raw}")`, "error")
|
|
17276
|
+
);
|
|
17277
|
+
}
|
|
17278
|
+
delete metadata["value"];
|
|
17279
|
+
}
|
|
17254
17280
|
if (split.alias) {
|
|
17255
17281
|
nameAliasMap?.set(normalizeName(split.alias), label);
|
|
17256
17282
|
}
|
|
@@ -17259,7 +17285,8 @@ function parseNodeLine(trimmed, lineNum, metaAliasMap, diagnostics, nameAliasMap
|
|
|
17259
17285
|
label,
|
|
17260
17286
|
lineNumber: lineNum,
|
|
17261
17287
|
metadata,
|
|
17262
|
-
...description !== void 0 && { description }
|
|
17288
|
+
...description !== void 0 && { description },
|
|
17289
|
+
...value !== void 0 && { value }
|
|
17263
17290
|
};
|
|
17264
17291
|
}
|
|
17265
17292
|
function splitTargetAndMeta(rest, metaAliasMap) {
|
|
@@ -26469,7 +26496,18 @@ function fitLabelToHeader(label, nodeWidth, maxLines) {
|
|
|
26469
26496
|
const truncated = label.length > maxChars ? label.slice(0, maxChars - 1) + "\u2026" : label;
|
|
26470
26497
|
return { lines: [truncated], fontSize: MIN_NODE_FONT_SIZE };
|
|
26471
26498
|
}
|
|
26472
|
-
function nodeColors(node, tagGroups, activeGroupName, palette, isDark, solid) {
|
|
26499
|
+
function nodeColors(node, tagGroups, activeGroupName, palette, isDark, value, solid) {
|
|
26500
|
+
const neutralFill = mix(palette.bg, palette.text, isDark ? 90 : 95);
|
|
26501
|
+
if (value.active) {
|
|
26502
|
+
const fill3 = node.value !== void 0 ? value.fillForValue(node.value) : neutralFill;
|
|
26503
|
+
const stroke3 = value.hue;
|
|
26504
|
+
const text2 = contrastText(
|
|
26505
|
+
fill3,
|
|
26506
|
+
palette.textOnFillLight,
|
|
26507
|
+
palette.textOnFillDark
|
|
26508
|
+
);
|
|
26509
|
+
return { fill: fill3, stroke: stroke3, text: text2 };
|
|
26510
|
+
}
|
|
26473
26511
|
const tagColor = resolveTagColor(
|
|
26474
26512
|
node.metadata,
|
|
26475
26513
|
[...tagGroups],
|
|
@@ -26578,25 +26616,65 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26578
26616
|
const sGroupLabelZone = sctx.structural(GROUP_LABEL_ZONE);
|
|
26579
26617
|
const sTitleFontSize = sctx.text(TITLE_FONT_SIZE);
|
|
26580
26618
|
const sTitleY = sctx.structural(TITLE_Y);
|
|
26619
|
+
const nodeValues = parsed.nodes.filter((n) => n.value !== void 0).map((n) => n.value);
|
|
26620
|
+
const hasRamp = nodeValues.length > 0;
|
|
26621
|
+
const allNonNegative = hasRamp && nodeValues.every((v) => v >= 0);
|
|
26622
|
+
const rampMin = allNonNegative ? 0 : Math.min(...nodeValues);
|
|
26623
|
+
const rampMax = Math.max(...nodeValues);
|
|
26624
|
+
const rampHue = resolveColor(parsed.boxMetricColor ?? "", palette) ?? palette.primary;
|
|
26625
|
+
const rampBase = isDark ? mix(palette.surface, palette.text, 28) : palette.bg;
|
|
26626
|
+
const fillForValue = (v) => {
|
|
26627
|
+
const t = rampMax > rampMin ? (v - rampMin) / (rampMax - rampMin) : 1;
|
|
26628
|
+
const pct = RAMP_FLOOR + Math.max(0, Math.min(1, t)) * (100 - RAMP_FLOOR);
|
|
26629
|
+
return mix(rampHue, rampBase, pct);
|
|
26630
|
+
};
|
|
26631
|
+
const VALUE_NAME = hasRamp ? parsed.boxMetric?.trim() || "Value" : null;
|
|
26632
|
+
const matchColorGroup = (v) => {
|
|
26633
|
+
const lv = v.trim().toLowerCase();
|
|
26634
|
+
if (lv === "none") return null;
|
|
26635
|
+
const tg = parsed.tagGroups.find((g) => g.name.toLowerCase() === lv);
|
|
26636
|
+
if (tg) return tg.name;
|
|
26637
|
+
if (lv === VALUE_NAME?.toLowerCase()) return VALUE_NAME;
|
|
26638
|
+
return v;
|
|
26639
|
+
};
|
|
26640
|
+
const override = activeTagGroup;
|
|
26641
|
+
let activeGroup;
|
|
26642
|
+
if (override !== void 0) {
|
|
26643
|
+
activeGroup = override === null ? null : matchColorGroup(override);
|
|
26644
|
+
} else if (parsed.options["active-tag"] !== void 0) {
|
|
26645
|
+
activeGroup = matchColorGroup(parsed.options["active-tag"]);
|
|
26646
|
+
} else {
|
|
26647
|
+
activeGroup = VALUE_NAME ?? (parsed.tagGroups.length > 0 ? parsed.tagGroups[0].name : null);
|
|
26648
|
+
}
|
|
26649
|
+
const activeIsValue = VALUE_NAME !== null && activeGroup === VALUE_NAME;
|
|
26650
|
+
const valueGroup = VALUE_NAME !== null ? {
|
|
26651
|
+
name: VALUE_NAME,
|
|
26652
|
+
entries: [],
|
|
26653
|
+
gradient: {
|
|
26654
|
+
min: rampMin,
|
|
26655
|
+
max: rampMax,
|
|
26656
|
+
hue: rampHue,
|
|
26657
|
+
base: rampBase
|
|
26658
|
+
}
|
|
26659
|
+
} : null;
|
|
26660
|
+
const legendGroups = [
|
|
26661
|
+
...valueGroup ? [valueGroup] : [],
|
|
26662
|
+
...parsed.tagGroups
|
|
26663
|
+
];
|
|
26581
26664
|
const reserveHasDescriptions = parsed.nodes.some(
|
|
26582
26665
|
(n) => n.description && n.description.length > 0
|
|
26583
26666
|
);
|
|
26584
|
-
const willRenderLegend =
|
|
26667
|
+
const willRenderLegend = legendGroups.length > 0 || reserveHasDescriptions && controlsHost !== "app";
|
|
26585
26668
|
const sLegendHeight = willRenderLegend ? sctx.structural(
|
|
26586
26669
|
getMaxLegendReservedHeight(
|
|
26587
26670
|
{
|
|
26588
|
-
groups:
|
|
26671
|
+
groups: legendGroups,
|
|
26589
26672
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
26590
26673
|
mode: exportMode ? "export" : "preview"
|
|
26591
26674
|
},
|
|
26592
26675
|
width
|
|
26593
26676
|
)
|
|
26594
26677
|
) : 0;
|
|
26595
|
-
const activeGroup = resolveActiveTagGroup(
|
|
26596
|
-
parsed.tagGroups,
|
|
26597
|
-
parsed.options["active-tag"],
|
|
26598
|
-
activeTagGroup
|
|
26599
|
-
);
|
|
26600
26678
|
const hidden = hiddenTagValues ?? parsed.initialHiddenTagValues;
|
|
26601
26679
|
const nodeMap = /* @__PURE__ */ new Map();
|
|
26602
26680
|
for (const node of parsed.nodes) nodeMap.set(node.label, node);
|
|
@@ -26607,7 +26685,7 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26607
26685
|
const hasAnyDescriptions = parsed.nodes.some(
|
|
26608
26686
|
(n) => n.description && n.description.length > 0
|
|
26609
26687
|
);
|
|
26610
|
-
const needsLegend =
|
|
26688
|
+
const needsLegend = legendGroups.length > 0 || hasAnyDescriptions && onToggleDescriptions;
|
|
26611
26689
|
const legendH = needsLegend ? sLegendHeight + 8 : 0;
|
|
26612
26690
|
const groupLabelsSet = new Set(layout.groups.map((g) => g.label));
|
|
26613
26691
|
let labelZoneExtension = 0;
|
|
@@ -26813,12 +26891,16 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26813
26891
|
activeGroup,
|
|
26814
26892
|
palette,
|
|
26815
26893
|
isDark,
|
|
26894
|
+
{ active: activeIsValue, hue: rampHue, fillForValue },
|
|
26816
26895
|
parsed.options["solid-fill"] === "on"
|
|
26817
26896
|
);
|
|
26818
26897
|
const nodeG = diagramG.append("g").attr("class", "bl-node").attr("transform", `translate(${ln.x},${ln.y})`).attr("data-line-number", node.lineNumber).attr("data-node-id", node.label).style("cursor", onClickItem ? "pointer" : "default").style("--bl-node-stroke", colors.stroke);
|
|
26819
26898
|
for (const [key, val] of Object.entries(node.metadata)) {
|
|
26820
26899
|
nodeG.attr(`data-tag-${key.toLowerCase()}`, val.toLowerCase());
|
|
26821
26900
|
}
|
|
26901
|
+
if (node.value !== void 0) {
|
|
26902
|
+
nodeG.attr("data-value", node.value);
|
|
26903
|
+
}
|
|
26822
26904
|
if (onClickItem) {
|
|
26823
26905
|
nodeG.on("click", (event) => {
|
|
26824
26906
|
const target = event.target;
|
|
@@ -26902,11 +26984,27 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26902
26984
|
nodeG.append("text").attr("x", 0).attr("y", -totalH / 2 + lineH / 2 + li * lineH).attr("text-anchor", "middle").attr("dominant-baseline", "central").attr("font-size", fitted.fontSize).attr("font-weight", "600").attr("fill", colors.text).text(fitted.lines[li]);
|
|
26903
26985
|
}
|
|
26904
26986
|
}
|
|
26987
|
+
if (parsed.showValues && node.value !== void 0) {
|
|
26988
|
+
const valueText = String(node.value);
|
|
26989
|
+
const descShown = !!(desc && desc.length > 0 && !hideDescriptions);
|
|
26990
|
+
if (descShown) {
|
|
26991
|
+
const padX = 6;
|
|
26992
|
+
const padY = 5;
|
|
26993
|
+
const bw = valueText.length * VALUE_FONT_SIZE * CHAR_WIDTH_RATIO2 + 8;
|
|
26994
|
+
const bh = VALUE_FONT_SIZE + 4;
|
|
26995
|
+
const bx = ln.width / 2 - bw - 4;
|
|
26996
|
+
const by = -ln.height / 2 + 4;
|
|
26997
|
+
nodeG.append("rect").attr("x", bx).attr("y", by).attr("width", bw).attr("height", bh).attr("rx", 3).attr("fill", palette.bg).attr("opacity", 0.85);
|
|
26998
|
+
nodeG.append("text").attr("class", "bl-node-value").attr("x", bx + bw - padX).attr("y", by + padY).attr("text-anchor", "end").attr("dominant-baseline", "central").attr("font-size", VALUE_FONT_SIZE).attr("font-weight", "600").attr("fill", palette.textMuted).text(valueText);
|
|
26999
|
+
} else {
|
|
27000
|
+
nodeG.append("text").attr("class", "bl-node-value").attr("x", 0).attr("y", ln.height / 2 - VALUE_FONT_SIZE).attr("text-anchor", "middle").attr("dominant-baseline", "central").attr("font-size", VALUE_FONT_SIZE).attr("font-weight", "600").attr("fill", colors.text).attr("opacity", 0.8).text(valueText);
|
|
27001
|
+
}
|
|
27002
|
+
}
|
|
26905
27003
|
}
|
|
26906
27004
|
const hasDescriptions = parsed.nodes.some(
|
|
26907
27005
|
(n) => n.description && n.description.length > 0
|
|
26908
27006
|
);
|
|
26909
|
-
const hasLegend =
|
|
27007
|
+
const hasLegend = legendGroups.length > 0 || hasDescriptions && controlsHost !== "app";
|
|
26910
27008
|
if (hasLegend) {
|
|
26911
27009
|
let controlsGroup;
|
|
26912
27010
|
if (hasDescriptions && (onToggleDescriptions || controlsHost === "app")) {
|
|
@@ -26924,7 +27022,7 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26924
27022
|
};
|
|
26925
27023
|
}
|
|
26926
27024
|
const legendConfig = {
|
|
26927
|
-
groups:
|
|
27025
|
+
groups: legendGroups,
|
|
26928
27026
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
26929
27027
|
mode: exportMode ? "export" : "preview",
|
|
26930
27028
|
// Keep inactive sibling tag groups visible as collapsed pills so the user
|
|
@@ -26979,7 +27077,7 @@ function renderBoxesAndLinesForExport(container, parsed, layout, palette, isDark
|
|
|
26979
27077
|
}
|
|
26980
27078
|
});
|
|
26981
27079
|
}
|
|
26982
|
-
var d3Selection6, d3Shape4, DIAGRAM_PADDING6, NODE_FONT_SIZE, MIN_NODE_FONT_SIZE, EDGE_LABEL_FONT_SIZE4, EDGE_STROKE_WIDTH5, NODE_STROKE_WIDTH5, NODE_RX, COLLAPSE_BAR_HEIGHT3, ARROWHEAD_W2, ARROWHEAD_H2, DESC_FONT_SIZE, DESC_LINE_HEIGHT, MAX_DESC_LINES, CHAR_WIDTH_RATIO2, NODE_TEXT_PADDING, GROUP_RX, GROUP_LABEL_FONT_SIZE, GROUP_LABEL_ZONE, lineGeneratorLR, lineGeneratorTB;
|
|
27080
|
+
var d3Selection6, d3Shape4, DIAGRAM_PADDING6, NODE_FONT_SIZE, MIN_NODE_FONT_SIZE, EDGE_LABEL_FONT_SIZE4, EDGE_STROKE_WIDTH5, NODE_STROKE_WIDTH5, NODE_RX, COLLAPSE_BAR_HEIGHT3, ARROWHEAD_W2, ARROWHEAD_H2, DESC_FONT_SIZE, DESC_LINE_HEIGHT, MAX_DESC_LINES, CHAR_WIDTH_RATIO2, NODE_TEXT_PADDING, GROUP_RX, GROUP_LABEL_FONT_SIZE, GROUP_LABEL_ZONE, RAMP_FLOOR, VALUE_FONT_SIZE, lineGeneratorLR, lineGeneratorTB;
|
|
26983
27081
|
var init_renderer6 = __esm({
|
|
26984
27082
|
"src/boxes-and-lines/renderer.ts"() {
|
|
26985
27083
|
"use strict";
|
|
@@ -26990,6 +27088,7 @@ var init_renderer6 = __esm({
|
|
|
26990
27088
|
init_legend_layout();
|
|
26991
27089
|
init_title_constants();
|
|
26992
27090
|
init_color_utils();
|
|
27091
|
+
init_colors();
|
|
26993
27092
|
init_tag_groups();
|
|
26994
27093
|
init_inline_markdown();
|
|
26995
27094
|
init_wrapped_desc();
|
|
@@ -27012,6 +27111,8 @@ var init_renderer6 = __esm({
|
|
|
27012
27111
|
GROUP_RX = 8;
|
|
27013
27112
|
GROUP_LABEL_FONT_SIZE = 14;
|
|
27014
27113
|
GROUP_LABEL_ZONE = 32;
|
|
27114
|
+
RAMP_FLOOR = 15;
|
|
27115
|
+
VALUE_FONT_SIZE = 11;
|
|
27015
27116
|
lineGeneratorLR = d3Shape4.line().x((d) => d.x).y((d) => d.y).curve(d3Shape4.curveBasis);
|
|
27016
27117
|
lineGeneratorTB = d3Shape4.line().x((d) => d.x).y((d) => d.y).curve(d3Shape4.curveBasis);
|
|
27017
27118
|
}
|
|
@@ -47566,6 +47667,38 @@ function parsePathRings(d) {
|
|
|
47566
47667
|
if (cur.length) rings.push(cur);
|
|
47567
47668
|
return rings;
|
|
47568
47669
|
}
|
|
47670
|
+
function dropAntimeridianWrapSlivers(d, width, height) {
|
|
47671
|
+
const rings = parsePathRings(d);
|
|
47672
|
+
if (rings.length <= 1) return d;
|
|
47673
|
+
const eps = 0.75;
|
|
47674
|
+
const minArea = 3e-3 * width * height;
|
|
47675
|
+
const ringArea = (r) => {
|
|
47676
|
+
let s = 0;
|
|
47677
|
+
for (let i = 0; i < r.length; i++) {
|
|
47678
|
+
const a = r[i];
|
|
47679
|
+
const b = r[(i + 1) % r.length];
|
|
47680
|
+
s += a[0] * b[1] - b[0] * a[1];
|
|
47681
|
+
}
|
|
47682
|
+
return Math.abs(s) / 2;
|
|
47683
|
+
};
|
|
47684
|
+
const areas = rings.map(ringArea);
|
|
47685
|
+
const maxArea = Math.max(...areas);
|
|
47686
|
+
const onVEdge = (a, b) => Math.abs(a[0]) <= eps && Math.abs(b[0]) <= eps || Math.abs(a[0] - width) <= eps && Math.abs(b[0] - width) <= eps;
|
|
47687
|
+
let dropped = false;
|
|
47688
|
+
const kept = rings.filter((r, idx) => {
|
|
47689
|
+
if (areas[idx] >= maxArea || areas[idx] >= minArea) return true;
|
|
47690
|
+
const touches = r.some((p, i) => onVEdge(p, r[(i + 1) % r.length]));
|
|
47691
|
+
if (touches) {
|
|
47692
|
+
dropped = true;
|
|
47693
|
+
return false;
|
|
47694
|
+
}
|
|
47695
|
+
return true;
|
|
47696
|
+
});
|
|
47697
|
+
if (!dropped) return d;
|
|
47698
|
+
return kept.map(
|
|
47699
|
+
(r) => r.map((p, i) => (i ? "L" : "M") + p[0] + "," + p[1]).join("") + "Z"
|
|
47700
|
+
).join("");
|
|
47701
|
+
}
|
|
47569
47702
|
function layoutMap(resolved, data, size, opts) {
|
|
47570
47703
|
const { palette, isDark } = opts;
|
|
47571
47704
|
const { width, height } = size;
|
|
@@ -47649,7 +47782,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47649
47782
|
const rampBase = isDark ? mix(palette.surface, palette.text, 28) : palette.bg;
|
|
47650
47783
|
const fillForValue = (s) => {
|
|
47651
47784
|
const t = rampMax > rampMin ? (s - rampMin) / (rampMax - rampMin) : 1;
|
|
47652
|
-
const pct =
|
|
47785
|
+
const pct = RAMP_FLOOR2 + Math.max(0, Math.min(1, t)) * (100 - RAMP_FLOOR2);
|
|
47653
47786
|
return mix(rampHue, rampBase, pct);
|
|
47654
47787
|
};
|
|
47655
47788
|
const tagFill = (tags, groupName) => {
|
|
@@ -47708,10 +47841,11 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47708
47841
|
const by0 = cb[0][1];
|
|
47709
47842
|
const cw = cb[1][0] - bx0;
|
|
47710
47843
|
const ch = cb[1][1] - by0;
|
|
47711
|
-
const
|
|
47712
|
-
const
|
|
47713
|
-
const
|
|
47714
|
-
const
|
|
47844
|
+
const topReserve = resolved.title && resolved.pois.length > 0 ? topPad : 0;
|
|
47845
|
+
const ox = 0;
|
|
47846
|
+
const oy = topReserve;
|
|
47847
|
+
const sx = cw > 0 ? width / cw : 1;
|
|
47848
|
+
const sy = ch > 0 ? (height - topReserve) / ch : 1;
|
|
47715
47849
|
stretchParams = { sx, sy, ox, oy, bx0, by0 };
|
|
47716
47850
|
const stretch = (x, y) => [
|
|
47717
47851
|
ox + (x - bx0) * sx,
|
|
@@ -47984,7 +48118,8 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47984
48118
|
const r = regionById.get(iso);
|
|
47985
48119
|
const viewF = shouldCull ? cullFeatureToView(f) : dropFrameFillers(f);
|
|
47986
48120
|
if (!viewF) continue;
|
|
47987
|
-
const
|
|
48121
|
+
const raw = path(viewF) ?? "";
|
|
48122
|
+
const d = fitIsGlobal ? dropAntimeridianWrapSlivers(raw, width, height) : raw;
|
|
47988
48123
|
if (!d) continue;
|
|
47989
48124
|
const isThisLayer = r?.layer === layerKind;
|
|
47990
48125
|
const isForeign = layerKind === "country" && usContext && iso !== "US";
|
|
@@ -48001,6 +48136,9 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
48001
48136
|
} else {
|
|
48002
48137
|
label = f.properties?.name;
|
|
48003
48138
|
}
|
|
48139
|
+
const labelAnchor = WORLD_LABEL_ANCHORS[iso];
|
|
48140
|
+
const c = labelAnchor ? project(labelAnchor[0], labelAnchor[1]) : path.centroid(viewF);
|
|
48141
|
+
const hasCentroid = c != null && Number.isFinite(c[0]) && Number.isFinite(c[1]);
|
|
48004
48142
|
regions.push({
|
|
48005
48143
|
id: iso,
|
|
48006
48144
|
d,
|
|
@@ -48009,6 +48147,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
48009
48147
|
lineNumber,
|
|
48010
48148
|
layer,
|
|
48011
48149
|
...label !== void 0 && { label },
|
|
48150
|
+
...hasCentroid && { labelX: c[0], labelY: c[1] },
|
|
48012
48151
|
...isThisLayer && r.value !== void 0 && { value: r.value },
|
|
48013
48152
|
...isThisLayer && Object.keys(r.tags).length > 0 && { tags: r.tags }
|
|
48014
48153
|
});
|
|
@@ -48449,10 +48588,6 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
48449
48588
|
lineNumber
|
|
48450
48589
|
});
|
|
48451
48590
|
};
|
|
48452
|
-
const WORLD_LABEL_ANCHORS = {
|
|
48453
|
-
US: [-98.5, 39.5]
|
|
48454
|
-
// CONUS geographic centre (near Lebanon, Kansas)
|
|
48455
|
-
};
|
|
48456
48591
|
const REGION_LABEL_GAP = 2;
|
|
48457
48592
|
const regionLabelRect = (cx, cy, text) => {
|
|
48458
48593
|
const w = measureLegendText(text, FONT2) + 2 * REGION_LABEL_GAP;
|
|
@@ -48818,7 +48953,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
48818
48953
|
diagnostics: []
|
|
48819
48954
|
};
|
|
48820
48955
|
}
|
|
48821
|
-
var import_d3_geo2, import_topojson_client2, FIT_PAD,
|
|
48956
|
+
var import_d3_geo2, import_topojson_client2, FIT_PAD, RAMP_FLOOR2, R_DEFAULT, R_MIN, R_MAX, W_MIN, W_MAX, FONT2, WORLD_LABEL_ANCHORS, MAX_CLUSTER_EXTENT_FACTOR, MAX_COLUMN_ROWS, REGION_LABEL_HALO_RATIO, LAND_TINT_LIGHT, LAND_TINT_DARK, TAG_TINT_LIGHT, TAG_TINT_DARK, WATER_TINT_LIGHT, WATER_TINT_DARK, RIVER_WIDTH, COMPACT_WIDTH_PX, RELIEF_MIN_AREA, RELIEF_MIN_DIM, RELIEF_HATCH_SPACING, RELIEF_HATCH_WIDTH, RELIEF_HATCH_STRENGTH, COASTLINE_RING_COUNT, COASTLINE_D0, COASTLINE_STEP, COASTLINE_THICKNESS, COASTLINE_OPACITY_NEAR, COASTLINE_OPACITY_FAR, COASTLINE_MIN_EXTENT, COASTLINE_MIN_EXTENT_GLOBAL, COASTLINE_STROKE_MIX, FOREIGN_TINT_LIGHT, FOREIGN_TINT_DARK, MUTED_FOREIGN_LIGHT, MUTED_FOREIGN_DARK, COLO_R, GOLDEN_ANGLE, STACK_OVERLAP, STACK_RING_MAX, STACK_RING_GAP, FAN_STEP, ARC_CURVE_FRAC, decodeCache, usConusProjection, alaskaProjection, hawaiiProjection, INSET_STATES, inAlaska, inHawaii, FOREIGN_BORDER, US_NON_CONUS;
|
|
48822
48957
|
var init_layout15 = __esm({
|
|
48823
48958
|
"src/map/layout.ts"() {
|
|
48824
48959
|
"use strict";
|
|
@@ -48833,13 +48968,17 @@ var init_layout15 = __esm({
|
|
|
48833
48968
|
init_title_constants();
|
|
48834
48969
|
init_context_labels();
|
|
48835
48970
|
FIT_PAD = 24;
|
|
48836
|
-
|
|
48971
|
+
RAMP_FLOOR2 = 15;
|
|
48837
48972
|
R_DEFAULT = 6;
|
|
48838
48973
|
R_MIN = 4;
|
|
48839
48974
|
R_MAX = 22;
|
|
48840
48975
|
W_MIN = 1.25;
|
|
48841
48976
|
W_MAX = 8;
|
|
48842
48977
|
FONT2 = 11;
|
|
48978
|
+
WORLD_LABEL_ANCHORS = {
|
|
48979
|
+
US: [-98.5, 39.5]
|
|
48980
|
+
// CONUS geographic centre (near Lebanon, Kansas)
|
|
48981
|
+
};
|
|
48843
48982
|
MAX_CLUSTER_EXTENT_FACTOR = 0.18;
|
|
48844
48983
|
MAX_COLUMN_ROWS = 7;
|
|
48845
48984
|
REGION_LABEL_HALO_RATIO = 4.5;
|
|
@@ -48853,9 +48992,9 @@ var init_layout15 = __esm({
|
|
|
48853
48992
|
COMPACT_WIDTH_PX = 480;
|
|
48854
48993
|
RELIEF_MIN_AREA = 12;
|
|
48855
48994
|
RELIEF_MIN_DIM = 2;
|
|
48856
|
-
RELIEF_HATCH_SPACING =
|
|
48857
|
-
RELIEF_HATCH_WIDTH = 0.
|
|
48858
|
-
RELIEF_HATCH_STRENGTH =
|
|
48995
|
+
RELIEF_HATCH_SPACING = 1.5;
|
|
48996
|
+
RELIEF_HATCH_WIDTH = 0.2;
|
|
48997
|
+
RELIEF_HATCH_STRENGTH = 26;
|
|
48859
48998
|
COASTLINE_RING_COUNT = 5;
|
|
48860
48999
|
COASTLINE_D0 = 16e-4;
|
|
48861
49000
|
COASTLINE_STEP = 28e-4;
|
|
@@ -48933,7 +49072,47 @@ function ringToPath(ring) {
|
|
|
48933
49072
|
d += (i ? "L" : "M") + ring[i][0] + "," + ring[i][1];
|
|
48934
49073
|
return d + "Z";
|
|
48935
49074
|
}
|
|
48936
|
-
function
|
|
49075
|
+
function polylineToPath(pts) {
|
|
49076
|
+
let d = "";
|
|
49077
|
+
for (let i = 0; i < pts.length; i++)
|
|
49078
|
+
d += (i ? "L" : "M") + pts[i][0] + "," + pts[i][1];
|
|
49079
|
+
return d;
|
|
49080
|
+
}
|
|
49081
|
+
function ringToCoastPaths(ring, frame) {
|
|
49082
|
+
if (!frame) return [ringToPath(ring)];
|
|
49083
|
+
const n = ring.length;
|
|
49084
|
+
const eps = 0.75;
|
|
49085
|
+
const onL = (x) => Math.abs(x) <= eps;
|
|
49086
|
+
const onR = (x) => Math.abs(x - frame.w) <= eps;
|
|
49087
|
+
const onT = (y) => Math.abs(y) <= eps;
|
|
49088
|
+
const onB = (y) => Math.abs(y - frame.h) <= eps;
|
|
49089
|
+
const isFrameEdge = (a, b) => onL(a[0]) && onL(b[0]) || onR(a[0]) && onR(b[0]) || onT(a[1]) && onT(b[1]) || onB(a[1]) && onB(b[1]);
|
|
49090
|
+
let firstBreak = -1;
|
|
49091
|
+
for (let i = 0; i < n; i++)
|
|
49092
|
+
if (isFrameEdge(ring[i], ring[(i + 1) % n])) {
|
|
49093
|
+
firstBreak = i;
|
|
49094
|
+
break;
|
|
49095
|
+
}
|
|
49096
|
+
if (firstBreak === -1) return [ringToPath(ring)];
|
|
49097
|
+
const paths = [];
|
|
49098
|
+
let cur = [];
|
|
49099
|
+
const start = (firstBreak + 1) % n;
|
|
49100
|
+
for (let k = 0; k < n; k++) {
|
|
49101
|
+
const i = (start + k) % n;
|
|
49102
|
+
const a = ring[i];
|
|
49103
|
+
const b = ring[(i + 1) % n];
|
|
49104
|
+
if (isFrameEdge(a, b)) {
|
|
49105
|
+
if (cur.length >= 2) paths.push(polylineToPath(cur));
|
|
49106
|
+
cur = [];
|
|
49107
|
+
continue;
|
|
49108
|
+
}
|
|
49109
|
+
if (cur.length === 0) cur.push(a);
|
|
49110
|
+
cur.push(b);
|
|
49111
|
+
}
|
|
49112
|
+
if (cur.length >= 2) paths.push(polylineToPath(cur));
|
|
49113
|
+
return paths;
|
|
49114
|
+
}
|
|
49115
|
+
function coastlineOuterRings(regions, minExtent, frame) {
|
|
48937
49116
|
const paths = [];
|
|
48938
49117
|
for (const r of regions) {
|
|
48939
49118
|
const rings = parsePathRings(r.d);
|
|
@@ -48956,7 +49135,7 @@ function coastlineOuterRings(regions, minExtent) {
|
|
|
48956
49135
|
for (let j = 0; j < rings.length; j++)
|
|
48957
49136
|
if (j !== i && pointInRing2(fx, fy, rings[j])) depth++;
|
|
48958
49137
|
if (depth % 2 === 1) continue;
|
|
48959
|
-
paths.push(
|
|
49138
|
+
paths.push(...ringToCoastPaths(ring, frame));
|
|
48960
49139
|
}
|
|
48961
49140
|
}
|
|
48962
49141
|
return paths;
|
|
@@ -49000,6 +49179,10 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
49000
49179
|
const drawRegion = (g, r, strokeWidth) => {
|
|
49001
49180
|
const p = g.append("path").attr("d", r.d).attr("fill", r.fill).attr("stroke", r.stroke).attr("stroke-width", strokeWidth);
|
|
49002
49181
|
if (r.label) p.attr("data-region-name", r.label);
|
|
49182
|
+
if (r.id && r.id !== "lake") p.attr("data-iso", r.id);
|
|
49183
|
+
if (r.labelX !== void 0 && r.labelY !== void 0) {
|
|
49184
|
+
p.attr("data-label-x", r.labelX).attr("data-label-y", r.labelY);
|
|
49185
|
+
}
|
|
49003
49186
|
if (r.layer !== "base") {
|
|
49004
49187
|
p.classed("dgmo-map-region", true).attr("data-region", r.id);
|
|
49005
49188
|
if (r.value !== void 0) p.attr("data-value", r.value);
|
|
@@ -49029,7 +49212,7 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
49029
49212
|
const landClip = defs.append("clipPath").attr("id", landClipId);
|
|
49030
49213
|
for (const r of layout.regions)
|
|
49031
49214
|
if (r.id !== "lake") landClip.append("path").attr("d", r.d);
|
|
49032
|
-
const gRelief = svg.append("g").attr("clip-path", `url(#${landClipId})`).append("g").attr("class", "dgmo-map-relief").attr("clip-path", `url(#${rangeClipId})`).attr("stroke", h.color).attr("stroke-width", h.width).attr("vector-effect", "non-scaling-stroke");
|
|
49215
|
+
const gRelief = svg.append("g").attr("clip-path", `url(#${landClipId})`).style("pointer-events", "none").append("g").attr("class", "dgmo-map-relief").attr("clip-path", `url(#${rangeClipId})`).attr("stroke", h.color).attr("stroke-width", h.width).attr("vector-effect", "non-scaling-stroke");
|
|
49033
49216
|
for (let y = h.spacing; y < height; y += h.spacing) {
|
|
49034
49217
|
gRelief.append("line").attr("x1", 0).attr("y1", y).attr("x2", width).attr("y2", y);
|
|
49035
49218
|
}
|
|
@@ -49050,10 +49233,16 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
49050
49233
|
mask.append("path").attr("d", d).attr("fill", "black").attr("stroke", "black").attr("stroke-width", 2 * reach).attr("stroke-linejoin", "round");
|
|
49051
49234
|
}
|
|
49052
49235
|
}
|
|
49053
|
-
const gWater = svg.append("g").attr("class", "dgmo-map-water-lines").attr("fill", "none").attr("mask", `url(#${maskId})`);
|
|
49236
|
+
const gWater = svg.append("g").attr("class", "dgmo-map-water-lines").attr("fill", "none").style("pointer-events", "none").attr("mask", `url(#${maskId})`);
|
|
49054
49237
|
appendWaterLines(
|
|
49055
49238
|
gWater,
|
|
49056
|
-
|
|
49239
|
+
// Pass the canvas frame so edges collinear with it (the antimeridian on a
|
|
49240
|
+
// world map, regional clipExtent cuts) don't get ringed as fake coast —
|
|
49241
|
+
// land runs cleanly to the render-area edge.
|
|
49242
|
+
coastlineOuterRings(layout.regions, cs.minExtent, {
|
|
49243
|
+
w: width,
|
|
49244
|
+
h: height
|
|
49245
|
+
}),
|
|
49057
49246
|
cs,
|
|
49058
49247
|
layout.background
|
|
49059
49248
|
);
|
|
@@ -49067,7 +49256,7 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
49067
49256
|
gWater.append("path").attr("d", ds.join(" ")).attr("stroke", stroke2).attr("stroke-width", 0.5).attr("stroke-linejoin", "round");
|
|
49068
49257
|
}
|
|
49069
49258
|
if (layout.rivers.length) {
|
|
49070
|
-
const gRivers = svg.append("g").attr("class", "dgmo-map-rivers").attr("fill", "none");
|
|
49259
|
+
const gRivers = svg.append("g").attr("class", "dgmo-map-rivers").attr("fill", "none").style("pointer-events", "none");
|
|
49071
49260
|
for (const r of layout.rivers) {
|
|
49072
49261
|
gRivers.append("path").attr("d", r.d).attr("stroke", r.color).attr("stroke-width", r.width).attr("stroke-linecap", "round").attr("stroke-linejoin", "round");
|
|
49073
49262
|
}
|
|
@@ -49108,7 +49297,7 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
49108
49297
|
const d = box.points.map((p, i) => `${i ? "L" : "M"}${p[0]},${p[1]}`).join("") + "Z";
|
|
49109
49298
|
clip.append("path").attr("d", d);
|
|
49110
49299
|
}
|
|
49111
|
-
const gInsetWater = insetG.append("g").attr("clip-path", `url(#${clipId})`).append("g").attr("class", "dgmo-map-inset-water-lines").attr("fill", "none").attr("mask", `url(#${maskId})`);
|
|
49300
|
+
const gInsetWater = insetG.append("g").attr("clip-path", `url(#${clipId})`).append("g").attr("class", "dgmo-map-inset-water-lines").attr("fill", "none").style("pointer-events", "none").attr("mask", `url(#${maskId})`);
|
|
49112
49301
|
appendWaterLines(
|
|
49113
49302
|
gInsetWater,
|
|
49114
49303
|
coastlineOuterRings(layout.insetRegions, cs.minExtent),
|
|
@@ -55126,10 +55315,12 @@ function renderTimelineHorizontalTimeSort(container, parsed, palette, isDark, se
|
|
|
55126
55315
|
const markerLabelY = markerReserve ? -(topScaleH + MARKER_ROW_H / 2) : 0;
|
|
55127
55316
|
const eraLabelY = eraReserve ? -(topScaleH + markerReserve + ERA_ROW_H / 2) : 0;
|
|
55128
55317
|
const innerWidth = width - margin.left - margin.right;
|
|
55129
|
-
const
|
|
55130
|
-
const rowH = Math.min(ctx.structural(28),
|
|
55318
|
+
const availInnerHeight = height - margin.top - margin.bottom;
|
|
55319
|
+
const rowH = Math.min(ctx.structural(28), availInnerHeight / sorted.length);
|
|
55320
|
+
const innerHeight = rowH * sorted.length;
|
|
55321
|
+
const usedHeight = margin.top + innerHeight + margin.bottom;
|
|
55131
55322
|
const xScale = d3Scale2.scaleLinear().domain([minDate - datePadding, maxDate + datePadding]).range([0, innerWidth]);
|
|
55132
|
-
const svg = d3Selection23.select(container).append("svg").attr("width", width).attr("height",
|
|
55323
|
+
const svg = d3Selection23.select(container).append("svg").attr("width", width).attr("height", usedHeight).attr("viewBox", `0 0 ${width} ${usedHeight}`).attr("preserveAspectRatio", "xMidYMin meet").style("background", bgColor);
|
|
55133
55324
|
if (ctx.isBelowFloor) {
|
|
55134
55325
|
svg.attr("width", "100%");
|
|
55135
55326
|
}
|
|
@@ -60506,7 +60697,9 @@ var COMPLETION_REGISTRY = /* @__PURE__ */ new Map([
|
|
|
60506
60697
|
withGlobals({
|
|
60507
60698
|
direction: { description: "Layout direction", values: ["LR", "TB"] },
|
|
60508
60699
|
"active-tag": { description: "Active tag group name" },
|
|
60509
|
-
hide: { description: "Hide tag:value pairs" }
|
|
60700
|
+
hide: { description: "Hide tag:value pairs" },
|
|
60701
|
+
"box-metric": { description: "Metric label for the value ramp" },
|
|
60702
|
+
"show-values": { description: "Print box values as text" }
|
|
60510
60703
|
})
|
|
60511
60704
|
],
|
|
60512
60705
|
[
|
|
@@ -60734,13 +60927,10 @@ var PIPE_METADATA = /* @__PURE__ */ new Map([
|
|
|
60734
60927
|
"boxes-and-lines",
|
|
60735
60928
|
{
|
|
60736
60929
|
node: {
|
|
60737
|
-
description: { description: "Node description text" }
|
|
60930
|
+
description: { description: "Node description text" },
|
|
60931
|
+
value: { description: "Numeric value for the metric ramp" }
|
|
60738
60932
|
},
|
|
60739
|
-
edge: {
|
|
60740
|
-
width: { description: "Edge stroke width in pixels" },
|
|
60741
|
-
split: { description: "Traffic split percentage" },
|
|
60742
|
-
fanout: { description: "Fanout multiplier (integer >= 1)" }
|
|
60743
|
-
}
|
|
60933
|
+
edge: {}
|
|
60744
60934
|
}
|
|
60745
60935
|
],
|
|
60746
60936
|
[
|
package/dist/internal.d.cts
CHANGED
|
@@ -2500,6 +2500,9 @@ interface BLNode {
|
|
|
2500
2500
|
readonly lineNumber: number;
|
|
2501
2501
|
readonly metadata: Readonly<Record<string, string>>;
|
|
2502
2502
|
readonly description?: readonly string[];
|
|
2503
|
+
/** Numeric measure lifted from `value: X` metadata (mirror of map's
|
|
2504
|
+
* `region.value`). Drives the value ramp / choropleth tinting. */
|
|
2505
|
+
readonly value?: number;
|
|
2503
2506
|
}
|
|
2504
2507
|
interface BLEdge {
|
|
2505
2508
|
readonly source: string;
|
|
@@ -2527,6 +2530,12 @@ interface ParsedBoxesAndLines {
|
|
|
2527
2530
|
readonly options: Readonly<Record<string, string>>;
|
|
2528
2531
|
readonly initialHiddenTagValues: ReadonlyMap<string, ReadonlySet<string>>;
|
|
2529
2532
|
readonly direction: 'LR' | 'TB';
|
|
2533
|
+
/** `box-metric <label> [color]` — names the value-ramp dimension and
|
|
2534
|
+
* optionally sets its hue. Mirror of map's `region-metric`. */
|
|
2535
|
+
readonly boxMetric?: string;
|
|
2536
|
+
readonly boxMetricColor?: string;
|
|
2537
|
+
/** `show-values` — print each box's numeric value as text (opt-in). */
|
|
2538
|
+
readonly showValues?: boolean;
|
|
2530
2539
|
readonly diagnostics: readonly DgmoError[];
|
|
2531
2540
|
readonly error: string | null;
|
|
2532
2541
|
}
|
|
@@ -4672,6 +4681,14 @@ interface MapLayoutRegion {
|
|
|
4672
4681
|
/** The region's tag values keyed by group (lowercased) — emitted as
|
|
4673
4682
|
* `data-tag-<group>` so the app can highlight on legend-entry hover. */
|
|
4674
4683
|
readonly tags?: Readonly<Record<string, string>>;
|
|
4684
|
+
/** Area-weighted screen centroid (px) of the DRAWN geometry — emitted as
|
|
4685
|
+
* `data-label-x`/`data-label-y` so the app can anchor the hover label here
|
|
4686
|
+
* instead of the path's bounding-box centre. The bbox centre breaks for
|
|
4687
|
+
* antimeridian crossers (Russia's wrapped Chukotka sliver pins the box's left
|
|
4688
|
+
* edge to the far side of the map, dropping the centre into the Atlantic); the
|
|
4689
|
+
* area-weighted centroid stays on the body. Honours WORLD_LABEL_ANCHORS. */
|
|
4690
|
+
readonly labelX?: number;
|
|
4691
|
+
readonly labelY?: number;
|
|
4675
4692
|
}
|
|
4676
4693
|
/** A framed inset "cutout" (albers-usa AK/HI), in screen px. The frame is a
|
|
4677
4694
|
* quad whose TOP edge is angled to ride just under the conus southern coast,
|
package/dist/internal.d.ts
CHANGED
|
@@ -2500,6 +2500,9 @@ interface BLNode {
|
|
|
2500
2500
|
readonly lineNumber: number;
|
|
2501
2501
|
readonly metadata: Readonly<Record<string, string>>;
|
|
2502
2502
|
readonly description?: readonly string[];
|
|
2503
|
+
/** Numeric measure lifted from `value: X` metadata (mirror of map's
|
|
2504
|
+
* `region.value`). Drives the value ramp / choropleth tinting. */
|
|
2505
|
+
readonly value?: number;
|
|
2503
2506
|
}
|
|
2504
2507
|
interface BLEdge {
|
|
2505
2508
|
readonly source: string;
|
|
@@ -2527,6 +2530,12 @@ interface ParsedBoxesAndLines {
|
|
|
2527
2530
|
readonly options: Readonly<Record<string, string>>;
|
|
2528
2531
|
readonly initialHiddenTagValues: ReadonlyMap<string, ReadonlySet<string>>;
|
|
2529
2532
|
readonly direction: 'LR' | 'TB';
|
|
2533
|
+
/** `box-metric <label> [color]` — names the value-ramp dimension and
|
|
2534
|
+
* optionally sets its hue. Mirror of map's `region-metric`. */
|
|
2535
|
+
readonly boxMetric?: string;
|
|
2536
|
+
readonly boxMetricColor?: string;
|
|
2537
|
+
/** `show-values` — print each box's numeric value as text (opt-in). */
|
|
2538
|
+
readonly showValues?: boolean;
|
|
2530
2539
|
readonly diagnostics: readonly DgmoError[];
|
|
2531
2540
|
readonly error: string | null;
|
|
2532
2541
|
}
|
|
@@ -4672,6 +4681,14 @@ interface MapLayoutRegion {
|
|
|
4672
4681
|
/** The region's tag values keyed by group (lowercased) — emitted as
|
|
4673
4682
|
* `data-tag-<group>` so the app can highlight on legend-entry hover. */
|
|
4674
4683
|
readonly tags?: Readonly<Record<string, string>>;
|
|
4684
|
+
/** Area-weighted screen centroid (px) of the DRAWN geometry — emitted as
|
|
4685
|
+
* `data-label-x`/`data-label-y` so the app can anchor the hover label here
|
|
4686
|
+
* instead of the path's bounding-box centre. The bbox centre breaks for
|
|
4687
|
+
* antimeridian crossers (Russia's wrapped Chukotka sliver pins the box's left
|
|
4688
|
+
* edge to the far side of the map, dropping the centre into the Atlantic); the
|
|
4689
|
+
* area-weighted centroid stays on the body. Honours WORLD_LABEL_ANCHORS. */
|
|
4690
|
+
readonly labelX?: number;
|
|
4691
|
+
readonly labelY?: number;
|
|
4675
4692
|
}
|
|
4676
4693
|
/** A framed inset "cutout" (albers-usa AK/HI), in screen px. The frame is a
|
|
4677
4694
|
* quad whose TOP edge is angled to ride just under the conus southern coast,
|