@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/index.cjs
CHANGED
|
@@ -26567,7 +26567,7 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26567
26567
|
const VALUE_NAME = hasRamp ? parsed.boxMetric?.trim() || "Value" : null;
|
|
26568
26568
|
const matchColorGroup = (v) => {
|
|
26569
26569
|
const lv = v.trim().toLowerCase();
|
|
26570
|
-
if (lv === "none") return null;
|
|
26570
|
+
if (lv === "" || lv === "none") return null;
|
|
26571
26571
|
const tg = parsed.tagGroups.find((g) => g.name.toLowerCase() === lv);
|
|
26572
26572
|
if (tg) return tg.name;
|
|
26573
26573
|
if (lv === VALUE_NAME?.toLowerCase()) return VALUE_NAME;
|
|
@@ -26908,6 +26908,22 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26908
26908
|
const tooltipText = fullText.length > 200 ? fullText.slice(0, 199) + "\u2026" : fullText;
|
|
26909
26909
|
nodeG.append("title").text(tooltipText);
|
|
26910
26910
|
}
|
|
26911
|
+
} else if (parsed.showValues && node.value !== void 0) {
|
|
26912
|
+
const valueLabel = parsed.boxMetric ? `${parsed.boxMetric}: ${node.value}` : String(node.value);
|
|
26913
|
+
const headerH = ln.height / 2;
|
|
26914
|
+
const sepY = -ln.height / 2 + headerH;
|
|
26915
|
+
const fitted = fitLabelToHeader(node.label, ln.width, 2);
|
|
26916
|
+
const labelLineH = fitted.fontSize * 1.3;
|
|
26917
|
+
const labelTotalH = fitted.lines.length * labelLineH;
|
|
26918
|
+
const headerCenterY = -ln.height / 2 + headerH / 2;
|
|
26919
|
+
for (let li = 0; li < fitted.lines.length; li++) {
|
|
26920
|
+
nodeG.append("text").attr("x", 0).attr(
|
|
26921
|
+
"y",
|
|
26922
|
+
headerCenterY - labelTotalH / 2 + labelLineH / 2 + li * labelLineH
|
|
26923
|
+
).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]);
|
|
26924
|
+
}
|
|
26925
|
+
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);
|
|
26926
|
+
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);
|
|
26911
26927
|
} else {
|
|
26912
26928
|
const maxLabelLines = Math.max(
|
|
26913
26929
|
2,
|
|
@@ -26920,21 +26936,16 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26920
26936
|
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]);
|
|
26921
26937
|
}
|
|
26922
26938
|
}
|
|
26923
|
-
if (parsed.showValues && node.value !== void 0) {
|
|
26939
|
+
if (parsed.showValues && node.value !== void 0 && desc && desc.length > 0 && !hideDescriptions) {
|
|
26924
26940
|
const valueText = String(node.value);
|
|
26925
|
-
const
|
|
26926
|
-
|
|
26927
|
-
|
|
26928
|
-
|
|
26929
|
-
|
|
26930
|
-
|
|
26931
|
-
|
|
26932
|
-
|
|
26933
|
-
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);
|
|
26934
|
-
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);
|
|
26935
|
-
} else {
|
|
26936
|
-
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);
|
|
26937
|
-
}
|
|
26941
|
+
const padX = 6;
|
|
26942
|
+
const padY = 5;
|
|
26943
|
+
const bw = valueText.length * VALUE_FONT_SIZE * CHAR_WIDTH_RATIO2 + 8;
|
|
26944
|
+
const bh = VALUE_FONT_SIZE + 4;
|
|
26945
|
+
const bx = Math.max(-ln.width / 2 + 4, ln.width / 2 - bw - 4);
|
|
26946
|
+
const by = -ln.height / 2 + 4;
|
|
26947
|
+
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);
|
|
26948
|
+
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);
|
|
26938
26949
|
}
|
|
26939
26950
|
}
|
|
26940
26951
|
const hasDescriptions = parsed.nodes.some(
|
|
@@ -27030,7 +27041,7 @@ var init_renderer6 = __esm({
|
|
|
27030
27041
|
init_wrapped_desc();
|
|
27031
27042
|
init_scaling();
|
|
27032
27043
|
DIAGRAM_PADDING6 = 20;
|
|
27033
|
-
NODE_FONT_SIZE =
|
|
27044
|
+
NODE_FONT_SIZE = 11;
|
|
27034
27045
|
MIN_NODE_FONT_SIZE = 9;
|
|
27035
27046
|
EDGE_LABEL_FONT_SIZE4 = 11;
|
|
27036
27047
|
EDGE_STROKE_WIDTH5 = 1.5;
|
|
@@ -46767,7 +46778,11 @@ function resolveMap(parsed, data) {
|
|
|
46767
46778
|
if (bb && !isWholeSphere(bb)) containerBoxes.push(bb);
|
|
46768
46779
|
}
|
|
46769
46780
|
const containerUnion = unionExtent(containerBoxes, points);
|
|
46770
|
-
if (containerUnion)
|
|
46781
|
+
if (containerUnion)
|
|
46782
|
+
extent2 = pad(
|
|
46783
|
+
clampContainerToCluster(containerUnion, points),
|
|
46784
|
+
PAD_FRACTION
|
|
46785
|
+
);
|
|
46771
46786
|
}
|
|
46772
46787
|
if (isPoiOnly) {
|
|
46773
46788
|
const cx = (extent2[0][0] + extent2[1][0]) / 2;
|
|
@@ -46848,6 +46863,22 @@ function mostCommonCountry(regions, poiCountries) {
|
|
|
46848
46863
|
}
|
|
46849
46864
|
return best;
|
|
46850
46865
|
}
|
|
46866
|
+
function clampContainerToCluster(container, points) {
|
|
46867
|
+
const poi = unionExtent([], points);
|
|
46868
|
+
if (!poi) return container;
|
|
46869
|
+
let [[west, south], [east, north]] = container;
|
|
46870
|
+
const [[pWest, pSouth], [pEast, pNorth]] = poi;
|
|
46871
|
+
south = Math.max(south, pSouth - CONTAINER_OVERSHOOT_DEG);
|
|
46872
|
+
north = Math.min(north, pNorth + CONTAINER_OVERSHOOT_DEG);
|
|
46873
|
+
if (east <= 180 && pEast <= 180) {
|
|
46874
|
+
west = Math.max(west, pWest - CONTAINER_OVERSHOOT_DEG);
|
|
46875
|
+
east = Math.min(east, pEast + CONTAINER_OVERSHOOT_DEG);
|
|
46876
|
+
}
|
|
46877
|
+
return [
|
|
46878
|
+
[west, south],
|
|
46879
|
+
[east, north]
|
|
46880
|
+
];
|
|
46881
|
+
}
|
|
46851
46882
|
function pad(e, frac) {
|
|
46852
46883
|
const dLon = (e[1][0] - e[0][0]) * frac || 1;
|
|
46853
46884
|
const dLat = (e[1][1] - e[0][1]) * frac || 1;
|
|
@@ -46860,7 +46891,7 @@ function firstError(diags) {
|
|
|
46860
46891
|
const e = diags.find((d) => d.severity === "error");
|
|
46861
46892
|
return e ? formatDgmoError(e) : null;
|
|
46862
46893
|
}
|
|
46863
|
-
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;
|
|
46894
|
+
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;
|
|
46864
46895
|
var init_resolver2 = __esm({
|
|
46865
46896
|
"src/map/resolver.ts"() {
|
|
46866
46897
|
"use strict";
|
|
@@ -46873,6 +46904,7 @@ var init_resolver2 = __esm({
|
|
|
46873
46904
|
WORLD_LAT_SOUTH = -58;
|
|
46874
46905
|
WORLD_LAT_NORTH = 78;
|
|
46875
46906
|
POI_ZOOM_FLOOR_DEG = 7;
|
|
46907
|
+
CONTAINER_OVERSHOOT_DEG = 8;
|
|
46876
46908
|
US_NATIONAL_LON_SPAN = 48;
|
|
46877
46909
|
REGION_ALIASES = {
|
|
46878
46910
|
// Common everyday names → the Natural-Earth display name actually shipped.
|
|
@@ -46951,6 +46983,55 @@ var init_resolver2 = __esm({
|
|
|
46951
46983
|
}
|
|
46952
46984
|
});
|
|
46953
46985
|
|
|
46986
|
+
// src/map/legend-band.ts
|
|
46987
|
+
function mapLegendGroups(legend) {
|
|
46988
|
+
const ramp = legend.ramp;
|
|
46989
|
+
const scoreGroup = ramp ? {
|
|
46990
|
+
name: ramp.metric?.trim() || "Value",
|
|
46991
|
+
entries: [],
|
|
46992
|
+
gradient: {
|
|
46993
|
+
min: ramp.min,
|
|
46994
|
+
max: ramp.max,
|
|
46995
|
+
hue: ramp.hue,
|
|
46996
|
+
base: ramp.base
|
|
46997
|
+
}
|
|
46998
|
+
} : null;
|
|
46999
|
+
const tagGroups = legend.tagGroups.filter((g) => g.entries.length > 0).map((g) => ({ name: g.name, entries: [...g.entries] }));
|
|
47000
|
+
return [...scoreGroup ? [scoreGroup] : [], ...tagGroups];
|
|
47001
|
+
}
|
|
47002
|
+
function mapLegendConfig(groups, mode) {
|
|
47003
|
+
return {
|
|
47004
|
+
groups,
|
|
47005
|
+
position: { placement: "top-center", titleRelation: "below-title" },
|
|
47006
|
+
mode,
|
|
47007
|
+
showEmptyGroups: false,
|
|
47008
|
+
showInactivePills: true
|
|
47009
|
+
};
|
|
47010
|
+
}
|
|
47011
|
+
function mapLegendTop(hasTitle, hasSubtitle) {
|
|
47012
|
+
return (hasTitle ? TITLE_Y + TITLE_FONT_SIZE : 0) + (hasSubtitle ? TITLE_FONT_SIZE : 0) + LEGEND_TOP_GAP2;
|
|
47013
|
+
}
|
|
47014
|
+
function mapLegendBand(legend, opts) {
|
|
47015
|
+
if (!legend) return 0;
|
|
47016
|
+
const groups = mapLegendGroups(legend);
|
|
47017
|
+
if (groups.length === 0) return 0;
|
|
47018
|
+
const config = mapLegendConfig(groups, opts.mode);
|
|
47019
|
+
const state = { activeGroup: legend.activeGroup };
|
|
47020
|
+
const { height } = computeLegendLayout(config, state, opts.width);
|
|
47021
|
+
if (height <= 0) return 0;
|
|
47022
|
+
return mapLegendTop(opts.hasTitle, opts.hasSubtitle) + height + LEGEND_BOTTOM_GAP2;
|
|
47023
|
+
}
|
|
47024
|
+
var LEGEND_TOP_GAP2, LEGEND_BOTTOM_GAP2;
|
|
47025
|
+
var init_legend_band = __esm({
|
|
47026
|
+
"src/map/legend-band.ts"() {
|
|
47027
|
+
"use strict";
|
|
47028
|
+
init_legend_layout();
|
|
47029
|
+
init_title_constants();
|
|
47030
|
+
LEGEND_TOP_GAP2 = 8;
|
|
47031
|
+
LEGEND_BOTTOM_GAP2 = 10;
|
|
47032
|
+
}
|
|
47033
|
+
});
|
|
47034
|
+
|
|
46954
47035
|
// src/map/colorize.ts
|
|
46955
47036
|
function assignColors(isos, adjacency) {
|
|
46956
47037
|
const sorted = [...isos].sort();
|
|
@@ -47531,12 +47612,43 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47531
47612
|
return tagFill(r.tags, activeGroup) ?? neutralFill;
|
|
47532
47613
|
};
|
|
47533
47614
|
const regionById = new Map(resolved.regions.map((r) => [r.iso, r]));
|
|
47615
|
+
let legend = null;
|
|
47616
|
+
if (!resolved.directives.noLegend) {
|
|
47617
|
+
const legendTagGroups = resolved.tagGroups.map((g) => ({
|
|
47618
|
+
name: g.name,
|
|
47619
|
+
entries: g.entries.map((e) => ({ value: e.value, color: e.color }))
|
|
47620
|
+
}));
|
|
47621
|
+
if (legendTagGroups.length > 0 || hasRamp) {
|
|
47622
|
+
legend = {
|
|
47623
|
+
tagGroups: legendTagGroups,
|
|
47624
|
+
activeGroup,
|
|
47625
|
+
...hasRamp && {
|
|
47626
|
+
ramp: {
|
|
47627
|
+
...resolved.directives.regionMetric !== void 0 && {
|
|
47628
|
+
metric: resolved.directives.regionMetric
|
|
47629
|
+
},
|
|
47630
|
+
min: rampMin,
|
|
47631
|
+
max: rampMax,
|
|
47632
|
+
hue: rampHue,
|
|
47633
|
+
base: rampBase
|
|
47634
|
+
}
|
|
47635
|
+
}
|
|
47636
|
+
};
|
|
47637
|
+
}
|
|
47638
|
+
}
|
|
47534
47639
|
const TITLE_GAP2 = 16;
|
|
47535
47640
|
let topPad = FIT_PAD;
|
|
47536
47641
|
if (resolved.title && resolved.pois.length > 0) {
|
|
47537
47642
|
const bannerBottom = (resolved.subtitle ? TITLE_Y + TITLE_FONT_SIZE : TITLE_Y) + TITLE_FONT_SIZE / 2;
|
|
47538
47643
|
topPad = Math.max(FIT_PAD, bannerBottom + TITLE_GAP2);
|
|
47539
47644
|
}
|
|
47645
|
+
const legendBand = mapLegendBand(legend, {
|
|
47646
|
+
width,
|
|
47647
|
+
mode: opts.legendMode ?? "preview",
|
|
47648
|
+
hasTitle: Boolean(resolved.title),
|
|
47649
|
+
hasSubtitle: Boolean(resolved.subtitle)
|
|
47650
|
+
});
|
|
47651
|
+
if (legendBand > topPad) topPad = legendBand;
|
|
47540
47652
|
const fitBox = [
|
|
47541
47653
|
[FIT_PAD, topPad],
|
|
47542
47654
|
[
|
|
@@ -47554,7 +47666,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47554
47666
|
const by0 = cb[0][1];
|
|
47555
47667
|
const cw = cb[1][0] - bx0;
|
|
47556
47668
|
const ch = cb[1][1] - by0;
|
|
47557
|
-
const topReserve = resolved.title && resolved.pois.length > 0 ? topPad : 0;
|
|
47669
|
+
const topReserve = resolved.title && resolved.pois.length > 0 || legendBand > 0 ? topPad : 0;
|
|
47558
47670
|
const ox = 0;
|
|
47559
47671
|
const oy = topReserve;
|
|
47560
47672
|
const sx = cw > 0 ? width / cw : 1;
|
|
@@ -48618,30 +48730,6 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
48618
48730
|
});
|
|
48619
48731
|
labels.push(...contextLabels);
|
|
48620
48732
|
}
|
|
48621
|
-
let legend = null;
|
|
48622
|
-
if (!resolved.directives.noLegend) {
|
|
48623
|
-
const tagGroups = resolved.tagGroups.map((g) => ({
|
|
48624
|
-
name: g.name,
|
|
48625
|
-
entries: g.entries.map((e) => ({ value: e.value, color: e.color }))
|
|
48626
|
-
}));
|
|
48627
|
-
if (tagGroups.length > 0 || hasRamp) {
|
|
48628
|
-
legend = {
|
|
48629
|
-
tagGroups,
|
|
48630
|
-
activeGroup,
|
|
48631
|
-
...hasRamp && {
|
|
48632
|
-
ramp: {
|
|
48633
|
-
...resolved.directives.regionMetric !== void 0 && {
|
|
48634
|
-
metric: resolved.directives.regionMetric
|
|
48635
|
-
},
|
|
48636
|
-
min: rampMin,
|
|
48637
|
-
max: rampMax,
|
|
48638
|
-
hue: rampHue,
|
|
48639
|
-
base: rampBase
|
|
48640
|
-
}
|
|
48641
|
-
}
|
|
48642
|
-
};
|
|
48643
|
-
}
|
|
48644
|
-
}
|
|
48645
48733
|
return {
|
|
48646
48734
|
width,
|
|
48647
48735
|
height,
|
|
@@ -48679,6 +48767,7 @@ var init_layout15 = __esm({
|
|
|
48679
48767
|
init_label_layout();
|
|
48680
48768
|
init_legend_constants();
|
|
48681
48769
|
init_title_constants();
|
|
48770
|
+
init_legend_band();
|
|
48682
48771
|
init_context_labels();
|
|
48683
48772
|
FIT_PAD = 24;
|
|
48684
48773
|
RAMP_FLOOR2 = 15;
|
|
@@ -48878,6 +48967,9 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
48878
48967
|
// stretch-distorting. The in-app preview pane passes no exportDims → unset →
|
|
48879
48968
|
// keeps the global stretch-fill.
|
|
48880
48969
|
preferContain: exportDims?.preferContain ?? false,
|
|
48970
|
+
// Reserve the legend band for the mode actually drawn below (export shows
|
|
48971
|
+
// only the active group; preview keeps the inactive pills).
|
|
48972
|
+
legendMode: exportDims ? "export" : "preview",
|
|
48881
48973
|
...activeGroupOverride !== void 0 && {
|
|
48882
48974
|
activeGroup: activeGroupOverride
|
|
48883
48975
|
}
|
|
@@ -49169,30 +49261,12 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
49169
49261
|
if (layout.legend) {
|
|
49170
49262
|
const legendY = (layout.title ? TITLE_Y + TITLE_FONT_SIZE : 0) + (layout.subtitle ? TITLE_FONT_SIZE : 0) + 8;
|
|
49171
49263
|
const legendG = svg.append("g").attr("class", "dgmo-map-legend").attr("transform", `translate(0, ${legendY})`);
|
|
49172
|
-
const
|
|
49173
|
-
const scoreGroup = ramp ? {
|
|
49174
|
-
name: ramp.metric?.trim() || "Value",
|
|
49175
|
-
entries: [],
|
|
49176
|
-
gradient: {
|
|
49177
|
-
min: ramp.min,
|
|
49178
|
-
max: ramp.max,
|
|
49179
|
-
hue: ramp.hue,
|
|
49180
|
-
base: ramp.base
|
|
49181
|
-
}
|
|
49182
|
-
} : null;
|
|
49183
|
-
const tagGroups = layout.legend.tagGroups.filter((g) => g.entries.length > 0).map((g) => ({ name: g.name, entries: [...g.entries] }));
|
|
49184
|
-
const groups = [...scoreGroup ? [scoreGroup] : [], ...tagGroups];
|
|
49264
|
+
const groups = mapLegendGroups(layout.legend);
|
|
49185
49265
|
if (groups.length > 0) {
|
|
49186
|
-
const config =
|
|
49266
|
+
const config = mapLegendConfig(
|
|
49187
49267
|
groups,
|
|
49188
|
-
|
|
49189
|
-
|
|
49190
|
-
showEmptyGroups: false,
|
|
49191
|
-
// Keep inactive siblings visible as pills so the user can click to flip
|
|
49192
|
-
// the active colouring dimension (preview only — export shows just the
|
|
49193
|
-
// active group).
|
|
49194
|
-
showInactivePills: true
|
|
49195
|
-
};
|
|
49268
|
+
exportDims ? "export" : "preview"
|
|
49269
|
+
);
|
|
49196
49270
|
const state = { activeGroup: layout.legend.activeGroup };
|
|
49197
49271
|
renderLegendD3(legendG, config, state, palette, isDark, void 0, width);
|
|
49198
49272
|
}
|
|
@@ -49237,6 +49311,7 @@ var init_renderer16 = __esm({
|
|
|
49237
49311
|
init_title_constants();
|
|
49238
49312
|
init_color_utils();
|
|
49239
49313
|
init_legend_d3();
|
|
49314
|
+
init_legend_band();
|
|
49240
49315
|
init_layout15();
|
|
49241
49316
|
LABEL_FONT = 11;
|
|
49242
49317
|
}
|
|
@@ -49257,9 +49332,10 @@ function mapContentAspect(resolved, data, ref = REF) {
|
|
|
49257
49332
|
const aspect = w / h;
|
|
49258
49333
|
return Number.isFinite(aspect) && aspect > 0 ? aspect : FALLBACK_ASPECT;
|
|
49259
49334
|
}
|
|
49260
|
-
function mapExportDimensions(resolved, data, baseWidth = 1200) {
|
|
49261
|
-
const
|
|
49262
|
-
const
|
|
49335
|
+
function mapExportDimensions(resolved, data, baseWidth = 1200, aspectOverride) {
|
|
49336
|
+
const useOverride = aspectOverride !== void 0 && Number.isFinite(aspectOverride) && aspectOverride > 0;
|
|
49337
|
+
const raw = useOverride ? aspectOverride : mapContentAspect(resolved, data);
|
|
49338
|
+
const clamped = useOverride ? raw : Math.max(ASPECT_MIN, Math.min(ASPECT_MAX, raw));
|
|
49263
49339
|
const width = baseWidth;
|
|
49264
49340
|
let height = Math.round(width / clamped);
|
|
49265
49341
|
let chromeReserve = 0;
|
|
@@ -49272,7 +49348,7 @@ function mapExportDimensions(resolved, data, baseWidth = 1200) {
|
|
|
49272
49348
|
height = Math.round(chromeReserve + MIN_MAP_BAND);
|
|
49273
49349
|
floored = true;
|
|
49274
49350
|
}
|
|
49275
|
-
const preferContain = clamped !== raw || floored;
|
|
49351
|
+
const preferContain = useOverride ? floored : clamped !== raw || floored;
|
|
49276
49352
|
return { width, height, preferContain };
|
|
49277
49353
|
}
|
|
49278
49354
|
var import_d3_geo3, FIT_PAD2, TITLE_GAP, ASPECT_MAX, ASPECT_MIN, MIN_MAP_BAND, FALLBACK_ASPECT, REF;
|
|
@@ -54979,7 +55055,6 @@ function renderTimelineTagLegendOverlay(container, parsed, palette, isDark, setu
|
|
|
54979
55055
|
function renderTimelineHorizontalTimeSort(container, parsed, palette, isDark, setup, hovers, onClickItem, _exportDims, _swimlaneTagGroup, _activeTagGroup, _onTagStateChange, _viewMode) {
|
|
54980
55056
|
const {
|
|
54981
55057
|
width,
|
|
54982
|
-
height,
|
|
54983
55058
|
tooltip,
|
|
54984
55059
|
solid,
|
|
54985
55060
|
textColor,
|
|
@@ -55028,8 +55103,7 @@ function renderTimelineHorizontalTimeSort(container, parsed, palette, isDark, se
|
|
|
55028
55103
|
const markerLabelY = markerReserve ? -(topScaleH + MARKER_ROW_H / 2) : 0;
|
|
55029
55104
|
const eraLabelY = eraReserve ? -(topScaleH + markerReserve + ERA_ROW_H / 2) : 0;
|
|
55030
55105
|
const innerWidth = width - margin.left - margin.right;
|
|
55031
|
-
const
|
|
55032
|
-
const rowH = Math.min(ctx.structural(28), availInnerHeight / sorted.length);
|
|
55106
|
+
const rowH = ctx.structural(28);
|
|
55033
55107
|
const innerHeight = rowH * sorted.length;
|
|
55034
55108
|
const usedHeight = margin.top + innerHeight + margin.bottom;
|
|
55035
55109
|
const xScale = d3Scale2.scaleLinear().domain([minDate - datePadding, maxDate + datePadding]).range([0, innerWidth]);
|
|
@@ -57554,7 +57628,12 @@ async function renderForExport(content, theme, palette, viewState, options) {
|
|
|
57554
57628
|
}
|
|
57555
57629
|
}
|
|
57556
57630
|
const mapResolved = resolveMap2(mapParsed, mapData);
|
|
57557
|
-
const dims2 = mapExportDimensions2(
|
|
57631
|
+
const dims2 = mapExportDimensions2(
|
|
57632
|
+
mapResolved,
|
|
57633
|
+
mapData,
|
|
57634
|
+
EXPORT_WIDTH,
|
|
57635
|
+
options?.mapAspect
|
|
57636
|
+
);
|
|
57558
57637
|
const container2 = createExportContainer(dims2.width, dims2.height);
|
|
57559
57638
|
renderMapForExport2(
|
|
57560
57639
|
container2,
|
|
@@ -58347,8 +58426,10 @@ __export(index_exports, {
|
|
|
58347
58426
|
decodeDiagramUrl: () => decodeDiagramUrl2,
|
|
58348
58427
|
encodeDiagramUrl: () => encodeDiagramUrl2,
|
|
58349
58428
|
formatDgmoError: () => formatDgmoError,
|
|
58429
|
+
getEmbedSvgViewBox: () => getEmbedSvgViewBox,
|
|
58350
58430
|
getMinDimensions: () => getMinDimensions,
|
|
58351
58431
|
getPalette: () => getPalette,
|
|
58432
|
+
normalizeSvgForEmbed: () => normalizeSvgForEmbed,
|
|
58352
58433
|
palettes: () => palettes,
|
|
58353
58434
|
render: () => render2,
|
|
58354
58435
|
themes: () => themes,
|
|
@@ -58720,6 +58801,134 @@ function extractInfraCounts(content) {
|
|
|
58720
58801
|
return { nodes: parsed.nodes.length };
|
|
58721
58802
|
}
|
|
58722
58803
|
|
|
58804
|
+
// src/utils/svg-embed.ts
|
|
58805
|
+
function normalizeSvgForEmbed(input) {
|
|
58806
|
+
let svg = input;
|
|
58807
|
+
const rootMatch = svg.match(/<svg[^>]*>/);
|
|
58808
|
+
const rootTag = rootMatch?.[0] ?? "";
|
|
58809
|
+
if (rootTag && !rootTag.includes("viewBox")) {
|
|
58810
|
+
const wh = rootTag.match(/width="(\d+)"[^>]*height="(\d+)"/);
|
|
58811
|
+
if (wh) {
|
|
58812
|
+
svg = svg.replace(/<svg/, `<svg viewBox="0 0 ${wh[1]} ${wh[2]}"`);
|
|
58813
|
+
}
|
|
58814
|
+
}
|
|
58815
|
+
const tight = computeBBox(svg);
|
|
58816
|
+
if (tight && tight.width > 0 && tight.height > 0) {
|
|
58817
|
+
const pad2 = 16;
|
|
58818
|
+
const vb = `${tight.x - pad2} ${tight.y - pad2} ${tight.width + pad2 * 2} ${tight.height + pad2 * 2}`;
|
|
58819
|
+
svg = svg.replace(/(<svg[^>]*?)viewBox="[^"]*"/, `$1viewBox="${vb}"`);
|
|
58820
|
+
}
|
|
58821
|
+
svg = svg.replace(/(<svg[^>]*?) width="[^"]*"/g, "$1");
|
|
58822
|
+
svg = svg.replace(/(<svg[^>]*?) height="[^"]*"/g, "$1");
|
|
58823
|
+
svg = svg.replace(/(<svg[^>]*?style="[^"]*?)background:[^;"]*;?\s*/g, "$1");
|
|
58824
|
+
svg = svg.replace(/<svg\s{2,}/g, "<svg ");
|
|
58825
|
+
return svg;
|
|
58826
|
+
}
|
|
58827
|
+
function getEmbedSvgViewBox(svg) {
|
|
58828
|
+
const tight = computeBBox(svg);
|
|
58829
|
+
if (!tight || tight.width <= 0 || tight.height <= 0) return null;
|
|
58830
|
+
const pad2 = 16;
|
|
58831
|
+
return {
|
|
58832
|
+
x: tight.x - pad2,
|
|
58833
|
+
y: tight.y - pad2,
|
|
58834
|
+
width: tight.width + pad2 * 2,
|
|
58835
|
+
height: tight.height + pad2 * 2
|
|
58836
|
+
};
|
|
58837
|
+
}
|
|
58838
|
+
function computeBBox(svg) {
|
|
58839
|
+
const xs = [];
|
|
58840
|
+
const ys = [];
|
|
58841
|
+
function push(x, y) {
|
|
58842
|
+
if (Number.isFinite(x) && Number.isFinite(y)) {
|
|
58843
|
+
xs.push(x);
|
|
58844
|
+
ys.push(y);
|
|
58845
|
+
}
|
|
58846
|
+
}
|
|
58847
|
+
function attr(tag, name) {
|
|
58848
|
+
const m = tag.match(new RegExp(`\\b${name}="([^"]*)"`));
|
|
58849
|
+
if (!m) return null;
|
|
58850
|
+
const n = parseFloat(m[1]);
|
|
58851
|
+
return Number.isFinite(n) ? n : null;
|
|
58852
|
+
}
|
|
58853
|
+
for (const m of svg.matchAll(/<rect\b[^>]*?\/?>/g)) {
|
|
58854
|
+
const tag = m[0];
|
|
58855
|
+
const x = attr(tag, "x");
|
|
58856
|
+
const y = attr(tag, "y");
|
|
58857
|
+
const w = attr(tag, "width");
|
|
58858
|
+
const h = attr(tag, "height");
|
|
58859
|
+
if (x !== null && y !== null && w !== null && h !== null) {
|
|
58860
|
+
push(x, y);
|
|
58861
|
+
push(x + w, y + h);
|
|
58862
|
+
}
|
|
58863
|
+
}
|
|
58864
|
+
for (const m of svg.matchAll(/<line\b[^>]*?\/?>/g)) {
|
|
58865
|
+
const tag = m[0];
|
|
58866
|
+
const x1 = attr(tag, "x1");
|
|
58867
|
+
const y1 = attr(tag, "y1");
|
|
58868
|
+
const x2 = attr(tag, "x2");
|
|
58869
|
+
const y2 = attr(tag, "y2");
|
|
58870
|
+
if (x1 !== null && y1 !== null && x2 !== null && y2 !== null) {
|
|
58871
|
+
push(x1, y1);
|
|
58872
|
+
push(x2, y2);
|
|
58873
|
+
}
|
|
58874
|
+
}
|
|
58875
|
+
for (const m of svg.matchAll(/<circle\b[^>]*?\/?>/g)) {
|
|
58876
|
+
const tag = m[0];
|
|
58877
|
+
const cx = attr(tag, "cx");
|
|
58878
|
+
const cy = attr(tag, "cy");
|
|
58879
|
+
const r = attr(tag, "r");
|
|
58880
|
+
if (cx !== null && cy !== null && r !== null) {
|
|
58881
|
+
push(cx - r, cy - r);
|
|
58882
|
+
push(cx + r, cy + r);
|
|
58883
|
+
}
|
|
58884
|
+
}
|
|
58885
|
+
for (const m of svg.matchAll(/<ellipse\b[^>]*?\/?>/g)) {
|
|
58886
|
+
const tag = m[0];
|
|
58887
|
+
const cx = attr(tag, "cx");
|
|
58888
|
+
const cy = attr(tag, "cy");
|
|
58889
|
+
const rx = attr(tag, "rx");
|
|
58890
|
+
const ry = attr(tag, "ry");
|
|
58891
|
+
if (cx !== null && cy !== null && rx !== null && ry !== null) {
|
|
58892
|
+
push(cx - rx, cy - ry);
|
|
58893
|
+
push(cx + rx, cy + ry);
|
|
58894
|
+
}
|
|
58895
|
+
}
|
|
58896
|
+
for (const m of svg.matchAll(/<text\b([^>]*?)>([\s\S]*?)<\/text>/g)) {
|
|
58897
|
+
const tag = `<text${m[1]}>`;
|
|
58898
|
+
const text = m[2].replace(/<[^>]+>/g, "");
|
|
58899
|
+
const x = attr(tag, "x");
|
|
58900
|
+
const y = attr(tag, "y");
|
|
58901
|
+
if (x !== null && y !== null) {
|
|
58902
|
+
const w = text.length * 7;
|
|
58903
|
+
push(x - w / 2, y - 14);
|
|
58904
|
+
push(x + w / 2, y + 4);
|
|
58905
|
+
}
|
|
58906
|
+
}
|
|
58907
|
+
for (const m of svg.matchAll(/<path\b[^>]*?\bd="([^"]+)"/g)) {
|
|
58908
|
+
const d = m[1];
|
|
58909
|
+
const nums = d.match(/-?\d+(?:\.\d+)?/g);
|
|
58910
|
+
if (!nums) continue;
|
|
58911
|
+
for (let i = 0; i + 1 < nums.length; i += 2) {
|
|
58912
|
+
push(parseFloat(nums[i]), parseFloat(nums[i + 1]));
|
|
58913
|
+
}
|
|
58914
|
+
}
|
|
58915
|
+
for (const m of svg.matchAll(
|
|
58916
|
+
/<(?:polygon|polyline)\b[^>]*?\bpoints="([^"]+)"/g
|
|
58917
|
+
)) {
|
|
58918
|
+
const nums = m[1].match(/-?\d+(?:\.\d+)?/g);
|
|
58919
|
+
if (!nums) continue;
|
|
58920
|
+
for (let i = 0; i + 1 < nums.length; i += 2) {
|
|
58921
|
+
push(parseFloat(nums[i]), parseFloat(nums[i + 1]));
|
|
58922
|
+
}
|
|
58923
|
+
}
|
|
58924
|
+
if (xs.length === 0 || ys.length === 0) return null;
|
|
58925
|
+
const minX = Math.min(...xs);
|
|
58926
|
+
const maxX = Math.max(...xs);
|
|
58927
|
+
const minY = Math.min(...ys);
|
|
58928
|
+
const maxY = Math.max(...ys);
|
|
58929
|
+
return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
|
|
58930
|
+
}
|
|
58931
|
+
|
|
58723
58932
|
// src/map/completion.ts
|
|
58724
58933
|
var fold2 = (s) => s.normalize("NFD").replace(/\p{Diacritic}/gu, "").toLowerCase().trim();
|
|
58725
58934
|
var groupThousands = (n) => String(n).replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
@@ -58844,8 +59053,10 @@ function decodeDiagramUrl2(url) {
|
|
|
58844
59053
|
decodeDiagramUrl,
|
|
58845
59054
|
encodeDiagramUrl,
|
|
58846
59055
|
formatDgmoError,
|
|
59056
|
+
getEmbedSvgViewBox,
|
|
58847
59057
|
getMinDimensions,
|
|
58848
59058
|
getPalette,
|
|
59059
|
+
normalizeSvgForEmbed,
|
|
58849
59060
|
palettes,
|
|
58850
59061
|
render,
|
|
58851
59062
|
themes,
|
package/dist/index.d.cts
CHANGED
|
@@ -182,6 +182,42 @@ declare function getMinDimensions(content: string): {
|
|
|
182
182
|
height: number;
|
|
183
183
|
};
|
|
184
184
|
|
|
185
|
+
/**
|
|
186
|
+
* Make an SVG produced by `@diagrammo/dgmo`'s static `render()` suitable for
|
|
187
|
+
* responsive inline embedding in any host (Obsidian, remark/markdown, web
|
|
188
|
+
* pages):
|
|
189
|
+
*
|
|
190
|
+
* - dgmo renders diagrams inside a fixed export canvas (e.g.
|
|
191
|
+
* `viewBox="0 0 1200 800"`), with content often occupying only a fraction
|
|
192
|
+
* of it. We compute a tight content bounding box from element coordinates
|
|
193
|
+
* and set the root `viewBox` to bbox+padding, so the diagram's intrinsic
|
|
194
|
+
* aspect ratio matches its CONTENT — no dead space above/below or beside it.
|
|
195
|
+
* - Ensure the root `<svg>` has a `viewBox` so it scales responsively.
|
|
196
|
+
* - Strip fixed `width="N"` / `height="N"` so CSS (e.g. `width:100%;
|
|
197
|
+
* height:auto`, or an aspect-ratio derived from the tight viewBox) controls
|
|
198
|
+
* sizing.
|
|
199
|
+
* - Remove any inline `background:` from the root style so the page
|
|
200
|
+
* background shows through.
|
|
201
|
+
*
|
|
202
|
+
* This is intentionally a string transform, not a DOM `getBBox()` step: dgmo
|
|
203
|
+
* can dual-render light/dark SVGs where one is hidden by color-mode CSS, and
|
|
204
|
+
* `getBBox()` returns 0 for the hidden copy. Parsing coordinates from the
|
|
205
|
+
* markup measures both copies reliably and works server-side (Node).
|
|
206
|
+
*/
|
|
207
|
+
declare function normalizeSvgForEmbed(input: string): string;
|
|
208
|
+
/**
|
|
209
|
+
* Parse the content bounding box of a normalized embed SVG, if one can be
|
|
210
|
+
* derived. Returns `null` when no usable coordinates are found (e.g. an empty
|
|
211
|
+
* diagram). Useful for hosts that want to set an explicit `aspect-ratio` from
|
|
212
|
+
* the tight viewBox.
|
|
213
|
+
*/
|
|
214
|
+
declare function getEmbedSvgViewBox(svg: string): {
|
|
215
|
+
x: number;
|
|
216
|
+
y: number;
|
|
217
|
+
width: number;
|
|
218
|
+
height: number;
|
|
219
|
+
} | null;
|
|
220
|
+
|
|
185
221
|
/**
|
|
186
222
|
* A gazetteer city entry: `[lat, lon, iso, pop, name, sub?]`.
|
|
187
223
|
* - `lat`/`lon` — rounded to 3 decimals.
|
|
@@ -336,4 +372,4 @@ interface DecodedDiagramUrl {
|
|
|
336
372
|
*/
|
|
337
373
|
declare function decodeDiagramUrl(url: string): DecodedDiagramUrl | null;
|
|
338
374
|
|
|
339
|
-
export { type CompactViewState, type DecodedDiagramUrl, type DgmoError, type DgmoSeverity, type EncodeDiagramUrlOptions, type Gazetteer, type GazetteerEntry, type MapCompletionOptions, type MapPlaceCompletion, type MapRegionCompletion, type PaletteColors, type PaletteConfig, type RegionName, type RegionNames, type RenderOptions, type RenderResult, type Theme, completeMapPlaces, completeMapRegions, decodeDiagramUrl, encodeDiagramUrl, formatDgmoError, getMinDimensions, getPalette, palettes, render, themes, parseDgmo as validate };
|
|
375
|
+
export { type CompactViewState, type DecodedDiagramUrl, type DgmoError, type DgmoSeverity, type EncodeDiagramUrlOptions, type Gazetteer, type GazetteerEntry, type MapCompletionOptions, type MapPlaceCompletion, type MapRegionCompletion, type PaletteColors, type PaletteConfig, type RegionName, type RegionNames, type RenderOptions, type RenderResult, type Theme, completeMapPlaces, completeMapRegions, decodeDiagramUrl, encodeDiagramUrl, formatDgmoError, getEmbedSvgViewBox, getMinDimensions, getPalette, normalizeSvgForEmbed, palettes, render, themes, parseDgmo as validate };
|
package/dist/index.d.ts
CHANGED
|
@@ -182,6 +182,42 @@ declare function getMinDimensions(content: string): {
|
|
|
182
182
|
height: number;
|
|
183
183
|
};
|
|
184
184
|
|
|
185
|
+
/**
|
|
186
|
+
* Make an SVG produced by `@diagrammo/dgmo`'s static `render()` suitable for
|
|
187
|
+
* responsive inline embedding in any host (Obsidian, remark/markdown, web
|
|
188
|
+
* pages):
|
|
189
|
+
*
|
|
190
|
+
* - dgmo renders diagrams inside a fixed export canvas (e.g.
|
|
191
|
+
* `viewBox="0 0 1200 800"`), with content often occupying only a fraction
|
|
192
|
+
* of it. We compute a tight content bounding box from element coordinates
|
|
193
|
+
* and set the root `viewBox` to bbox+padding, so the diagram's intrinsic
|
|
194
|
+
* aspect ratio matches its CONTENT — no dead space above/below or beside it.
|
|
195
|
+
* - Ensure the root `<svg>` has a `viewBox` so it scales responsively.
|
|
196
|
+
* - Strip fixed `width="N"` / `height="N"` so CSS (e.g. `width:100%;
|
|
197
|
+
* height:auto`, or an aspect-ratio derived from the tight viewBox) controls
|
|
198
|
+
* sizing.
|
|
199
|
+
* - Remove any inline `background:` from the root style so the page
|
|
200
|
+
* background shows through.
|
|
201
|
+
*
|
|
202
|
+
* This is intentionally a string transform, not a DOM `getBBox()` step: dgmo
|
|
203
|
+
* can dual-render light/dark SVGs where one is hidden by color-mode CSS, and
|
|
204
|
+
* `getBBox()` returns 0 for the hidden copy. Parsing coordinates from the
|
|
205
|
+
* markup measures both copies reliably and works server-side (Node).
|
|
206
|
+
*/
|
|
207
|
+
declare function normalizeSvgForEmbed(input: string): string;
|
|
208
|
+
/**
|
|
209
|
+
* Parse the content bounding box of a normalized embed SVG, if one can be
|
|
210
|
+
* derived. Returns `null` when no usable coordinates are found (e.g. an empty
|
|
211
|
+
* diagram). Useful for hosts that want to set an explicit `aspect-ratio` from
|
|
212
|
+
* the tight viewBox.
|
|
213
|
+
*/
|
|
214
|
+
declare function getEmbedSvgViewBox(svg: string): {
|
|
215
|
+
x: number;
|
|
216
|
+
y: number;
|
|
217
|
+
width: number;
|
|
218
|
+
height: number;
|
|
219
|
+
} | null;
|
|
220
|
+
|
|
185
221
|
/**
|
|
186
222
|
* A gazetteer city entry: `[lat, lon, iso, pop, name, sub?]`.
|
|
187
223
|
* - `lat`/`lon` — rounded to 3 decimals.
|
|
@@ -336,4 +372,4 @@ interface DecodedDiagramUrl {
|
|
|
336
372
|
*/
|
|
337
373
|
declare function decodeDiagramUrl(url: string): DecodedDiagramUrl | null;
|
|
338
374
|
|
|
339
|
-
export { type CompactViewState, type DecodedDiagramUrl, type DgmoError, type DgmoSeverity, type EncodeDiagramUrlOptions, type Gazetteer, type GazetteerEntry, type MapCompletionOptions, type MapPlaceCompletion, type MapRegionCompletion, type PaletteColors, type PaletteConfig, type RegionName, type RegionNames, type RenderOptions, type RenderResult, type Theme, completeMapPlaces, completeMapRegions, decodeDiagramUrl, encodeDiagramUrl, formatDgmoError, getMinDimensions, getPalette, palettes, render, themes, parseDgmo as validate };
|
|
375
|
+
export { type CompactViewState, type DecodedDiagramUrl, type DgmoError, type DgmoSeverity, type EncodeDiagramUrlOptions, type Gazetteer, type GazetteerEntry, type MapCompletionOptions, type MapPlaceCompletion, type MapRegionCompletion, type PaletteColors, type PaletteConfig, type RegionName, type RegionNames, type RenderOptions, type RenderResult, type Theme, completeMapPlaces, completeMapRegions, decodeDiagramUrl, encodeDiagramUrl, formatDgmoError, getEmbedSvgViewBox, getMinDimensions, getPalette, normalizeSvgForEmbed, palettes, render, themes, parseDgmo as validate };
|