@diagrammo/dgmo 0.23.0 → 0.24.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 +152 -73
- package/dist/advanced.d.cts +35 -19
- package/dist/advanced.d.ts +35 -19
- package/dist/advanced.js +152 -73
- package/dist/auto.cjs +153 -74
- package/dist/auto.js +110 -110
- package/dist/auto.mjs +153 -74
- package/dist/cli.cjs +150 -150
- package/dist/index.cjs +284 -73
- package/dist/index.d.cts +37 -1
- package/dist/index.d.ts +37 -1
- package/dist/index.js +282 -73
- package/dist/internal.cjs +152 -73
- package/dist/internal.d.cts +35 -19
- package/dist/internal.d.ts +35 -19
- package/dist/internal.js +152 -73
- package/docs/language-reference.md +3 -2
- package/package.json +1 -1
- package/src/boxes-and-lines/renderer.ts +98 -51
- package/src/d3.ts +22 -10
- package/src/index.ts +8 -0
- package/src/map/dimensions.ts +21 -5
- package/src/map/layout.ts +57 -46
- package/src/map/legend-band.ts +99 -0
- package/src/map/renderer.ts +10 -28
- package/src/map/resolver.ts +43 -1
- package/src/map/types.ts +20 -0
- package/src/utils/svg-embed.ts +193 -0
package/dist/advanced.cjs
CHANGED
|
@@ -26631,7 +26631,7 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26631
26631
|
const VALUE_NAME = hasRamp ? parsed.boxMetric?.trim() || "Value" : null;
|
|
26632
26632
|
const matchColorGroup = (v) => {
|
|
26633
26633
|
const lv = v.trim().toLowerCase();
|
|
26634
|
-
if (lv === "none") return null;
|
|
26634
|
+
if (lv === "" || lv === "none") return null;
|
|
26635
26635
|
const tg = parsed.tagGroups.find((g) => g.name.toLowerCase() === lv);
|
|
26636
26636
|
if (tg) return tg.name;
|
|
26637
26637
|
if (lv === VALUE_NAME?.toLowerCase()) return VALUE_NAME;
|
|
@@ -26972,6 +26972,22 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26972
26972
|
const tooltipText = fullText.length > 200 ? fullText.slice(0, 199) + "\u2026" : fullText;
|
|
26973
26973
|
nodeG.append("title").text(tooltipText);
|
|
26974
26974
|
}
|
|
26975
|
+
} else if (parsed.showValues && node.value !== void 0) {
|
|
26976
|
+
const valueLabel = parsed.boxMetric ? `${parsed.boxMetric}: ${node.value}` : String(node.value);
|
|
26977
|
+
const headerH = ln.height / 2;
|
|
26978
|
+
const sepY = -ln.height / 2 + headerH;
|
|
26979
|
+
const fitted = fitLabelToHeader(node.label, ln.width, 2);
|
|
26980
|
+
const labelLineH = fitted.fontSize * 1.3;
|
|
26981
|
+
const labelTotalH = fitted.lines.length * labelLineH;
|
|
26982
|
+
const headerCenterY = -ln.height / 2 + headerH / 2;
|
|
26983
|
+
for (let li = 0; li < fitted.lines.length; li++) {
|
|
26984
|
+
nodeG.append("text").attr("x", 0).attr(
|
|
26985
|
+
"y",
|
|
26986
|
+
headerCenterY - labelTotalH / 2 + labelLineH / 2 + li * labelLineH
|
|
26987
|
+
).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]);
|
|
26988
|
+
}
|
|
26989
|
+
nodeG.append("line").attr("x1", -ln.width / 2).attr("y1", sepY).attr("x2", ln.width / 2).attr("y2", sepY).attr("stroke", colors.stroke).attr("stroke-opacity", 0.3).attr("stroke-width", 1);
|
|
26990
|
+
nodeG.append("text").attr("class", "bl-node-value").attr("x", 0).attr("y", (sepY + ln.height / 2) / 2).attr("text-anchor", "middle").attr("dominant-baseline", "central").attr("font-size", VALUE_FONT_SIZE).attr("fill", colors.text).attr("opacity", 0.85).text(valueLabel);
|
|
26975
26991
|
} else {
|
|
26976
26992
|
const maxLabelLines = Math.max(
|
|
26977
26993
|
2,
|
|
@@ -26984,21 +27000,16 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26984
27000
|
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]);
|
|
26985
27001
|
}
|
|
26986
27002
|
}
|
|
26987
|
-
if (parsed.showValues && node.value !== void 0) {
|
|
27003
|
+
if (parsed.showValues && node.value !== void 0 && desc && desc.length > 0 && !hideDescriptions) {
|
|
26988
27004
|
const valueText = String(node.value);
|
|
26989
|
-
const
|
|
26990
|
-
|
|
26991
|
-
|
|
26992
|
-
|
|
26993
|
-
|
|
26994
|
-
|
|
26995
|
-
|
|
26996
|
-
|
|
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
|
-
}
|
|
27005
|
+
const padX = 6;
|
|
27006
|
+
const padY = 5;
|
|
27007
|
+
const bw = valueText.length * VALUE_FONT_SIZE * CHAR_WIDTH_RATIO2 + 8;
|
|
27008
|
+
const bh = VALUE_FONT_SIZE + 4;
|
|
27009
|
+
const bx = Math.max(-ln.width / 2 + 4, ln.width / 2 - bw - 4);
|
|
27010
|
+
const by = -ln.height / 2 + 4;
|
|
27011
|
+
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);
|
|
27012
|
+
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);
|
|
27002
27013
|
}
|
|
27003
27014
|
}
|
|
27004
27015
|
const hasDescriptions = parsed.nodes.some(
|
|
@@ -27094,7 +27105,7 @@ var init_renderer6 = __esm({
|
|
|
27094
27105
|
init_wrapped_desc();
|
|
27095
27106
|
init_scaling();
|
|
27096
27107
|
DIAGRAM_PADDING6 = 20;
|
|
27097
|
-
NODE_FONT_SIZE =
|
|
27108
|
+
NODE_FONT_SIZE = 11;
|
|
27098
27109
|
MIN_NODE_FONT_SIZE = 9;
|
|
27099
27110
|
EDGE_LABEL_FONT_SIZE4 = 11;
|
|
27100
27111
|
EDGE_STROKE_WIDTH5 = 1.5;
|
|
@@ -47054,7 +47065,11 @@ function resolveMap(parsed, data) {
|
|
|
47054
47065
|
if (bb && !isWholeSphere(bb)) containerBoxes.push(bb);
|
|
47055
47066
|
}
|
|
47056
47067
|
const containerUnion = unionExtent(containerBoxes, points);
|
|
47057
|
-
if (containerUnion)
|
|
47068
|
+
if (containerUnion)
|
|
47069
|
+
extent2 = pad(
|
|
47070
|
+
clampContainerToCluster(containerUnion, points),
|
|
47071
|
+
PAD_FRACTION
|
|
47072
|
+
);
|
|
47058
47073
|
}
|
|
47059
47074
|
if (isPoiOnly) {
|
|
47060
47075
|
const cx = (extent2[0][0] + extent2[1][0]) / 2;
|
|
@@ -47135,6 +47150,22 @@ function mostCommonCountry(regions, poiCountries) {
|
|
|
47135
47150
|
}
|
|
47136
47151
|
return best;
|
|
47137
47152
|
}
|
|
47153
|
+
function clampContainerToCluster(container, points) {
|
|
47154
|
+
const poi = unionExtent([], points);
|
|
47155
|
+
if (!poi) return container;
|
|
47156
|
+
let [[west, south], [east, north]] = container;
|
|
47157
|
+
const [[pWest, pSouth], [pEast, pNorth]] = poi;
|
|
47158
|
+
south = Math.max(south, pSouth - CONTAINER_OVERSHOOT_DEG);
|
|
47159
|
+
north = Math.min(north, pNorth + CONTAINER_OVERSHOOT_DEG);
|
|
47160
|
+
if (east <= 180 && pEast <= 180) {
|
|
47161
|
+
west = Math.max(west, pWest - CONTAINER_OVERSHOOT_DEG);
|
|
47162
|
+
east = Math.min(east, pEast + CONTAINER_OVERSHOOT_DEG);
|
|
47163
|
+
}
|
|
47164
|
+
return [
|
|
47165
|
+
[west, south],
|
|
47166
|
+
[east, north]
|
|
47167
|
+
];
|
|
47168
|
+
}
|
|
47138
47169
|
function pad(e, frac) {
|
|
47139
47170
|
const dLon = (e[1][0] - e[0][0]) * frac || 1;
|
|
47140
47171
|
const dLat = (e[1][1] - e[0][1]) * frac || 1;
|
|
@@ -47147,7 +47178,7 @@ function firstError(diags) {
|
|
|
47147
47178
|
const e = diags.find((d) => d.severity === "error");
|
|
47148
47179
|
return e ? formatDgmoError(e) : null;
|
|
47149
47180
|
}
|
|
47150
|
-
var WORLD_SPAN, MERCATOR_MAX_LAT, PAD_FRACTION, REGION_PAD_FRACTION, WORLD_LAT_SOUTH, WORLD_LAT_NORTH, POI_ZOOM_FLOOR_DEG, US_NATIONAL_LON_SPAN, REGION_ALIASES, US_STATE_POSTAL;
|
|
47181
|
+
var WORLD_SPAN, MERCATOR_MAX_LAT, PAD_FRACTION, REGION_PAD_FRACTION, WORLD_LAT_SOUTH, WORLD_LAT_NORTH, POI_ZOOM_FLOOR_DEG, CONTAINER_OVERSHOOT_DEG, US_NATIONAL_LON_SPAN, REGION_ALIASES, US_STATE_POSTAL;
|
|
47151
47182
|
var init_resolver2 = __esm({
|
|
47152
47183
|
"src/map/resolver.ts"() {
|
|
47153
47184
|
"use strict";
|
|
@@ -47160,6 +47191,7 @@ var init_resolver2 = __esm({
|
|
|
47160
47191
|
WORLD_LAT_SOUTH = -58;
|
|
47161
47192
|
WORLD_LAT_NORTH = 78;
|
|
47162
47193
|
POI_ZOOM_FLOOR_DEG = 7;
|
|
47194
|
+
CONTAINER_OVERSHOOT_DEG = 8;
|
|
47163
47195
|
US_NATIONAL_LON_SPAN = 48;
|
|
47164
47196
|
REGION_ALIASES = {
|
|
47165
47197
|
// Common everyday names → the Natural-Earth display name actually shipped.
|
|
@@ -47238,6 +47270,55 @@ var init_resolver2 = __esm({
|
|
|
47238
47270
|
}
|
|
47239
47271
|
});
|
|
47240
47272
|
|
|
47273
|
+
// src/map/legend-band.ts
|
|
47274
|
+
function mapLegendGroups(legend) {
|
|
47275
|
+
const ramp = legend.ramp;
|
|
47276
|
+
const scoreGroup = ramp ? {
|
|
47277
|
+
name: ramp.metric?.trim() || "Value",
|
|
47278
|
+
entries: [],
|
|
47279
|
+
gradient: {
|
|
47280
|
+
min: ramp.min,
|
|
47281
|
+
max: ramp.max,
|
|
47282
|
+
hue: ramp.hue,
|
|
47283
|
+
base: ramp.base
|
|
47284
|
+
}
|
|
47285
|
+
} : null;
|
|
47286
|
+
const tagGroups = legend.tagGroups.filter((g) => g.entries.length > 0).map((g) => ({ name: g.name, entries: [...g.entries] }));
|
|
47287
|
+
return [...scoreGroup ? [scoreGroup] : [], ...tagGroups];
|
|
47288
|
+
}
|
|
47289
|
+
function mapLegendConfig(groups, mode) {
|
|
47290
|
+
return {
|
|
47291
|
+
groups,
|
|
47292
|
+
position: { placement: "top-center", titleRelation: "below-title" },
|
|
47293
|
+
mode,
|
|
47294
|
+
showEmptyGroups: false,
|
|
47295
|
+
showInactivePills: true
|
|
47296
|
+
};
|
|
47297
|
+
}
|
|
47298
|
+
function mapLegendTop(hasTitle, hasSubtitle) {
|
|
47299
|
+
return (hasTitle ? TITLE_Y + TITLE_FONT_SIZE : 0) + (hasSubtitle ? TITLE_FONT_SIZE : 0) + LEGEND_TOP_GAP2;
|
|
47300
|
+
}
|
|
47301
|
+
function mapLegendBand(legend, opts) {
|
|
47302
|
+
if (!legend) return 0;
|
|
47303
|
+
const groups = mapLegendGroups(legend);
|
|
47304
|
+
if (groups.length === 0) return 0;
|
|
47305
|
+
const config = mapLegendConfig(groups, opts.mode);
|
|
47306
|
+
const state = { activeGroup: legend.activeGroup };
|
|
47307
|
+
const { height } = computeLegendLayout(config, state, opts.width);
|
|
47308
|
+
if (height <= 0) return 0;
|
|
47309
|
+
return mapLegendTop(opts.hasTitle, opts.hasSubtitle) + height + LEGEND_BOTTOM_GAP2;
|
|
47310
|
+
}
|
|
47311
|
+
var LEGEND_TOP_GAP2, LEGEND_BOTTOM_GAP2;
|
|
47312
|
+
var init_legend_band = __esm({
|
|
47313
|
+
"src/map/legend-band.ts"() {
|
|
47314
|
+
"use strict";
|
|
47315
|
+
init_legend_layout();
|
|
47316
|
+
init_title_constants();
|
|
47317
|
+
LEGEND_TOP_GAP2 = 8;
|
|
47318
|
+
LEGEND_BOTTOM_GAP2 = 10;
|
|
47319
|
+
}
|
|
47320
|
+
});
|
|
47321
|
+
|
|
47241
47322
|
// src/map/colorize.ts
|
|
47242
47323
|
function assignColors(isos, adjacency) {
|
|
47243
47324
|
const sorted = [...isos].sort();
|
|
@@ -47818,12 +47899,43 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47818
47899
|
return tagFill(r.tags, activeGroup) ?? neutralFill;
|
|
47819
47900
|
};
|
|
47820
47901
|
const regionById = new Map(resolved.regions.map((r) => [r.iso, r]));
|
|
47902
|
+
let legend = null;
|
|
47903
|
+
if (!resolved.directives.noLegend) {
|
|
47904
|
+
const legendTagGroups = resolved.tagGroups.map((g) => ({
|
|
47905
|
+
name: g.name,
|
|
47906
|
+
entries: g.entries.map((e) => ({ value: e.value, color: e.color }))
|
|
47907
|
+
}));
|
|
47908
|
+
if (legendTagGroups.length > 0 || hasRamp) {
|
|
47909
|
+
legend = {
|
|
47910
|
+
tagGroups: legendTagGroups,
|
|
47911
|
+
activeGroup,
|
|
47912
|
+
...hasRamp && {
|
|
47913
|
+
ramp: {
|
|
47914
|
+
...resolved.directives.regionMetric !== void 0 && {
|
|
47915
|
+
metric: resolved.directives.regionMetric
|
|
47916
|
+
},
|
|
47917
|
+
min: rampMin,
|
|
47918
|
+
max: rampMax,
|
|
47919
|
+
hue: rampHue,
|
|
47920
|
+
base: rampBase
|
|
47921
|
+
}
|
|
47922
|
+
}
|
|
47923
|
+
};
|
|
47924
|
+
}
|
|
47925
|
+
}
|
|
47821
47926
|
const TITLE_GAP2 = 16;
|
|
47822
47927
|
let topPad = FIT_PAD;
|
|
47823
47928
|
if (resolved.title && resolved.pois.length > 0) {
|
|
47824
47929
|
const bannerBottom = (resolved.subtitle ? TITLE_Y + TITLE_FONT_SIZE : TITLE_Y) + TITLE_FONT_SIZE / 2;
|
|
47825
47930
|
topPad = Math.max(FIT_PAD, bannerBottom + TITLE_GAP2);
|
|
47826
47931
|
}
|
|
47932
|
+
const legendBand = mapLegendBand(legend, {
|
|
47933
|
+
width,
|
|
47934
|
+
mode: opts.legendMode ?? "preview",
|
|
47935
|
+
hasTitle: Boolean(resolved.title),
|
|
47936
|
+
hasSubtitle: Boolean(resolved.subtitle)
|
|
47937
|
+
});
|
|
47938
|
+
if (legendBand > topPad) topPad = legendBand;
|
|
47827
47939
|
const fitBox = [
|
|
47828
47940
|
[FIT_PAD, topPad],
|
|
47829
47941
|
[
|
|
@@ -47841,7 +47953,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47841
47953
|
const by0 = cb[0][1];
|
|
47842
47954
|
const cw = cb[1][0] - bx0;
|
|
47843
47955
|
const ch = cb[1][1] - by0;
|
|
47844
|
-
const topReserve = resolved.title && resolved.pois.length > 0 ? topPad : 0;
|
|
47956
|
+
const topReserve = resolved.title && resolved.pois.length > 0 || legendBand > 0 ? topPad : 0;
|
|
47845
47957
|
const ox = 0;
|
|
47846
47958
|
const oy = topReserve;
|
|
47847
47959
|
const sx = cw > 0 ? width / cw : 1;
|
|
@@ -48905,30 +49017,6 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
48905
49017
|
});
|
|
48906
49018
|
labels.push(...contextLabels);
|
|
48907
49019
|
}
|
|
48908
|
-
let legend = null;
|
|
48909
|
-
if (!resolved.directives.noLegend) {
|
|
48910
|
-
const tagGroups = resolved.tagGroups.map((g) => ({
|
|
48911
|
-
name: g.name,
|
|
48912
|
-
entries: g.entries.map((e) => ({ value: e.value, color: e.color }))
|
|
48913
|
-
}));
|
|
48914
|
-
if (tagGroups.length > 0 || hasRamp) {
|
|
48915
|
-
legend = {
|
|
48916
|
-
tagGroups,
|
|
48917
|
-
activeGroup,
|
|
48918
|
-
...hasRamp && {
|
|
48919
|
-
ramp: {
|
|
48920
|
-
...resolved.directives.regionMetric !== void 0 && {
|
|
48921
|
-
metric: resolved.directives.regionMetric
|
|
48922
|
-
},
|
|
48923
|
-
min: rampMin,
|
|
48924
|
-
max: rampMax,
|
|
48925
|
-
hue: rampHue,
|
|
48926
|
-
base: rampBase
|
|
48927
|
-
}
|
|
48928
|
-
}
|
|
48929
|
-
};
|
|
48930
|
-
}
|
|
48931
|
-
}
|
|
48932
49020
|
return {
|
|
48933
49021
|
width,
|
|
48934
49022
|
height,
|
|
@@ -48966,6 +49054,7 @@ var init_layout15 = __esm({
|
|
|
48966
49054
|
init_label_layout();
|
|
48967
49055
|
init_legend_constants();
|
|
48968
49056
|
init_title_constants();
|
|
49057
|
+
init_legend_band();
|
|
48969
49058
|
init_context_labels();
|
|
48970
49059
|
FIT_PAD = 24;
|
|
48971
49060
|
RAMP_FLOOR2 = 15;
|
|
@@ -49165,6 +49254,9 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
49165
49254
|
// stretch-distorting. The in-app preview pane passes no exportDims → unset →
|
|
49166
49255
|
// keeps the global stretch-fill.
|
|
49167
49256
|
preferContain: exportDims?.preferContain ?? false,
|
|
49257
|
+
// Reserve the legend band for the mode actually drawn below (export shows
|
|
49258
|
+
// only the active group; preview keeps the inactive pills).
|
|
49259
|
+
legendMode: exportDims ? "export" : "preview",
|
|
49168
49260
|
...activeGroupOverride !== void 0 && {
|
|
49169
49261
|
activeGroup: activeGroupOverride
|
|
49170
49262
|
}
|
|
@@ -49456,30 +49548,12 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
49456
49548
|
if (layout.legend) {
|
|
49457
49549
|
const legendY = (layout.title ? TITLE_Y + TITLE_FONT_SIZE : 0) + (layout.subtitle ? TITLE_FONT_SIZE : 0) + 8;
|
|
49458
49550
|
const legendG = svg.append("g").attr("class", "dgmo-map-legend").attr("transform", `translate(0, ${legendY})`);
|
|
49459
|
-
const
|
|
49460
|
-
const scoreGroup = ramp ? {
|
|
49461
|
-
name: ramp.metric?.trim() || "Value",
|
|
49462
|
-
entries: [],
|
|
49463
|
-
gradient: {
|
|
49464
|
-
min: ramp.min,
|
|
49465
|
-
max: ramp.max,
|
|
49466
|
-
hue: ramp.hue,
|
|
49467
|
-
base: ramp.base
|
|
49468
|
-
}
|
|
49469
|
-
} : null;
|
|
49470
|
-
const tagGroups = layout.legend.tagGroups.filter((g) => g.entries.length > 0).map((g) => ({ name: g.name, entries: [...g.entries] }));
|
|
49471
|
-
const groups = [...scoreGroup ? [scoreGroup] : [], ...tagGroups];
|
|
49551
|
+
const groups = mapLegendGroups(layout.legend);
|
|
49472
49552
|
if (groups.length > 0) {
|
|
49473
|
-
const config =
|
|
49553
|
+
const config = mapLegendConfig(
|
|
49474
49554
|
groups,
|
|
49475
|
-
|
|
49476
|
-
|
|
49477
|
-
showEmptyGroups: false,
|
|
49478
|
-
// Keep inactive siblings visible as pills so the user can click to flip
|
|
49479
|
-
// the active colouring dimension (preview only — export shows just the
|
|
49480
|
-
// active group).
|
|
49481
|
-
showInactivePills: true
|
|
49482
|
-
};
|
|
49555
|
+
exportDims ? "export" : "preview"
|
|
49556
|
+
);
|
|
49483
49557
|
const state = { activeGroup: layout.legend.activeGroup };
|
|
49484
49558
|
renderLegendD3(legendG, config, state, palette, isDark, void 0, width);
|
|
49485
49559
|
}
|
|
@@ -49524,6 +49598,7 @@ var init_renderer16 = __esm({
|
|
|
49524
49598
|
init_title_constants();
|
|
49525
49599
|
init_color_utils();
|
|
49526
49600
|
init_legend_d3();
|
|
49601
|
+
init_legend_band();
|
|
49527
49602
|
init_layout15();
|
|
49528
49603
|
LABEL_FONT = 11;
|
|
49529
49604
|
}
|
|
@@ -49544,9 +49619,10 @@ function mapContentAspect(resolved, data, ref = REF) {
|
|
|
49544
49619
|
const aspect = w / h;
|
|
49545
49620
|
return Number.isFinite(aspect) && aspect > 0 ? aspect : FALLBACK_ASPECT;
|
|
49546
49621
|
}
|
|
49547
|
-
function mapExportDimensions(resolved, data, baseWidth = 1200) {
|
|
49548
|
-
const
|
|
49549
|
-
const
|
|
49622
|
+
function mapExportDimensions(resolved, data, baseWidth = 1200, aspectOverride) {
|
|
49623
|
+
const useOverride = aspectOverride !== void 0 && Number.isFinite(aspectOverride) && aspectOverride > 0;
|
|
49624
|
+
const raw = useOverride ? aspectOverride : mapContentAspect(resolved, data);
|
|
49625
|
+
const clamped = useOverride ? raw : Math.max(ASPECT_MIN, Math.min(ASPECT_MAX, raw));
|
|
49550
49626
|
const width = baseWidth;
|
|
49551
49627
|
let height = Math.round(width / clamped);
|
|
49552
49628
|
let chromeReserve = 0;
|
|
@@ -49559,7 +49635,7 @@ function mapExportDimensions(resolved, data, baseWidth = 1200) {
|
|
|
49559
49635
|
height = Math.round(chromeReserve + MIN_MAP_BAND);
|
|
49560
49636
|
floored = true;
|
|
49561
49637
|
}
|
|
49562
|
-
const preferContain = clamped !== raw || floored;
|
|
49638
|
+
const preferContain = useOverride ? floored : clamped !== raw || floored;
|
|
49563
49639
|
return { width, height, preferContain };
|
|
49564
49640
|
}
|
|
49565
49641
|
var import_d3_geo3, FIT_PAD2, TITLE_GAP, ASPECT_MAX, ASPECT_MIN, MIN_MAP_BAND, FALLBACK_ASPECT, REF;
|
|
@@ -55266,7 +55342,6 @@ function renderTimelineTagLegendOverlay(container, parsed, palette, isDark, setu
|
|
|
55266
55342
|
function renderTimelineHorizontalTimeSort(container, parsed, palette, isDark, setup, hovers, onClickItem, _exportDims, _swimlaneTagGroup, _activeTagGroup, _onTagStateChange, _viewMode) {
|
|
55267
55343
|
const {
|
|
55268
55344
|
width,
|
|
55269
|
-
height,
|
|
55270
55345
|
tooltip,
|
|
55271
55346
|
solid,
|
|
55272
55347
|
textColor,
|
|
@@ -55315,8 +55390,7 @@ function renderTimelineHorizontalTimeSort(container, parsed, palette, isDark, se
|
|
|
55315
55390
|
const markerLabelY = markerReserve ? -(topScaleH + MARKER_ROW_H / 2) : 0;
|
|
55316
55391
|
const eraLabelY = eraReserve ? -(topScaleH + markerReserve + ERA_ROW_H / 2) : 0;
|
|
55317
55392
|
const innerWidth = width - margin.left - margin.right;
|
|
55318
|
-
const
|
|
55319
|
-
const rowH = Math.min(ctx.structural(28), availInnerHeight / sorted.length);
|
|
55393
|
+
const rowH = ctx.structural(28);
|
|
55320
55394
|
const innerHeight = rowH * sorted.length;
|
|
55321
55395
|
const usedHeight = margin.top + innerHeight + margin.bottom;
|
|
55322
55396
|
const xScale = d3Scale2.scaleLinear().domain([minDate - datePadding, maxDate + datePadding]).range([0, innerWidth]);
|
|
@@ -57897,7 +57971,12 @@ async function renderForExport(content, theme, palette, viewState, options) {
|
|
|
57897
57971
|
}
|
|
57898
57972
|
}
|
|
57899
57973
|
const mapResolved = resolveMap2(mapParsed, mapData);
|
|
57900
|
-
const dims2 = mapExportDimensions2(
|
|
57974
|
+
const dims2 = mapExportDimensions2(
|
|
57975
|
+
mapResolved,
|
|
57976
|
+
mapData,
|
|
57977
|
+
EXPORT_WIDTH,
|
|
57978
|
+
options?.mapAspect
|
|
57979
|
+
);
|
|
57901
57980
|
const container2 = createExportContainer(dims2.width, dims2.height);
|
|
57902
57981
|
renderMapForExport2(
|
|
57903
57982
|
container2,
|
package/dist/advanced.d.cts
CHANGED
|
@@ -236,6 +236,28 @@ interface ParsedMap {
|
|
|
236
236
|
readonly diagnostics: readonly DgmoError[];
|
|
237
237
|
readonly error: string | null;
|
|
238
238
|
}
|
|
239
|
+
/** Legend descriptor for a rendered map (a layout-stage output, re-exported from
|
|
240
|
+
* `layout.ts`). It lives here so the `legend-band` helper can consume it without
|
|
241
|
+
* importing `layout` — `layout` already value-imports `mapLegendBand`, so the
|
|
242
|
+
* reverse type import would form a layout↔legend-band cycle. */
|
|
243
|
+
interface MapLayoutLegend {
|
|
244
|
+
readonly tagGroups: ReadonlyArray<{
|
|
245
|
+
name: string;
|
|
246
|
+
entries: ReadonlyArray<{
|
|
247
|
+
value: string;
|
|
248
|
+
color: string;
|
|
249
|
+
}>;
|
|
250
|
+
}>;
|
|
251
|
+
readonly activeGroup: string | null;
|
|
252
|
+
readonly ramp?: {
|
|
253
|
+
metric?: string;
|
|
254
|
+
min: number;
|
|
255
|
+
max: number;
|
|
256
|
+
hue: string;
|
|
257
|
+
/** Low end of the ramp gradient (the land colour the fills blend from). */
|
|
258
|
+
base: string;
|
|
259
|
+
};
|
|
260
|
+
}
|
|
239
261
|
|
|
240
262
|
/** A TopoJSON topology (world-coarse/world-detail keyed by ISO 3166-1 alpha-2;
|
|
241
263
|
* us-states keyed by ISO 3166-2). Geometry feature `id` is the ISO code;
|
|
@@ -1568,6 +1590,7 @@ declare function renderForExport(content: string, theme: 'light' | 'dark' | 'tra
|
|
|
1568
1590
|
tagGroup?: string;
|
|
1569
1591
|
exportMode?: boolean;
|
|
1570
1592
|
mapData?: MapData;
|
|
1593
|
+
mapAspect?: number;
|
|
1571
1594
|
}): Promise<string>;
|
|
1572
1595
|
|
|
1573
1596
|
/**
|
|
@@ -4839,24 +4862,7 @@ interface PlacedLabel {
|
|
|
4839
4862
|
readonly clusterMember?: string;
|
|
4840
4863
|
readonly lineNumber: number;
|
|
4841
4864
|
}
|
|
4842
|
-
|
|
4843
|
-
readonly tagGroups: ReadonlyArray<{
|
|
4844
|
-
name: string;
|
|
4845
|
-
entries: ReadonlyArray<{
|
|
4846
|
-
value: string;
|
|
4847
|
-
color: string;
|
|
4848
|
-
}>;
|
|
4849
|
-
}>;
|
|
4850
|
-
readonly activeGroup: string | null;
|
|
4851
|
-
readonly ramp?: {
|
|
4852
|
-
metric?: string;
|
|
4853
|
-
min: number;
|
|
4854
|
-
max: number;
|
|
4855
|
-
hue: string;
|
|
4856
|
-
/** Low end of the ramp gradient (the land colour the fills blend from). */
|
|
4857
|
-
base: string;
|
|
4858
|
-
};
|
|
4859
|
-
}
|
|
4865
|
+
|
|
4860
4866
|
/** A drawn river centerline — an open stroked path (no fill). */
|
|
4861
4867
|
interface MapLayoutRiver {
|
|
4862
4868
|
readonly d: string;
|
|
@@ -4955,6 +4961,10 @@ interface LayoutOptions {
|
|
|
4955
4961
|
* canvas away from the content aspect, so the off-aspect canvas doesn't
|
|
4956
4962
|
* re-distort. The in-app preview pane leaves this unset (keeps stretch-fill). */
|
|
4957
4963
|
readonly preferContain?: boolean;
|
|
4964
|
+
/** Which legend variant gets drawn — `'export'` shows only the active group,
|
|
4965
|
+
* `'preview'` keeps inactive pills. Used to size the reserved legend band so
|
|
4966
|
+
* the projected land starts below the legend. Defaults to `'preview'`. */
|
|
4967
|
+
readonly legendMode?: LegendMode;
|
|
4958
4968
|
}
|
|
4959
4969
|
interface Size {
|
|
4960
4970
|
readonly width: number;
|
|
@@ -5007,7 +5017,13 @@ interface MapExportDimensions {
|
|
|
5007
5017
|
readonly height: number;
|
|
5008
5018
|
readonly preferContain: boolean;
|
|
5009
5019
|
}
|
|
5010
|
-
declare function mapExportDimensions(resolved: ResolvedMap, data: MapData, baseWidth?: number
|
|
5020
|
+
declare function mapExportDimensions(resolved: ResolvedMap, data: MapData, baseWidth?: number,
|
|
5021
|
+
/** WYSIWYG override (app export): the live preview pane's displayed aspect
|
|
5022
|
+
* (width / height). When provided, the canvas adopts it verbatim and
|
|
5023
|
+
* stretch-fills (no clamp, no contain) so the PNG matches exactly what's on
|
|
5024
|
+
* screen. Omitted by every headless consumer (CLI / MCP / SSG / Obsidian),
|
|
5025
|
+
* which keep the intrinsic-aspect sizing below. */
|
|
5026
|
+
aspectOverride?: number): MapExportDimensions;
|
|
5011
5027
|
|
|
5012
5028
|
/** Nearest gazetteer city to a point: the real haversine distance, plus the
|
|
5013
5029
|
* canonical name + ISO + (US-only) subdivision for token shaping. `lon`/`lat`
|
package/dist/advanced.d.ts
CHANGED
|
@@ -236,6 +236,28 @@ interface ParsedMap {
|
|
|
236
236
|
readonly diagnostics: readonly DgmoError[];
|
|
237
237
|
readonly error: string | null;
|
|
238
238
|
}
|
|
239
|
+
/** Legend descriptor for a rendered map (a layout-stage output, re-exported from
|
|
240
|
+
* `layout.ts`). It lives here so the `legend-band` helper can consume it without
|
|
241
|
+
* importing `layout` — `layout` already value-imports `mapLegendBand`, so the
|
|
242
|
+
* reverse type import would form a layout↔legend-band cycle. */
|
|
243
|
+
interface MapLayoutLegend {
|
|
244
|
+
readonly tagGroups: ReadonlyArray<{
|
|
245
|
+
name: string;
|
|
246
|
+
entries: ReadonlyArray<{
|
|
247
|
+
value: string;
|
|
248
|
+
color: string;
|
|
249
|
+
}>;
|
|
250
|
+
}>;
|
|
251
|
+
readonly activeGroup: string | null;
|
|
252
|
+
readonly ramp?: {
|
|
253
|
+
metric?: string;
|
|
254
|
+
min: number;
|
|
255
|
+
max: number;
|
|
256
|
+
hue: string;
|
|
257
|
+
/** Low end of the ramp gradient (the land colour the fills blend from). */
|
|
258
|
+
base: string;
|
|
259
|
+
};
|
|
260
|
+
}
|
|
239
261
|
|
|
240
262
|
/** A TopoJSON topology (world-coarse/world-detail keyed by ISO 3166-1 alpha-2;
|
|
241
263
|
* us-states keyed by ISO 3166-2). Geometry feature `id` is the ISO code;
|
|
@@ -1568,6 +1590,7 @@ declare function renderForExport(content: string, theme: 'light' | 'dark' | 'tra
|
|
|
1568
1590
|
tagGroup?: string;
|
|
1569
1591
|
exportMode?: boolean;
|
|
1570
1592
|
mapData?: MapData;
|
|
1593
|
+
mapAspect?: number;
|
|
1571
1594
|
}): Promise<string>;
|
|
1572
1595
|
|
|
1573
1596
|
/**
|
|
@@ -4839,24 +4862,7 @@ interface PlacedLabel {
|
|
|
4839
4862
|
readonly clusterMember?: string;
|
|
4840
4863
|
readonly lineNumber: number;
|
|
4841
4864
|
}
|
|
4842
|
-
|
|
4843
|
-
readonly tagGroups: ReadonlyArray<{
|
|
4844
|
-
name: string;
|
|
4845
|
-
entries: ReadonlyArray<{
|
|
4846
|
-
value: string;
|
|
4847
|
-
color: string;
|
|
4848
|
-
}>;
|
|
4849
|
-
}>;
|
|
4850
|
-
readonly activeGroup: string | null;
|
|
4851
|
-
readonly ramp?: {
|
|
4852
|
-
metric?: string;
|
|
4853
|
-
min: number;
|
|
4854
|
-
max: number;
|
|
4855
|
-
hue: string;
|
|
4856
|
-
/** Low end of the ramp gradient (the land colour the fills blend from). */
|
|
4857
|
-
base: string;
|
|
4858
|
-
};
|
|
4859
|
-
}
|
|
4865
|
+
|
|
4860
4866
|
/** A drawn river centerline — an open stroked path (no fill). */
|
|
4861
4867
|
interface MapLayoutRiver {
|
|
4862
4868
|
readonly d: string;
|
|
@@ -4955,6 +4961,10 @@ interface LayoutOptions {
|
|
|
4955
4961
|
* canvas away from the content aspect, so the off-aspect canvas doesn't
|
|
4956
4962
|
* re-distort. The in-app preview pane leaves this unset (keeps stretch-fill). */
|
|
4957
4963
|
readonly preferContain?: boolean;
|
|
4964
|
+
/** Which legend variant gets drawn — `'export'` shows only the active group,
|
|
4965
|
+
* `'preview'` keeps inactive pills. Used to size the reserved legend band so
|
|
4966
|
+
* the projected land starts below the legend. Defaults to `'preview'`. */
|
|
4967
|
+
readonly legendMode?: LegendMode;
|
|
4958
4968
|
}
|
|
4959
4969
|
interface Size {
|
|
4960
4970
|
readonly width: number;
|
|
@@ -5007,7 +5017,13 @@ interface MapExportDimensions {
|
|
|
5007
5017
|
readonly height: number;
|
|
5008
5018
|
readonly preferContain: boolean;
|
|
5009
5019
|
}
|
|
5010
|
-
declare function mapExportDimensions(resolved: ResolvedMap, data: MapData, baseWidth?: number
|
|
5020
|
+
declare function mapExportDimensions(resolved: ResolvedMap, data: MapData, baseWidth?: number,
|
|
5021
|
+
/** WYSIWYG override (app export): the live preview pane's displayed aspect
|
|
5022
|
+
* (width / height). When provided, the canvas adopts it verbatim and
|
|
5023
|
+
* stretch-fills (no clamp, no contain) so the PNG matches exactly what's on
|
|
5024
|
+
* screen. Omitted by every headless consumer (CLI / MCP / SSG / Obsidian),
|
|
5025
|
+
* which keep the intrinsic-aspect sizing below. */
|
|
5026
|
+
aspectOverride?: number): MapExportDimensions;
|
|
5011
5027
|
|
|
5012
5028
|
/** Nearest gazetteer city to a point: the real haversine distance, plus the
|
|
5013
5029
|
* canonical name + ISO + (US-only) subdivision for token shaping. `lon`/`lat`
|