@diagrammo/dgmo 0.21.1 → 0.22.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/README.md +16 -6
- package/dist/advanced.cjs +2003 -466
- package/dist/advanced.d.cts +5714 -0
- package/dist/advanced.d.ts +5714 -0
- package/dist/advanced.js +1999 -466
- package/dist/auto.cjs +2048 -449
- package/dist/auto.d.cts +39 -0
- package/dist/auto.d.ts +39 -0
- package/dist/auto.js +121 -121
- package/dist/auto.mjs +2050 -450
- package/dist/cli.cjs +170 -170
- package/dist/editor.cjs +13 -16
- package/dist/editor.js +13 -16
- package/dist/highlight.cjs +15 -13
- package/dist/highlight.js +15 -13
- package/dist/index.cjs +2032 -435
- package/dist/index.d.cts +339 -0
- package/dist/index.d.ts +339 -0
- package/dist/index.js +2034 -436
- package/dist/internal.cjs +2003 -466
- package/dist/internal.d.cts +5714 -0
- package/dist/internal.d.ts +5714 -0
- package/dist/internal.js +1999 -466
- package/dist/map-data/water-bodies.json +1 -0
- package/docs/language-reference.md +20 -9
- package/gallery/fixtures/map-categorical-world.dgmo +16 -0
- package/gallery/fixtures/map-categorical.dgmo +0 -1
- package/gallery/fixtures/map-choropleth.dgmo +0 -1
- package/gallery/fixtures/map-coastline.dgmo +7 -0
- package/gallery/fixtures/map-colorize.dgmo +11 -0
- package/gallery/fixtures/map-direct-color.dgmo +0 -1
- package/gallery/fixtures/map-reference-world.dgmo +11 -0
- package/gallery/fixtures/map-region-scope.dgmo +0 -3
- package/gallery/fixtures/map-route.dgmo +0 -1
- package/package.json +1 -1
- package/src/advanced.ts +12 -1
- package/src/boxes-and-lines/renderer.ts +39 -12
- package/src/cli.ts +1 -1
- package/src/completion.ts +32 -25
- package/src/cycle/renderer.ts +14 -1
- package/src/d3.ts +8 -2
- package/src/editor/highlight-api.ts +4 -0
- package/src/editor/keywords.ts +13 -16
- package/src/infra/renderer.ts +35 -7
- package/src/map/colorize.ts +54 -0
- package/src/map/context-labels.ts +429 -0
- package/src/map/data/types.ts +34 -0
- package/src/map/data/water-bodies.json +1 -0
- package/src/map/dimensions.ts +117 -0
- package/src/map/geo-query.ts +21 -3
- package/src/map/geo.ts +47 -1
- package/src/map/layout.ts +1300 -251
- package/src/map/load-data.ts +10 -2
- package/src/map/parser.ts +42 -116
- package/src/map/renderer.ts +512 -13
- package/src/map/resolved-types.ts +16 -2
- package/src/map/resolver.ts +208 -59
- package/src/map/types.ts +30 -32
- package/src/mindmap/renderer.ts +10 -1
- package/src/palettes/atlas.ts +77 -0
- package/src/palettes/blueprint.ts +73 -0
- package/src/palettes/color-utils.ts +58 -1
- package/src/palettes/index.ts +12 -3
- package/src/palettes/slate.ts +73 -0
- package/src/palettes/tidewater.ts +73 -0
- package/src/render.ts +8 -1
- package/src/tech-radar/renderer.ts +3 -0
- package/src/tech-radar/types.ts +3 -0
- package/src/utils/d3-types.ts +5 -0
- package/src/utils/legend-layout.ts +21 -4
- package/src/utils/legend-types.ts +7 -0
- package/src/utils/reserved-key-registry.ts +3 -0
- package/src/palettes/bold.ts +0 -67
package/dist/auto.mjs
CHANGED
|
@@ -91,18 +91,18 @@ function computeQuadrantPointLabels(points, chartBounds, obstacles, pointRadius,
|
|
|
91
91
|
const results = [];
|
|
92
92
|
for (let i = 0; i < points.length; i++) {
|
|
93
93
|
const pt = points[i];
|
|
94
|
-
const
|
|
94
|
+
const labelWidth2 = pt.label.length * fontSize * CHAR_WIDTH_RATIO + 8;
|
|
95
95
|
let best = null;
|
|
96
96
|
const directions = [
|
|
97
97
|
{
|
|
98
98
|
// Above
|
|
99
99
|
gen: (offset) => {
|
|
100
|
-
const lx = pt.cx -
|
|
100
|
+
const lx = pt.cx - labelWidth2 / 2;
|
|
101
101
|
const ly = pt.cy - offset - labelHeight;
|
|
102
|
-
if (ly < chartBounds.top || lx < chartBounds.left || lx +
|
|
102
|
+
if (ly < chartBounds.top || lx < chartBounds.left || lx + labelWidth2 > chartBounds.right)
|
|
103
103
|
return null;
|
|
104
104
|
return {
|
|
105
|
-
rect: { x: lx, y: ly, w:
|
|
105
|
+
rect: { x: lx, y: ly, w: labelWidth2, h: labelHeight },
|
|
106
106
|
textX: pt.cx,
|
|
107
107
|
textY: ly + labelHeight / 2,
|
|
108
108
|
anchor: "middle"
|
|
@@ -112,12 +112,12 @@ function computeQuadrantPointLabels(points, chartBounds, obstacles, pointRadius,
|
|
|
112
112
|
{
|
|
113
113
|
// Below
|
|
114
114
|
gen: (offset) => {
|
|
115
|
-
const lx = pt.cx -
|
|
115
|
+
const lx = pt.cx - labelWidth2 / 2;
|
|
116
116
|
const ly = pt.cy + offset;
|
|
117
|
-
if (ly + labelHeight > chartBounds.bottom || lx < chartBounds.left || lx +
|
|
117
|
+
if (ly + labelHeight > chartBounds.bottom || lx < chartBounds.left || lx + labelWidth2 > chartBounds.right)
|
|
118
118
|
return null;
|
|
119
119
|
return {
|
|
120
|
-
rect: { x: lx, y: ly, w:
|
|
120
|
+
rect: { x: lx, y: ly, w: labelWidth2, h: labelHeight },
|
|
121
121
|
textX: pt.cx,
|
|
122
122
|
textY: ly + labelHeight / 2,
|
|
123
123
|
anchor: "middle"
|
|
@@ -129,10 +129,10 @@ function computeQuadrantPointLabels(points, chartBounds, obstacles, pointRadius,
|
|
|
129
129
|
gen: (offset) => {
|
|
130
130
|
const lx = pt.cx + offset;
|
|
131
131
|
const ly = pt.cy - labelHeight / 2;
|
|
132
|
-
if (lx +
|
|
132
|
+
if (lx + labelWidth2 > chartBounds.right || ly < chartBounds.top || ly + labelHeight > chartBounds.bottom)
|
|
133
133
|
return null;
|
|
134
134
|
return {
|
|
135
|
-
rect: { x: lx, y: ly, w:
|
|
135
|
+
rect: { x: lx, y: ly, w: labelWidth2, h: labelHeight },
|
|
136
136
|
textX: lx,
|
|
137
137
|
textY: pt.cy,
|
|
138
138
|
anchor: "start"
|
|
@@ -142,13 +142,13 @@ function computeQuadrantPointLabels(points, chartBounds, obstacles, pointRadius,
|
|
|
142
142
|
{
|
|
143
143
|
// Left
|
|
144
144
|
gen: (offset) => {
|
|
145
|
-
const lx = pt.cx - offset -
|
|
145
|
+
const lx = pt.cx - offset - labelWidth2;
|
|
146
146
|
const ly = pt.cy - labelHeight / 2;
|
|
147
147
|
if (lx < chartBounds.left || ly < chartBounds.top || ly + labelHeight > chartBounds.bottom)
|
|
148
148
|
return null;
|
|
149
149
|
return {
|
|
150
|
-
rect: { x: lx, y: ly, w:
|
|
151
|
-
textX: lx +
|
|
150
|
+
rect: { x: lx, y: ly, w: labelWidth2, h: labelHeight },
|
|
151
|
+
textX: lx + labelWidth2,
|
|
152
152
|
textY: pt.cy,
|
|
153
153
|
anchor: "end"
|
|
154
154
|
};
|
|
@@ -198,10 +198,10 @@ function computeQuadrantPointLabels(points, chartBounds, obstacles, pointRadius,
|
|
|
198
198
|
}
|
|
199
199
|
}
|
|
200
200
|
if (!best) {
|
|
201
|
-
const lx = pt.cx -
|
|
201
|
+
const lx = pt.cx - labelWidth2 / 2;
|
|
202
202
|
const ly = pt.cy - minGap - labelHeight;
|
|
203
203
|
best = {
|
|
204
|
-
rect: { x: lx, y: ly, w:
|
|
204
|
+
rect: { x: lx, y: ly, w: labelWidth2, h: labelHeight },
|
|
205
205
|
textX: pt.cx,
|
|
206
206
|
textY: ly + labelHeight / 2,
|
|
207
207
|
anchor: "middle",
|
|
@@ -761,6 +761,9 @@ var init_reserved_key_registry = __esm({
|
|
|
761
761
|
"value",
|
|
762
762
|
"label",
|
|
763
763
|
"style"
|
|
764
|
+
// `surface:` was removed in the 2026-06-02 defaults-on review — it is no longer
|
|
765
|
+
// a recognized metadata key (the route/edge surface feature was cut; §24B.7).
|
|
766
|
+
// A stray `surface: water` is no longer captured as a reserved key.
|
|
764
767
|
]);
|
|
765
768
|
ORG_REGISTRY = staticRegistry([
|
|
766
769
|
"color",
|
|
@@ -1823,77 +1826,266 @@ function getSegmentColors(palette, count) {
|
|
|
1823
1826
|
(_, i) => hslToHex(Math.round((startHue + i * step) % 360), avgS, avgL)
|
|
1824
1827
|
);
|
|
1825
1828
|
}
|
|
1829
|
+
function politicalTints(palette, count, isDark) {
|
|
1830
|
+
if (count <= 0) return [];
|
|
1831
|
+
const base = isDark ? palette.surface : palette.bg;
|
|
1832
|
+
const c = palette.colors;
|
|
1833
|
+
const swatches = [
|
|
1834
|
+
.../* @__PURE__ */ new Set([
|
|
1835
|
+
c.green,
|
|
1836
|
+
c.yellow,
|
|
1837
|
+
c.orange,
|
|
1838
|
+
c.purple,
|
|
1839
|
+
c.red,
|
|
1840
|
+
c.teal,
|
|
1841
|
+
c.cyan,
|
|
1842
|
+
c.blue
|
|
1843
|
+
])
|
|
1844
|
+
];
|
|
1845
|
+
const bands = isDark ? POLITICAL_TINT_BANDS.dark : POLITICAL_TINT_BANDS.light;
|
|
1846
|
+
const out = [];
|
|
1847
|
+
for (const pct of bands) {
|
|
1848
|
+
if (out.length >= count) break;
|
|
1849
|
+
for (const s of swatches) out.push(mix(s, base, pct));
|
|
1850
|
+
}
|
|
1851
|
+
return out.slice(0, count);
|
|
1852
|
+
}
|
|
1853
|
+
var POLITICAL_TINT_BANDS;
|
|
1826
1854
|
var init_color_utils = __esm({
|
|
1827
1855
|
"src/palettes/color-utils.ts"() {
|
|
1828
1856
|
"use strict";
|
|
1857
|
+
POLITICAL_TINT_BANDS = {
|
|
1858
|
+
light: [32, 48, 64, 80],
|
|
1859
|
+
dark: [44, 58, 72, 86]
|
|
1860
|
+
};
|
|
1829
1861
|
}
|
|
1830
1862
|
});
|
|
1831
1863
|
|
|
1832
|
-
// src/palettes/
|
|
1833
|
-
var
|
|
1834
|
-
var
|
|
1835
|
-
"src/palettes/
|
|
1864
|
+
// src/palettes/atlas.ts
|
|
1865
|
+
var atlasPalette;
|
|
1866
|
+
var init_atlas = __esm({
|
|
1867
|
+
"src/palettes/atlas.ts"() {
|
|
1836
1868
|
"use strict";
|
|
1837
1869
|
init_registry();
|
|
1838
|
-
|
|
1839
|
-
id: "
|
|
1840
|
-
name: "
|
|
1870
|
+
atlasPalette = {
|
|
1871
|
+
id: "atlas",
|
|
1872
|
+
name: "Atlas",
|
|
1841
1873
|
light: {
|
|
1842
|
-
bg: "#
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1874
|
+
bg: "#f3ead3",
|
|
1875
|
+
// warm manila / parchment
|
|
1876
|
+
surface: "#ece0c0",
|
|
1877
|
+
// deeper paper (cards, panels)
|
|
1878
|
+
overlay: "#e8dab8",
|
|
1879
|
+
// popovers, dropdowns
|
|
1880
|
+
border: "#bcaa86",
|
|
1881
|
+
// muted sepia rule line
|
|
1882
|
+
text: "#463a26",
|
|
1883
|
+
// aged sepia-brown ink
|
|
1884
|
+
textMuted: "#7a6a4f",
|
|
1885
|
+
// faded annotation ink
|
|
1886
|
+
textOnFillLight: "#f7f1de",
|
|
1887
|
+
// parchment (light text on dark fills)
|
|
1888
|
+
textOnFillDark: "#3a2e1c",
|
|
1889
|
+
// deep ink (dark text on light fills)
|
|
1890
|
+
primary: "#5b7a99",
|
|
1891
|
+
// pull-down map ocean (steel-blue)
|
|
1892
|
+
secondary: "#7e9a6f",
|
|
1893
|
+
// lowland sage / celadon
|
|
1894
|
+
accent: "#b07f7c",
|
|
1895
|
+
// dusty rose
|
|
1896
|
+
destructive: "#b25a45",
|
|
1897
|
+
// brick / terracotta
|
|
1854
1898
|
colors: {
|
|
1855
|
-
red: "#
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1899
|
+
red: "#bf6a52",
|
|
1900
|
+
// terracotta brick
|
|
1901
|
+
orange: "#cf9a5c",
|
|
1902
|
+
// map tan / ochre
|
|
1903
|
+
yellow: "#cdb35e",
|
|
1904
|
+
// straw / muted lemon
|
|
1905
|
+
green: "#7e9a6f",
|
|
1906
|
+
// sage / celadon lowland
|
|
1907
|
+
blue: "#5b7a99",
|
|
1908
|
+
// steel-blue ocean
|
|
1909
|
+
purple: "#9a7fa6",
|
|
1910
|
+
// dusty lilac / mauve
|
|
1911
|
+
teal: "#6fa094",
|
|
1912
|
+
// muted seafoam
|
|
1913
|
+
cyan: "#79a7b5",
|
|
1914
|
+
// shallow-water blue
|
|
1915
|
+
gray: "#8a7d68",
|
|
1916
|
+
// warm taupe
|
|
1917
|
+
black: "#463a26",
|
|
1918
|
+
// ink
|
|
1919
|
+
white: "#ece0c0"
|
|
1920
|
+
// paper
|
|
1866
1921
|
}
|
|
1867
1922
|
},
|
|
1868
1923
|
dark: {
|
|
1869
|
-
bg: "#
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1924
|
+
bg: "#1e2a33",
|
|
1925
|
+
// deep map ocean (night globe)
|
|
1926
|
+
surface: "#27353f",
|
|
1927
|
+
// raised ocean
|
|
1928
|
+
overlay: "#2e3d48",
|
|
1929
|
+
// popovers, dropdowns
|
|
1930
|
+
border: "#3d4f5c",
|
|
1931
|
+
// depth-contour line
|
|
1932
|
+
text: "#e8dcc0",
|
|
1933
|
+
// parchment ink, inverted
|
|
1934
|
+
textMuted: "#a89a7d",
|
|
1935
|
+
// faded label
|
|
1936
|
+
textOnFillLight: "#f7f1de",
|
|
1937
|
+
// parchment
|
|
1938
|
+
textOnFillDark: "#1a242c",
|
|
1939
|
+
// deep ocean ink
|
|
1940
|
+
primary: "#7ba0bf",
|
|
1941
|
+
// brighter ocean
|
|
1942
|
+
secondary: "#9bb588",
|
|
1943
|
+
// sage, lifted
|
|
1944
|
+
accent: "#cf9a96",
|
|
1945
|
+
// dusty rose, lifted
|
|
1946
|
+
destructive: "#c9745c",
|
|
1947
|
+
// brick, lifted
|
|
1881
1948
|
colors: {
|
|
1882
|
-
red: "#
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1949
|
+
red: "#cf7a60",
|
|
1950
|
+
// terracotta
|
|
1951
|
+
orange: "#d9a96a",
|
|
1952
|
+
// tan / ochre
|
|
1953
|
+
yellow: "#d8c074",
|
|
1954
|
+
// straw
|
|
1955
|
+
green: "#9bb588",
|
|
1956
|
+
// sage lowland
|
|
1957
|
+
blue: "#7ba0bf",
|
|
1958
|
+
// ocean
|
|
1959
|
+
purple: "#b59ac0",
|
|
1960
|
+
// lilac / mauve
|
|
1961
|
+
teal: "#85b3a6",
|
|
1962
|
+
// seafoam
|
|
1963
|
+
cyan: "#92bccb",
|
|
1964
|
+
// shallow-water blue
|
|
1965
|
+
gray: "#9a8d76",
|
|
1966
|
+
// warm taupe
|
|
1967
|
+
black: "#27353f",
|
|
1968
|
+
// raised ocean
|
|
1969
|
+
white: "#e8dcc0"
|
|
1970
|
+
// parchment
|
|
1893
1971
|
}
|
|
1894
1972
|
}
|
|
1895
1973
|
};
|
|
1896
|
-
registerPalette(
|
|
1974
|
+
registerPalette(atlasPalette);
|
|
1975
|
+
}
|
|
1976
|
+
});
|
|
1977
|
+
|
|
1978
|
+
// src/palettes/blueprint.ts
|
|
1979
|
+
var blueprintPalette;
|
|
1980
|
+
var init_blueprint = __esm({
|
|
1981
|
+
"src/palettes/blueprint.ts"() {
|
|
1982
|
+
"use strict";
|
|
1983
|
+
init_registry();
|
|
1984
|
+
blueprintPalette = {
|
|
1985
|
+
id: "blueprint",
|
|
1986
|
+
name: "Blueprint",
|
|
1987
|
+
light: {
|
|
1988
|
+
bg: "#f4f8fb",
|
|
1989
|
+
// pale drafting white (faint cyan)
|
|
1990
|
+
surface: "#e6eef4",
|
|
1991
|
+
// drafting panel
|
|
1992
|
+
overlay: "#dde9f1",
|
|
1993
|
+
// popovers, dropdowns
|
|
1994
|
+
border: "#aac3d6",
|
|
1995
|
+
// pale blue grid line
|
|
1996
|
+
text: "#123a5e",
|
|
1997
|
+
// blueprint navy ink
|
|
1998
|
+
textMuted: "#4f7390",
|
|
1999
|
+
// faint draft note
|
|
2000
|
+
textOnFillLight: "#f4f8fb",
|
|
2001
|
+
// drafting white
|
|
2002
|
+
textOnFillDark: "#0c2f4d",
|
|
2003
|
+
// deep blueprint navy
|
|
2004
|
+
primary: "#1f5e8c",
|
|
2005
|
+
// blueprint blue
|
|
2006
|
+
secondary: "#5b7d96",
|
|
2007
|
+
// steel
|
|
2008
|
+
accent: "#b08a3e",
|
|
2009
|
+
// draftsman's ochre highlight
|
|
2010
|
+
destructive: "#c0504d",
|
|
2011
|
+
// correction red
|
|
2012
|
+
colors: {
|
|
2013
|
+
red: "#c25a4e",
|
|
2014
|
+
// correction red
|
|
2015
|
+
orange: "#c2823e",
|
|
2016
|
+
// ochre
|
|
2017
|
+
yellow: "#c2a843",
|
|
2018
|
+
// pencil gold
|
|
2019
|
+
green: "#4f8a6b",
|
|
2020
|
+
// drafting green
|
|
2021
|
+
blue: "#1f5e8c",
|
|
2022
|
+
// blueprint blue
|
|
2023
|
+
purple: "#6f5e96",
|
|
2024
|
+
// indigo pencil
|
|
2025
|
+
teal: "#3a8a8a",
|
|
2026
|
+
// teal
|
|
2027
|
+
cyan: "#3f8fb5",
|
|
2028
|
+
// cyan
|
|
2029
|
+
gray: "#7e8e98",
|
|
2030
|
+
// graphite
|
|
2031
|
+
black: "#123a5e",
|
|
2032
|
+
// navy ink
|
|
2033
|
+
white: "#e6eef4"
|
|
2034
|
+
// panel
|
|
2035
|
+
}
|
|
2036
|
+
},
|
|
2037
|
+
dark: {
|
|
2038
|
+
bg: "#103a5e",
|
|
2039
|
+
// deep blueprint blue (cyanotype ground)
|
|
2040
|
+
surface: "#16466e",
|
|
2041
|
+
// raised sheet
|
|
2042
|
+
overlay: "#1c5180",
|
|
2043
|
+
// popovers, dropdowns
|
|
2044
|
+
border: "#3a6f96",
|
|
2045
|
+
// grid line
|
|
2046
|
+
text: "#eaf2f8",
|
|
2047
|
+
// chalk white
|
|
2048
|
+
textMuted: "#9fc0d6",
|
|
2049
|
+
// faint chalk note
|
|
2050
|
+
textOnFillLight: "#eaf2f8",
|
|
2051
|
+
// chalk white
|
|
2052
|
+
textOnFillDark: "#0c2f4d",
|
|
2053
|
+
// deep blueprint navy
|
|
2054
|
+
primary: "#7fb8d8",
|
|
2055
|
+
// chalk cyan
|
|
2056
|
+
secondary: "#9fb8c8",
|
|
2057
|
+
// pale steel
|
|
2058
|
+
accent: "#d8c27a",
|
|
2059
|
+
// chalk amber
|
|
2060
|
+
destructive: "#e08a7a",
|
|
2061
|
+
// chalk correction red
|
|
2062
|
+
colors: {
|
|
2063
|
+
red: "#e0907e",
|
|
2064
|
+
// chalk red
|
|
2065
|
+
orange: "#e0ab78",
|
|
2066
|
+
// chalk amber
|
|
2067
|
+
yellow: "#e3d089",
|
|
2068
|
+
// chalk gold
|
|
2069
|
+
green: "#93c79e",
|
|
2070
|
+
// chalk green
|
|
2071
|
+
blue: "#8ec3e0",
|
|
2072
|
+
// chalk cyan-blue
|
|
2073
|
+
purple: "#b6a6d8",
|
|
2074
|
+
// chalk indigo
|
|
2075
|
+
teal: "#84c7c2",
|
|
2076
|
+
// chalk teal
|
|
2077
|
+
cyan: "#9fd6e0",
|
|
2078
|
+
// chalk cyan
|
|
2079
|
+
gray: "#aebecb",
|
|
2080
|
+
// chalk graphite
|
|
2081
|
+
black: "#16466e",
|
|
2082
|
+
// raised sheet
|
|
2083
|
+
white: "#eaf2f8"
|
|
2084
|
+
// chalk white
|
|
2085
|
+
}
|
|
2086
|
+
}
|
|
2087
|
+
};
|
|
2088
|
+
registerPalette(blueprintPalette);
|
|
1897
2089
|
}
|
|
1898
2090
|
});
|
|
1899
2091
|
|
|
@@ -2390,6 +2582,120 @@ var init_rose_pine = __esm({
|
|
|
2390
2582
|
}
|
|
2391
2583
|
});
|
|
2392
2584
|
|
|
2585
|
+
// src/palettes/slate.ts
|
|
2586
|
+
var slatePalette;
|
|
2587
|
+
var init_slate = __esm({
|
|
2588
|
+
"src/palettes/slate.ts"() {
|
|
2589
|
+
"use strict";
|
|
2590
|
+
init_registry();
|
|
2591
|
+
slatePalette = {
|
|
2592
|
+
id: "slate",
|
|
2593
|
+
name: "Slate",
|
|
2594
|
+
light: {
|
|
2595
|
+
bg: "#ffffff",
|
|
2596
|
+
// clean slide white
|
|
2597
|
+
surface: "#f3f5f8",
|
|
2598
|
+
// light cool-gray panel
|
|
2599
|
+
overlay: "#eaeef3",
|
|
2600
|
+
// popovers, dropdowns
|
|
2601
|
+
border: "#d4dae1",
|
|
2602
|
+
// hairline rule
|
|
2603
|
+
text: "#1f2933",
|
|
2604
|
+
// near-black slate (softer than pure black)
|
|
2605
|
+
textMuted: "#5b6672",
|
|
2606
|
+
// secondary label
|
|
2607
|
+
textOnFillLight: "#ffffff",
|
|
2608
|
+
// light text on dark fills
|
|
2609
|
+
textOnFillDark: "#1f2933",
|
|
2610
|
+
// dark text on light fills
|
|
2611
|
+
primary: "#3b6ea5",
|
|
2612
|
+
// confident corporate blue
|
|
2613
|
+
secondary: "#5b6672",
|
|
2614
|
+
// slate gray
|
|
2615
|
+
accent: "#3a9188",
|
|
2616
|
+
// muted teal accent
|
|
2617
|
+
destructive: "#c0504d",
|
|
2618
|
+
// brick red
|
|
2619
|
+
colors: {
|
|
2620
|
+
red: "#c0504d",
|
|
2621
|
+
// brick
|
|
2622
|
+
orange: "#cc7a33",
|
|
2623
|
+
// muted amber
|
|
2624
|
+
yellow: "#c9a227",
|
|
2625
|
+
// gold (not neon)
|
|
2626
|
+
green: "#5b9357",
|
|
2627
|
+
// forest / sage
|
|
2628
|
+
blue: "#3b6ea5",
|
|
2629
|
+
// corporate blue
|
|
2630
|
+
purple: "#7d5ba6",
|
|
2631
|
+
// muted violet
|
|
2632
|
+
teal: "#3a9188",
|
|
2633
|
+
// teal
|
|
2634
|
+
cyan: "#4f96c4",
|
|
2635
|
+
// steel cyan
|
|
2636
|
+
gray: "#7e8a97",
|
|
2637
|
+
// cool gray
|
|
2638
|
+
black: "#1f2933",
|
|
2639
|
+
// slate ink
|
|
2640
|
+
white: "#f3f5f8"
|
|
2641
|
+
// panel
|
|
2642
|
+
}
|
|
2643
|
+
},
|
|
2644
|
+
dark: {
|
|
2645
|
+
bg: "#161b22",
|
|
2646
|
+
// deep slate (keynote dark)
|
|
2647
|
+
surface: "#202833",
|
|
2648
|
+
// raised panel
|
|
2649
|
+
overlay: "#29323e",
|
|
2650
|
+
// popovers, dropdowns
|
|
2651
|
+
border: "#38424f",
|
|
2652
|
+
// divider
|
|
2653
|
+
text: "#e6eaef",
|
|
2654
|
+
// off-white
|
|
2655
|
+
textMuted: "#9aa5b1",
|
|
2656
|
+
// secondary label
|
|
2657
|
+
textOnFillLight: "#ffffff",
|
|
2658
|
+
// light text on dark fills
|
|
2659
|
+
textOnFillDark: "#161b22",
|
|
2660
|
+
// dark text on light fills
|
|
2661
|
+
primary: "#5b9bd5",
|
|
2662
|
+
// lifted corporate blue
|
|
2663
|
+
secondary: "#8593a3",
|
|
2664
|
+
// slate gray, lifted
|
|
2665
|
+
accent: "#45b3a3",
|
|
2666
|
+
// teal, lifted
|
|
2667
|
+
destructive: "#e07b6e",
|
|
2668
|
+
// brick, lifted
|
|
2669
|
+
colors: {
|
|
2670
|
+
red: "#e07b6e",
|
|
2671
|
+
// brick
|
|
2672
|
+
orange: "#e0975a",
|
|
2673
|
+
// amber
|
|
2674
|
+
yellow: "#d9bd5a",
|
|
2675
|
+
// gold
|
|
2676
|
+
green: "#74b56e",
|
|
2677
|
+
// forest / sage
|
|
2678
|
+
blue: "#5b9bd5",
|
|
2679
|
+
// corporate blue
|
|
2680
|
+
purple: "#a585c9",
|
|
2681
|
+
// violet
|
|
2682
|
+
teal: "#45b3a3",
|
|
2683
|
+
// teal
|
|
2684
|
+
cyan: "#62b0d9",
|
|
2685
|
+
// steel cyan
|
|
2686
|
+
gray: "#95a1ae",
|
|
2687
|
+
// cool gray
|
|
2688
|
+
black: "#202833",
|
|
2689
|
+
// raised panel
|
|
2690
|
+
white: "#e6eaef"
|
|
2691
|
+
// off-white
|
|
2692
|
+
}
|
|
2693
|
+
}
|
|
2694
|
+
};
|
|
2695
|
+
registerPalette(slatePalette);
|
|
2696
|
+
}
|
|
2697
|
+
});
|
|
2698
|
+
|
|
2393
2699
|
// src/palettes/solarized.ts
|
|
2394
2700
|
var solarizedPalette;
|
|
2395
2701
|
var init_solarized = __esm({
|
|
@@ -2485,6 +2791,120 @@ var init_solarized = __esm({
|
|
|
2485
2791
|
}
|
|
2486
2792
|
});
|
|
2487
2793
|
|
|
2794
|
+
// src/palettes/tidewater.ts
|
|
2795
|
+
var tidewaterPalette;
|
|
2796
|
+
var init_tidewater = __esm({
|
|
2797
|
+
"src/palettes/tidewater.ts"() {
|
|
2798
|
+
"use strict";
|
|
2799
|
+
init_registry();
|
|
2800
|
+
tidewaterPalette = {
|
|
2801
|
+
id: "tidewater",
|
|
2802
|
+
name: "Tidewater",
|
|
2803
|
+
light: {
|
|
2804
|
+
bg: "#eceff0",
|
|
2805
|
+
// weathered sea-mist paper
|
|
2806
|
+
surface: "#e0e4e3",
|
|
2807
|
+
// worn deck panel
|
|
2808
|
+
overlay: "#dadfdf",
|
|
2809
|
+
// popovers, dropdowns
|
|
2810
|
+
border: "#a9b2b3",
|
|
2811
|
+
// muted slate rule
|
|
2812
|
+
text: "#18313f",
|
|
2813
|
+
// ship's-log navy ink
|
|
2814
|
+
textMuted: "#51636b",
|
|
2815
|
+
// faded log entry
|
|
2816
|
+
textOnFillLight: "#f3f5f3",
|
|
2817
|
+
// weathered white
|
|
2818
|
+
textOnFillDark: "#162c38",
|
|
2819
|
+
// deep navy
|
|
2820
|
+
primary: "#1f4e6b",
|
|
2821
|
+
// deep-sea navy
|
|
2822
|
+
secondary: "#b08a4f",
|
|
2823
|
+
// rope / manila tan
|
|
2824
|
+
accent: "#c69a3e",
|
|
2825
|
+
// brass
|
|
2826
|
+
destructive: "#c1433a",
|
|
2827
|
+
// signal-flag red
|
|
2828
|
+
colors: {
|
|
2829
|
+
red: "#c1433a",
|
|
2830
|
+
// signal-flag red
|
|
2831
|
+
orange: "#cc7a38",
|
|
2832
|
+
// weathered amber
|
|
2833
|
+
yellow: "#d6bf5a",
|
|
2834
|
+
// brass gold
|
|
2835
|
+
green: "#4f8a6b",
|
|
2836
|
+
// sea-glass green
|
|
2837
|
+
blue: "#1f4e6b",
|
|
2838
|
+
// deep-sea navy
|
|
2839
|
+
purple: "#6a5a8c",
|
|
2840
|
+
// twilight harbor
|
|
2841
|
+
teal: "#3d8c8c",
|
|
2842
|
+
// sea-glass teal
|
|
2843
|
+
cyan: "#4f9bb5",
|
|
2844
|
+
// shallow water
|
|
2845
|
+
gray: "#8a8d86",
|
|
2846
|
+
// driftwood gray
|
|
2847
|
+
black: "#18313f",
|
|
2848
|
+
// navy ink
|
|
2849
|
+
white: "#e0e4e3"
|
|
2850
|
+
// deck panel
|
|
2851
|
+
}
|
|
2852
|
+
},
|
|
2853
|
+
dark: {
|
|
2854
|
+
bg: "#0f2230",
|
|
2855
|
+
// night-harbor deep sea
|
|
2856
|
+
surface: "#16303f",
|
|
2857
|
+
// raised hull
|
|
2858
|
+
overlay: "#1d3a4a",
|
|
2859
|
+
// popovers, dropdowns
|
|
2860
|
+
border: "#2c4856",
|
|
2861
|
+
// rigging line
|
|
2862
|
+
text: "#e6ebe8",
|
|
2863
|
+
// weathered white
|
|
2864
|
+
textMuted: "#9aaab0",
|
|
2865
|
+
// faded label
|
|
2866
|
+
textOnFillLight: "#f3f5f3",
|
|
2867
|
+
// weathered white
|
|
2868
|
+
textOnFillDark: "#0f2230",
|
|
2869
|
+
// deep sea
|
|
2870
|
+
primary: "#4f9bc4",
|
|
2871
|
+
// lifted sea blue
|
|
2872
|
+
secondary: "#c9a46a",
|
|
2873
|
+
// rope tan, lifted
|
|
2874
|
+
accent: "#d9b25a",
|
|
2875
|
+
// brass, lifted
|
|
2876
|
+
destructive: "#e06a5e",
|
|
2877
|
+
// signal red, lifted
|
|
2878
|
+
colors: {
|
|
2879
|
+
red: "#e06a5e",
|
|
2880
|
+
// signal-flag red
|
|
2881
|
+
orange: "#df9a52",
|
|
2882
|
+
// amber
|
|
2883
|
+
yellow: "#e0c662",
|
|
2884
|
+
// brass gold
|
|
2885
|
+
green: "#6fb58c",
|
|
2886
|
+
// sea-glass green
|
|
2887
|
+
blue: "#4f9bc4",
|
|
2888
|
+
// sea blue
|
|
2889
|
+
purple: "#9486bf",
|
|
2890
|
+
// twilight harbor
|
|
2891
|
+
teal: "#5cb0ac",
|
|
2892
|
+
// sea-glass teal
|
|
2893
|
+
cyan: "#62b4cf",
|
|
2894
|
+
// shallow water
|
|
2895
|
+
gray: "#9aa39c",
|
|
2896
|
+
// driftwood gray
|
|
2897
|
+
black: "#16303f",
|
|
2898
|
+
// raised hull
|
|
2899
|
+
white: "#e6ebe8"
|
|
2900
|
+
// weathered white
|
|
2901
|
+
}
|
|
2902
|
+
}
|
|
2903
|
+
};
|
|
2904
|
+
registerPalette(tidewaterPalette);
|
|
2905
|
+
}
|
|
2906
|
+
});
|
|
2907
|
+
|
|
2488
2908
|
// src/palettes/tokyo-night.ts
|
|
2489
2909
|
var tokyoNightPalette;
|
|
2490
2910
|
var init_tokyo_night = __esm({
|
|
@@ -2760,7 +3180,8 @@ var init_monokai = __esm({
|
|
|
2760
3180
|
// src/palettes/index.ts
|
|
2761
3181
|
var palettes_exports = {};
|
|
2762
3182
|
__export(palettes_exports, {
|
|
2763
|
-
|
|
3183
|
+
atlasPalette: () => atlasPalette,
|
|
3184
|
+
blueprintPalette: () => blueprintPalette,
|
|
2764
3185
|
catppuccinPalette: () => catppuccinPalette,
|
|
2765
3186
|
contrastText: () => contrastText,
|
|
2766
3187
|
draculaPalette: () => draculaPalette,
|
|
@@ -2781,7 +3202,9 @@ __export(palettes_exports, {
|
|
|
2781
3202
|
rosePinePalette: () => rosePinePalette,
|
|
2782
3203
|
shade: () => shade,
|
|
2783
3204
|
shapeFill: () => shapeFill,
|
|
3205
|
+
slatePalette: () => slatePalette,
|
|
2784
3206
|
solarizedPalette: () => solarizedPalette,
|
|
3207
|
+
tidewaterPalette: () => tidewaterPalette,
|
|
2785
3208
|
tint: () => tint,
|
|
2786
3209
|
tokyoNightPalette: () => tokyoNightPalette
|
|
2787
3210
|
});
|
|
@@ -2791,17 +3214,21 @@ var init_palettes = __esm({
|
|
|
2791
3214
|
"use strict";
|
|
2792
3215
|
init_registry();
|
|
2793
3216
|
init_color_utils();
|
|
2794
|
-
|
|
3217
|
+
init_atlas();
|
|
3218
|
+
init_blueprint();
|
|
2795
3219
|
init_catppuccin();
|
|
2796
3220
|
init_gruvbox();
|
|
2797
3221
|
init_nord();
|
|
2798
3222
|
init_one_dark();
|
|
2799
3223
|
init_rose_pine();
|
|
3224
|
+
init_slate();
|
|
2800
3225
|
init_solarized();
|
|
3226
|
+
init_tidewater();
|
|
2801
3227
|
init_tokyo_night();
|
|
2802
3228
|
init_dracula();
|
|
2803
3229
|
init_monokai();
|
|
2804
|
-
|
|
3230
|
+
init_atlas();
|
|
3231
|
+
init_blueprint();
|
|
2805
3232
|
init_catppuccin();
|
|
2806
3233
|
init_dracula();
|
|
2807
3234
|
init_gruvbox();
|
|
@@ -2809,9 +3236,15 @@ var init_palettes = __esm({
|
|
|
2809
3236
|
init_nord();
|
|
2810
3237
|
init_one_dark();
|
|
2811
3238
|
init_rose_pine();
|
|
3239
|
+
init_slate();
|
|
2812
3240
|
init_solarized();
|
|
3241
|
+
init_tidewater();
|
|
2813
3242
|
init_tokyo_night();
|
|
2814
3243
|
palettes = {
|
|
3244
|
+
atlas: atlasPalette,
|
|
3245
|
+
blueprint: blueprintPalette,
|
|
3246
|
+
slate: slatePalette,
|
|
3247
|
+
tidewater: tidewaterPalette,
|
|
2815
3248
|
nord: nordPalette,
|
|
2816
3249
|
catppuccin: catppuccinPalette,
|
|
2817
3250
|
solarized: solarizedPalette,
|
|
@@ -2820,8 +3253,7 @@ var init_palettes = __esm({
|
|
|
2820
3253
|
oneDark: oneDarkPalette,
|
|
2821
3254
|
rosePine: rosePinePalette,
|
|
2822
3255
|
dracula: draculaPalette,
|
|
2823
|
-
monokai: monokaiPalette
|
|
2824
|
-
bold: boldPalette
|
|
3256
|
+
monokai: monokaiPalette
|
|
2825
3257
|
};
|
|
2826
3258
|
}
|
|
2827
3259
|
});
|
|
@@ -3331,6 +3763,9 @@ function controlsGroupCapsuleWidth(toggles) {
|
|
|
3331
3763
|
}
|
|
3332
3764
|
return w;
|
|
3333
3765
|
}
|
|
3766
|
+
function isAppHostedControls(config, isExport) {
|
|
3767
|
+
return !isExport && config.controlsHost === "app" && !!config.controlsGroup && config.controlsGroup.toggles.length > 0;
|
|
3768
|
+
}
|
|
3334
3769
|
function buildControlsGroupLayout(config, state) {
|
|
3335
3770
|
const cg = config.controlsGroup;
|
|
3336
3771
|
if (!cg || cg.toggles.length === 0) return void 0;
|
|
@@ -3384,6 +3819,7 @@ function buildControlsGroupLayout(config, state) {
|
|
|
3384
3819
|
function computeLegendLayout(config, state, containerWidth) {
|
|
3385
3820
|
const { groups, controls: configControls, mode } = config;
|
|
3386
3821
|
const isExport = mode === "export";
|
|
3822
|
+
const gated = isAppHostedControls(config, isExport);
|
|
3387
3823
|
const activeGroupName = state.activeGroup?.toLowerCase() ?? null;
|
|
3388
3824
|
if (isExport && !activeGroupName) {
|
|
3389
3825
|
return {
|
|
@@ -3394,7 +3830,7 @@ function computeLegendLayout(config, state, containerWidth) {
|
|
|
3394
3830
|
pills: []
|
|
3395
3831
|
};
|
|
3396
3832
|
}
|
|
3397
|
-
const controlsGroupLayout = isExport ? void 0 : buildControlsGroupLayout(config, state);
|
|
3833
|
+
const controlsGroupLayout = isExport || gated ? void 0 : buildControlsGroupLayout(config, state);
|
|
3398
3834
|
const visibleGroups = config.showEmptyGroups ? groups : groups.filter((g) => g.entries.length > 0 || !!g.gradient);
|
|
3399
3835
|
if (visibleGroups.length === 0 && (!configControls || configControls.length === 0) && !controlsGroupLayout) {
|
|
3400
3836
|
return {
|
|
@@ -8296,8 +8732,8 @@ function computeScatterLabelGraphics(points, chartBounds, fontSize, symbolSize,
|
|
|
8296
8732
|
const pt = points[i];
|
|
8297
8733
|
const ptSize = pt.size ?? symbolSize;
|
|
8298
8734
|
const minGap = ptSize / 2 + 4;
|
|
8299
|
-
const
|
|
8300
|
-
const labelX = pt.px -
|
|
8735
|
+
const labelWidth2 = pt.name.length * fontSize * 0.6 + 8;
|
|
8736
|
+
const labelX = pt.px - labelWidth2 / 2;
|
|
8301
8737
|
let bestLabelY = 0;
|
|
8302
8738
|
let bestOffset = Infinity;
|
|
8303
8739
|
let placed = false;
|
|
@@ -8309,7 +8745,7 @@ function computeScatterLabelGraphics(points, chartBounds, fontSize, symbolSize,
|
|
|
8309
8745
|
const candidate = {
|
|
8310
8746
|
x: labelX,
|
|
8311
8747
|
y: labelY,
|
|
8312
|
-
w:
|
|
8748
|
+
w: labelWidth2,
|
|
8313
8749
|
h: labelHeight
|
|
8314
8750
|
};
|
|
8315
8751
|
let collision = false;
|
|
@@ -8351,7 +8787,7 @@ function computeScatterLabelGraphics(points, chartBounds, fontSize, symbolSize,
|
|
|
8351
8787
|
const labelRect = {
|
|
8352
8788
|
x: labelX,
|
|
8353
8789
|
y: bestLabelY,
|
|
8354
|
-
w:
|
|
8790
|
+
w: labelWidth2,
|
|
8355
8791
|
h: labelHeight
|
|
8356
8792
|
};
|
|
8357
8793
|
placedLabels.push(labelRect);
|
|
@@ -8387,7 +8823,7 @@ function computeScatterLabelGraphics(points, chartBounds, fontSize, symbolSize,
|
|
|
8387
8823
|
shape: {
|
|
8388
8824
|
x: labelX - bgPad,
|
|
8389
8825
|
y: bestLabelY - bgPad,
|
|
8390
|
-
width:
|
|
8826
|
+
width: labelWidth2 + bgPad * 2,
|
|
8391
8827
|
height: labelHeight + bgPad * 2
|
|
8392
8828
|
},
|
|
8393
8829
|
style: { fill: bg },
|
|
@@ -15823,10 +16259,6 @@ function parseMap(content) {
|
|
|
15823
16259
|
handleTag(trimmed, lineNumber);
|
|
15824
16260
|
continue;
|
|
15825
16261
|
}
|
|
15826
|
-
if ((firstWord === "muted" || firstWord === "natural") && trimmed === firstWord) {
|
|
15827
|
-
handleDirective(firstWord, "", lineNumber);
|
|
15828
|
-
continue;
|
|
15829
|
-
}
|
|
15830
16262
|
if (DIRECTIVE_SET.has(firstWord) && !trimmed.slice(firstWord.length).trimStart().startsWith(":")) {
|
|
15831
16263
|
handleDirective(
|
|
15832
16264
|
firstWord,
|
|
@@ -15873,24 +16305,6 @@ function parseMap(content) {
|
|
|
15873
16305
|
pushWarning(line12, `Duplicate directive "${key}" \u2014 last value wins.`);
|
|
15874
16306
|
};
|
|
15875
16307
|
switch (key) {
|
|
15876
|
-
case "region":
|
|
15877
|
-
dup(d.region);
|
|
15878
|
-
d.region = value;
|
|
15879
|
-
break;
|
|
15880
|
-
case "projection":
|
|
15881
|
-
dup(d.projection);
|
|
15882
|
-
if (value && ![
|
|
15883
|
-
"equirectangular",
|
|
15884
|
-
"natural-earth",
|
|
15885
|
-
"albers-usa",
|
|
15886
|
-
"mercator"
|
|
15887
|
-
].includes(value))
|
|
15888
|
-
pushWarning(
|
|
15889
|
-
line12,
|
|
15890
|
-
`Unknown projection "${value}" (expected equirectangular | natural-earth | albers-usa | mercator).`
|
|
15891
|
-
);
|
|
15892
|
-
d.projection = value;
|
|
15893
|
-
break;
|
|
15894
16308
|
case "region-metric": {
|
|
15895
16309
|
dup(d.regionMetric);
|
|
15896
16310
|
const { label: rmLabel, colorName: rmColor } = peelTrailingColorName(value);
|
|
@@ -15906,91 +16320,43 @@ function parseMap(content) {
|
|
|
15906
16320
|
dup(d.flowMetric);
|
|
15907
16321
|
d.flowMetric = value;
|
|
15908
16322
|
break;
|
|
15909
|
-
case "
|
|
15910
|
-
dup(d.
|
|
15911
|
-
|
|
15912
|
-
const s = parseScale(value, line12);
|
|
15913
|
-
if (s) d.scale = s;
|
|
15914
|
-
}
|
|
15915
|
-
break;
|
|
15916
|
-
case "region-labels":
|
|
15917
|
-
dup(d.regionLabels);
|
|
15918
|
-
if (value && !["full", "abbrev", "off"].includes(value))
|
|
15919
|
-
pushWarning(
|
|
15920
|
-
line12,
|
|
15921
|
-
`Unknown region-labels "${value}" (expected full | abbrev | off).`
|
|
15922
|
-
);
|
|
15923
|
-
d.regionLabels = value;
|
|
15924
|
-
break;
|
|
15925
|
-
case "poi-labels":
|
|
15926
|
-
dup(d.poiLabels);
|
|
15927
|
-
if (value && !["off", "auto", "all"].includes(value))
|
|
15928
|
-
pushWarning(
|
|
15929
|
-
line12,
|
|
15930
|
-
`Unknown poi-labels "${value}" (expected off | auto | all).`
|
|
15931
|
-
);
|
|
15932
|
-
d.poiLabels = value;
|
|
15933
|
-
break;
|
|
15934
|
-
case "default-country":
|
|
15935
|
-
dup(d.defaultCountry);
|
|
15936
|
-
d.defaultCountry = value;
|
|
15937
|
-
break;
|
|
15938
|
-
case "default-state":
|
|
15939
|
-
dup(d.defaultState);
|
|
15940
|
-
d.defaultState = value;
|
|
16323
|
+
case "locale":
|
|
16324
|
+
dup(d.locale);
|
|
16325
|
+
d.locale = value;
|
|
15941
16326
|
break;
|
|
15942
16327
|
case "active-tag":
|
|
15943
16328
|
dup(d.activeTag);
|
|
15944
16329
|
d.activeTag = value;
|
|
15945
16330
|
break;
|
|
16331
|
+
case "caption":
|
|
16332
|
+
dup(d.caption);
|
|
16333
|
+
d.caption = value;
|
|
16334
|
+
break;
|
|
16335
|
+
// ── Cosmetic `no-*` opt-outs: bare flags, idempotent (mirror `no-legend`,
|
|
16336
|
+
// no dup warning); each defaults the feature ON when absent. ──
|
|
15946
16337
|
case "no-legend":
|
|
15947
16338
|
d.noLegend = true;
|
|
15948
16339
|
break;
|
|
15949
|
-
case "no-
|
|
15950
|
-
d.
|
|
16340
|
+
case "no-coastline":
|
|
16341
|
+
d.noCoastline = true;
|
|
15951
16342
|
break;
|
|
15952
|
-
case "relief":
|
|
15953
|
-
d.
|
|
16343
|
+
case "no-relief":
|
|
16344
|
+
d.noRelief = true;
|
|
15954
16345
|
break;
|
|
15955
|
-
case "
|
|
15956
|
-
|
|
15957
|
-
if (d.basemapStyle !== void 0 && d.basemapStyle !== key)
|
|
15958
|
-
pushWarning(
|
|
15959
|
-
line12,
|
|
15960
|
-
`Conflicting basemap dress \u2014 "${d.basemapStyle}" then "${key}"; last wins.`
|
|
15961
|
-
);
|
|
15962
|
-
d.basemapStyle = key;
|
|
16346
|
+
case "no-context-labels":
|
|
16347
|
+
d.noContextLabels = true;
|
|
15963
16348
|
break;
|
|
15964
|
-
case "
|
|
15965
|
-
|
|
15966
|
-
d.subtitle = value;
|
|
16349
|
+
case "no-region-labels":
|
|
16350
|
+
d.noRegionLabels = true;
|
|
15967
16351
|
break;
|
|
15968
|
-
case "
|
|
15969
|
-
|
|
15970
|
-
|
|
16352
|
+
case "no-poi-labels":
|
|
16353
|
+
d.noPoiLabels = true;
|
|
16354
|
+
break;
|
|
16355
|
+
case "no-colorize":
|
|
16356
|
+
d.noColorize = true;
|
|
15971
16357
|
break;
|
|
15972
16358
|
}
|
|
15973
16359
|
}
|
|
15974
|
-
function parseScale(value, line12) {
|
|
15975
|
-
const toks = value.split(/\s+/).filter(Boolean);
|
|
15976
|
-
const min = Number(toks[0]);
|
|
15977
|
-
const max = Number(toks[1]);
|
|
15978
|
-
if (!Number.isFinite(min) || !Number.isFinite(max)) {
|
|
15979
|
-
pushError(line12, `scale requires numeric <min> <max> (got "${value}").`);
|
|
15980
|
-
return null;
|
|
15981
|
-
}
|
|
15982
|
-
const scale = { min, max };
|
|
15983
|
-
if (toks[2] === "center") {
|
|
15984
|
-
const c = Number(toks[3]);
|
|
15985
|
-
if (Number.isFinite(c)) scale.center = c;
|
|
15986
|
-
else
|
|
15987
|
-
pushError(
|
|
15988
|
-
line12,
|
|
15989
|
-
`scale center requires a number (got "${toks[3] ?? ""}").`
|
|
15990
|
-
);
|
|
15991
|
-
}
|
|
15992
|
-
return scale;
|
|
15993
|
-
}
|
|
15994
16360
|
function handleTag(trimmed, line12) {
|
|
15995
16361
|
const m = matchTagBlockHeading(trimmed);
|
|
15996
16362
|
if (!m) {
|
|
@@ -16190,13 +16556,15 @@ function parseMap(content) {
|
|
|
16190
16556
|
pushError(line12, `Edge has an empty endpoint: "${trimmed}".`);
|
|
16191
16557
|
continue;
|
|
16192
16558
|
}
|
|
16193
|
-
const
|
|
16559
|
+
const isLast = k === links.length - 1;
|
|
16560
|
+
const meta = isLast ? lastSplit.meta : {};
|
|
16561
|
+
const style = links[k].style === "arc" ? "arc" : "straight";
|
|
16194
16562
|
edges.push({
|
|
16195
16563
|
from,
|
|
16196
16564
|
to,
|
|
16197
16565
|
...links[k].label !== void 0 && { label: links[k].label },
|
|
16198
16566
|
directed: links[k].directed,
|
|
16199
|
-
style
|
|
16567
|
+
style,
|
|
16200
16568
|
meta,
|
|
16201
16569
|
lineNumber: line12
|
|
16202
16570
|
});
|
|
@@ -16282,22 +16650,19 @@ var init_parser12 = __esm({
|
|
|
16282
16650
|
LEG_ARROW_RE = /^(-[^>]*?->|->|~[^>]*?~>|~>|--)\s+(.+)$/;
|
|
16283
16651
|
AT_RE = /(^|[\s,])at\s*:/i;
|
|
16284
16652
|
DIRECTIVE_SET = /* @__PURE__ */ new Set([
|
|
16285
|
-
"region",
|
|
16286
|
-
"projection",
|
|
16287
16653
|
"region-metric",
|
|
16288
16654
|
"poi-metric",
|
|
16289
16655
|
"flow-metric",
|
|
16290
|
-
"
|
|
16291
|
-
"region-labels",
|
|
16292
|
-
"poi-labels",
|
|
16293
|
-
"default-country",
|
|
16294
|
-
"default-state",
|
|
16656
|
+
"locale",
|
|
16295
16657
|
"active-tag",
|
|
16658
|
+
"caption",
|
|
16296
16659
|
"no-legend",
|
|
16297
|
-
"no-
|
|
16298
|
-
"relief",
|
|
16299
|
-
"
|
|
16300
|
-
"
|
|
16660
|
+
"no-coastline",
|
|
16661
|
+
"no-relief",
|
|
16662
|
+
"no-context-labels",
|
|
16663
|
+
"no-region-labels",
|
|
16664
|
+
"no-poi-labels",
|
|
16665
|
+
"no-colorize"
|
|
16301
16666
|
]);
|
|
16302
16667
|
}
|
|
16303
16668
|
});
|
|
@@ -24219,8 +24584,8 @@ function renderKanban(container, parsed, palette, isDark, options) {
|
|
|
24219
24584
|
let metaY = separatorY + sCardSeparatorGap + sCardMetaFontSize;
|
|
24220
24585
|
for (const meta of tagMeta) {
|
|
24221
24586
|
cg.append("text").attr("x", cx + sCardPaddingX).attr("y", metaY).attr("font-size", sCardMetaFontSize).attr("fill", onCardText).text(`${meta.label}: `);
|
|
24222
|
-
const
|
|
24223
|
-
cg.append("text").attr("x", cx + sCardPaddingX +
|
|
24587
|
+
const labelWidth2 = (meta.label.length + 2) * sCardMetaFontSize * 0.6;
|
|
24588
|
+
cg.append("text").attr("x", cx + sCardPaddingX + labelWidth2).attr("y", metaY).attr("font-size", sCardMetaFontSize).attr("fill", onCardText).text(meta.value);
|
|
24224
24589
|
metaY += sCardMetaLineHeight;
|
|
24225
24590
|
}
|
|
24226
24591
|
for (const detail of card.details) {
|
|
@@ -24564,8 +24929,8 @@ function renderSwimlaneCard(parent, cardLayout, tagGroups, activeTagGroup, palet
|
|
|
24564
24929
|
let metaY = separatorY + sCardSeparatorGap + sCardMetaFontSize;
|
|
24565
24930
|
for (const meta of tagMeta) {
|
|
24566
24931
|
cg.append("text").attr("x", cx + sCardPaddingX).attr("y", metaY).attr("font-size", sCardMetaFontSize).attr("fill", palette.textMuted).text(`${meta.label}: `);
|
|
24567
|
-
const
|
|
24568
|
-
cg.append("text").attr("x", cx + sCardPaddingX +
|
|
24932
|
+
const labelWidth2 = (meta.label.length + 2) * sCardMetaFontSize * 0.6;
|
|
24933
|
+
cg.append("text").attr("x", cx + sCardPaddingX + labelWidth2).attr("y", metaY).attr("font-size", sCardMetaFontSize).attr("fill", onCardText).text(meta.value);
|
|
24569
24934
|
metaY += sCardMetaLineHeight;
|
|
24570
24935
|
}
|
|
24571
24936
|
for (const detail of card.details) {
|
|
@@ -25399,8 +25764,8 @@ function classifyEREntities(tables, relationships) {
|
|
|
25399
25764
|
}
|
|
25400
25765
|
}
|
|
25401
25766
|
const mmParticipants = /* @__PURE__ */ new Set();
|
|
25402
|
-
for (const [id,
|
|
25403
|
-
if (
|
|
25767
|
+
for (const [id, neighbors2] of tableStarNeighbors) {
|
|
25768
|
+
if (neighbors2.size >= 2) mmParticipants.add(id);
|
|
25404
25769
|
}
|
|
25405
25770
|
const indegreeValues = Object.values(indegreeMap);
|
|
25406
25771
|
const mean = indegreeValues.reduce((a, b) => a + b, 0) / indegreeValues.length;
|
|
@@ -26073,7 +26438,8 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26073
26438
|
controlsExpanded,
|
|
26074
26439
|
onToggleDescriptions,
|
|
26075
26440
|
onToggleControlsExpand,
|
|
26076
|
-
exportMode = false
|
|
26441
|
+
exportMode = false,
|
|
26442
|
+
controlsHost
|
|
26077
26443
|
} = options ?? {};
|
|
26078
26444
|
d3Selection6.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
26079
26445
|
const width = exportDims?.width ?? container.clientWidth;
|
|
@@ -26091,7 +26457,11 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26091
26457
|
const sGroupLabelZone = sctx.structural(GROUP_LABEL_ZONE);
|
|
26092
26458
|
const sTitleFontSize = sctx.text(TITLE_FONT_SIZE);
|
|
26093
26459
|
const sTitleY = sctx.structural(TITLE_Y);
|
|
26094
|
-
const
|
|
26460
|
+
const reserveHasDescriptions = parsed.nodes.some(
|
|
26461
|
+
(n) => n.description && n.description.length > 0
|
|
26462
|
+
);
|
|
26463
|
+
const willRenderLegend = parsed.tagGroups.length > 0 || reserveHasDescriptions && controlsHost !== "app";
|
|
26464
|
+
const sLegendHeight = willRenderLegend ? sctx.structural(
|
|
26095
26465
|
getMaxLegendReservedHeight(
|
|
26096
26466
|
{
|
|
26097
26467
|
groups: parsed.tagGroups,
|
|
@@ -26100,7 +26470,7 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26100
26470
|
},
|
|
26101
26471
|
width
|
|
26102
26472
|
)
|
|
26103
|
-
);
|
|
26473
|
+
) : 0;
|
|
26104
26474
|
const activeGroup = resolveActiveTagGroup(
|
|
26105
26475
|
parsed.tagGroups,
|
|
26106
26476
|
parsed.options["active-tag"],
|
|
@@ -26415,10 +26785,10 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26415
26785
|
const hasDescriptions = parsed.nodes.some(
|
|
26416
26786
|
(n) => n.description && n.description.length > 0
|
|
26417
26787
|
);
|
|
26418
|
-
const hasLegend = parsed.tagGroups.length > 0 || hasDescriptions;
|
|
26788
|
+
const hasLegend = parsed.tagGroups.length > 0 || hasDescriptions && controlsHost !== "app";
|
|
26419
26789
|
if (hasLegend) {
|
|
26420
26790
|
let controlsGroup;
|
|
26421
|
-
if (hasDescriptions && onToggleDescriptions) {
|
|
26791
|
+
if (hasDescriptions && (onToggleDescriptions || controlsHost === "app")) {
|
|
26422
26792
|
controlsGroup = {
|
|
26423
26793
|
toggles: [
|
|
26424
26794
|
{
|
|
@@ -26436,7 +26806,14 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26436
26806
|
groups: parsed.tagGroups,
|
|
26437
26807
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
26438
26808
|
mode: exportMode ? "export" : "preview",
|
|
26439
|
-
|
|
26809
|
+
// Keep inactive sibling tag groups visible as collapsed pills so the user
|
|
26810
|
+
// can click one to flip the active colouring dimension (preview only —
|
|
26811
|
+
// export shows just the active group). Without this, declaring a second
|
|
26812
|
+
// tag group (e.g. Team) leaves it invisible whenever another group is
|
|
26813
|
+
// active. The app's BoxesAndLinesPreview already wires pill clicks.
|
|
26814
|
+
showInactivePills: true,
|
|
26815
|
+
...controlsGroup !== void 0 && { controlsGroup },
|
|
26816
|
+
...controlsHost !== void 0 && { controlsHost }
|
|
26440
26817
|
};
|
|
26441
26818
|
const legendState = {
|
|
26442
26819
|
activeGroup,
|
|
@@ -27683,8 +28060,9 @@ function renderMindmap(container, parsed, layout, palette, isDark, onClickItem,
|
|
|
27683
28060
|
const containerHeight = exportDims?.height ?? (container.getBoundingClientRect().height || 600);
|
|
27684
28061
|
d3Selection7.select(container).selectAll("*").remove();
|
|
27685
28062
|
const svg = d3Selection7.select(container).append("svg").attr("width", containerWidth).attr("height", containerHeight).attr("viewBox", `0 0 ${containerWidth} ${containerHeight}`).attr("preserveAspectRatio", "xMidYMin meet").style("font-family", FONT_FAMILY);
|
|
28063
|
+
const appHosted = options?.controlsHost === "app";
|
|
27686
28064
|
const hasControls = !!options?.onToggleColorByDepth || !!options?.onToggleDescriptions;
|
|
27687
|
-
const hasLegend = parsed.tagGroups.length > 0 || hasControls;
|
|
28065
|
+
const hasLegend = parsed.tagGroups.length > 0 || hasControls && !appHosted;
|
|
27688
28066
|
const fixedLegend = !isExport && hasLegend;
|
|
27689
28067
|
const legendReserve = fixedLegend ? getMaxLegendReservedHeight(
|
|
27690
28068
|
{
|
|
@@ -27778,7 +28156,10 @@ function renderMindmap(container, parsed, layout, palette, isDark, onClickItem,
|
|
|
27778
28156
|
}),
|
|
27779
28157
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
27780
28158
|
mode: options?.exportMode ? "export" : "preview",
|
|
27781
|
-
...controlsToggles !== void 0 && { controlsGroup: controlsToggles }
|
|
28159
|
+
...controlsToggles !== void 0 && { controlsGroup: controlsToggles },
|
|
28160
|
+
...options?.controlsHost !== void 0 && {
|
|
28161
|
+
controlsHost: options.controlsHost
|
|
28162
|
+
}
|
|
27782
28163
|
};
|
|
27783
28164
|
const legendState = {
|
|
27784
28165
|
activeGroup: options?.colorByDepth ? null : activeTagGroup !== void 0 ? activeTagGroup : parsed.options["active-tag"] ?? null,
|
|
@@ -28221,8 +28602,8 @@ function computeFieldAlignX(children) {
|
|
|
28221
28602
|
for (const child of children) {
|
|
28222
28603
|
if (child.metadata["_labelField"] === "true" && child.children.length >= 2) {
|
|
28223
28604
|
const labelEl = child.children[0];
|
|
28224
|
-
const
|
|
28225
|
-
maxLabelWidth = Math.max(maxLabelWidth,
|
|
28605
|
+
const labelWidth2 = labelEl.label.length * CHAR_WIDTH5;
|
|
28606
|
+
maxLabelWidth = Math.max(maxLabelWidth, labelWidth2);
|
|
28226
28607
|
labelFieldCount++;
|
|
28227
28608
|
}
|
|
28228
28609
|
}
|
|
@@ -33187,7 +33568,7 @@ function hasRoles(node) {
|
|
|
33187
33568
|
function computeNodeWidth2(node, expanded, options) {
|
|
33188
33569
|
const badgeVal = node.computedConcurrentInvocations === 0 && node.computedInstances > 1 ? node.computedInstances : 0;
|
|
33189
33570
|
const badgeLen = badgeVal > 0 ? `${badgeVal}x`.length + 2 : 0;
|
|
33190
|
-
const
|
|
33571
|
+
const labelWidth2 = (node.label.length + badgeLen) * CHAR_WIDTH7 + PADDING_X3;
|
|
33191
33572
|
const allKeys = [];
|
|
33192
33573
|
if (node.computedRps > 0) allKeys.push("RPS");
|
|
33193
33574
|
if (expanded) {
|
|
@@ -33231,7 +33612,7 @@ function computeNodeWidth2(node, expanded, options) {
|
|
|
33231
33612
|
allKeys.push("overflow");
|
|
33232
33613
|
}
|
|
33233
33614
|
}
|
|
33234
|
-
if (allKeys.length === 0) return Math.max(MIN_NODE_WIDTH2,
|
|
33615
|
+
if (allKeys.length === 0) return Math.max(MIN_NODE_WIDTH2, labelWidth2);
|
|
33235
33616
|
const maxKeyLen = Math.max(...allKeys.map((k) => k.length));
|
|
33236
33617
|
let maxRowWidth = 0;
|
|
33237
33618
|
if (node.computedRps > 0) {
|
|
@@ -33319,7 +33700,7 @@ function computeNodeWidth2(node, expanded, options) {
|
|
|
33319
33700
|
truncated.length * META_CHAR_WIDTH3 + PADDING_X3
|
|
33320
33701
|
);
|
|
33321
33702
|
}
|
|
33322
|
-
return Math.max(MIN_NODE_WIDTH2,
|
|
33703
|
+
return Math.max(MIN_NODE_WIDTH2, labelWidth2, maxRowWidth + 20, descWidth);
|
|
33323
33704
|
}
|
|
33324
33705
|
function computeNodeHeight2(node, expanded, options) {
|
|
33325
33706
|
const propCount = countDisplayProps(node, expanded, options);
|
|
@@ -34869,8 +35250,9 @@ function computeInfraLegendGroups(nodes, tagGroups, palette, edges) {
|
|
|
34869
35250
|
}
|
|
34870
35251
|
return groups;
|
|
34871
35252
|
}
|
|
34872
|
-
function renderLegend3(rootSvg, legendGroups, totalWidth, legendY, palette, isDark, activeGroup, playback, exportMode = false) {
|
|
35253
|
+
function renderLegend3(rootSvg, legendGroups, totalWidth, legendY, palette, isDark, activeGroup, playback, exportMode = false, controlsHost) {
|
|
34873
35254
|
if (legendGroups.length === 0 && !playback) return;
|
|
35255
|
+
const appHostedPlayback = controlsHost === "app" && !!playback;
|
|
34874
35256
|
const legendG = rootSvg.append("g").attr("transform", `translate(0, ${legendY})`);
|
|
34875
35257
|
if (activeGroup) {
|
|
34876
35258
|
legendG.attr("data-legend-active", activeGroup.toLowerCase());
|
|
@@ -34879,14 +35261,29 @@ function renderLegend3(rootSvg, legendGroups, totalWidth, legendY, palette, isDa
|
|
|
34879
35261
|
name: g.name,
|
|
34880
35262
|
entries: g.entries.map((e) => ({ value: e.value, color: e.color }))
|
|
34881
35263
|
}));
|
|
34882
|
-
if (playback) {
|
|
35264
|
+
if (playback && !appHostedPlayback) {
|
|
34883
35265
|
allGroups.push({ name: "Playback", entries: [] });
|
|
34884
35266
|
}
|
|
34885
35267
|
const legendConfig = {
|
|
34886
35268
|
groups: allGroups,
|
|
34887
35269
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
34888
35270
|
mode: exportMode ? "export" : "preview",
|
|
34889
|
-
showEmptyGroups: true
|
|
35271
|
+
showEmptyGroups: true,
|
|
35272
|
+
...appHostedPlayback && {
|
|
35273
|
+
controlsHost: "app",
|
|
35274
|
+
controlsGroup: {
|
|
35275
|
+
toggles: [
|
|
35276
|
+
{
|
|
35277
|
+
id: "playback",
|
|
35278
|
+
type: "toggle",
|
|
35279
|
+
label: "Playback",
|
|
35280
|
+
active: true,
|
|
35281
|
+
onToggle: () => {
|
|
35282
|
+
}
|
|
35283
|
+
}
|
|
35284
|
+
]
|
|
35285
|
+
}
|
|
35286
|
+
}
|
|
34890
35287
|
};
|
|
34891
35288
|
const legendState = { activeGroup };
|
|
34892
35289
|
renderLegendD3(
|
|
@@ -34937,8 +35334,9 @@ function renderLegend3(rootSvg, legendGroups, totalWidth, legendY, palette, isDa
|
|
|
34937
35334
|
}
|
|
34938
35335
|
}
|
|
34939
35336
|
}
|
|
34940
|
-
function renderInfra(container, layout, palette, isDark, title, titleLineNumber, tagGroups, activeGroup, animate, playback, expandedNodeIds, exportMode, collapsedNodes) {
|
|
35337
|
+
function renderInfra(container, layout, palette, isDark, title, titleLineNumber, tagGroups, activeGroup, animate, playback, expandedNodeIds, exportMode, collapsedNodes, controlsHost) {
|
|
34941
35338
|
d3Selection11.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
35339
|
+
const appHostedPlayback = controlsHost === "app" && !!playback;
|
|
34942
35340
|
const ctx = ScaleContext.identity();
|
|
34943
35341
|
const sc = buildScaledConstants(ctx);
|
|
34944
35342
|
const legendGroups = computeInfraLegendGroups(
|
|
@@ -34947,7 +35345,7 @@ function renderInfra(container, layout, palette, isDark, title, titleLineNumber,
|
|
|
34947
35345
|
palette,
|
|
34948
35346
|
layout.edges
|
|
34949
35347
|
);
|
|
34950
|
-
const hasLegend = legendGroups.length > 0 || !!playback;
|
|
35348
|
+
const hasLegend = legendGroups.length > 0 || !!playback && !appHostedPlayback;
|
|
34951
35349
|
const fixedLegend = !exportMode && hasLegend;
|
|
34952
35350
|
const legendDynamicH = hasLegend ? getMaxLegendReservedHeight(
|
|
34953
35351
|
{
|
|
@@ -35091,7 +35489,8 @@ function renderInfra(container, layout, palette, isDark, title, titleLineNumber,
|
|
|
35091
35489
|
isDark,
|
|
35092
35490
|
activeGroup ?? null,
|
|
35093
35491
|
playback ?? void 0,
|
|
35094
|
-
exportMode
|
|
35492
|
+
exportMode,
|
|
35493
|
+
controlsHost
|
|
35095
35494
|
);
|
|
35096
35495
|
legendSvg.selectAll(".infra-legend-group").style("pointer-events", "auto");
|
|
35097
35496
|
} else {
|
|
@@ -35104,7 +35503,8 @@ function renderInfra(container, layout, palette, isDark, title, titleLineNumber,
|
|
|
35104
35503
|
isDark,
|
|
35105
35504
|
activeGroup ?? null,
|
|
35106
35505
|
playback ?? void 0,
|
|
35107
|
-
exportMode
|
|
35506
|
+
exportMode,
|
|
35507
|
+
controlsHost
|
|
35108
35508
|
);
|
|
35109
35509
|
}
|
|
35110
35510
|
}
|
|
@@ -42738,6 +43138,9 @@ function renderTechRadar(container, parsed, palette, isDark, onClickItem, export
|
|
|
42738
43138
|
onToggle: (active) => options.onToggleListing(active)
|
|
42739
43139
|
}
|
|
42740
43140
|
]
|
|
43141
|
+
},
|
|
43142
|
+
...options.controlsHost !== void 0 && {
|
|
43143
|
+
controlsHost: options.controlsHost
|
|
42741
43144
|
}
|
|
42742
43145
|
};
|
|
42743
43146
|
const legendState = {
|
|
@@ -44560,7 +44963,7 @@ function computeCycleLayout(parsed, options) {
|
|
|
44560
44963
|
const circleNodes = parsed.options["circle-nodes"] === "true";
|
|
44561
44964
|
const nodeDims = parsed.nodes.map((node) => {
|
|
44562
44965
|
const hasDesc = !hideDescriptions && node.description.length > 0;
|
|
44563
|
-
const
|
|
44966
|
+
const labelWidth2 = Math.max(
|
|
44564
44967
|
MIN_NODE_WIDTH4,
|
|
44565
44968
|
node.label.length * LABEL_CHAR_W + NODE_PAD_X * 2
|
|
44566
44969
|
);
|
|
@@ -44569,12 +44972,12 @@ function computeCycleLayout(parsed, options) {
|
|
|
44569
44972
|
}
|
|
44570
44973
|
if (!hasDesc) {
|
|
44571
44974
|
return {
|
|
44572
|
-
width: Math.min(MAX_NODE_WIDTH3,
|
|
44975
|
+
width: Math.min(MAX_NODE_WIDTH3, labelWidth2),
|
|
44573
44976
|
height: PLAIN_NODE_HEIGHT,
|
|
44574
44977
|
wrappedDesc: []
|
|
44575
44978
|
};
|
|
44576
44979
|
}
|
|
44577
|
-
return chooseDescribedRectDims(node.description,
|
|
44980
|
+
return chooseDescribedRectDims(node.description, labelWidth2);
|
|
44578
44981
|
});
|
|
44579
44982
|
if (circleNodes) {
|
|
44580
44983
|
const maxDiam = Math.max(...nodeDims.map((d) => d.width));
|
|
@@ -44770,10 +45173,10 @@ function computeCycleLayout(parsed, options) {
|
|
|
44770
45173
|
scale
|
|
44771
45174
|
};
|
|
44772
45175
|
}
|
|
44773
|
-
function chooseDescribedRectDims(description,
|
|
45176
|
+
function chooseDescribedRectDims(description, labelWidth2) {
|
|
44774
45177
|
const minW = Math.min(
|
|
44775
45178
|
MAX_NODE_WIDTH3,
|
|
44776
|
-
Math.max(MIN_NODE_WIDTH4,
|
|
45179
|
+
Math.max(MIN_NODE_WIDTH4, labelWidth2, DESC_MIN_WIDTH)
|
|
44777
45180
|
);
|
|
44778
45181
|
let best = null;
|
|
44779
45182
|
let bestScore = Infinity;
|
|
@@ -45202,7 +45605,8 @@ function renderCycle(container, parsed, palette, isDark, onClickItem, exportDims
|
|
|
45202
45605
|
const hideDescriptions = (renderOptions?.hideDescriptions ?? false) || parsed.options["no-descriptions"] === "true" || viewState?.hd === true;
|
|
45203
45606
|
const showDescriptions = !hideDescriptions;
|
|
45204
45607
|
const hasDescriptions = parsed.nodes.some((n) => n.description.length > 0) || parsed.edges.some((e) => e.description.length > 0);
|
|
45205
|
-
const
|
|
45608
|
+
const appHostedControls = renderOptions?.controlsHost === "app";
|
|
45609
|
+
const hasLegend = !appHostedControls && hasDescriptions && !!renderOptions?.onToggleDescriptions;
|
|
45206
45610
|
const showTitle = !!parsed.title && parsed.options["no-title"] !== "on";
|
|
45207
45611
|
const legendOffset = hasLegend ? sLegendHeight : 0;
|
|
45208
45612
|
const layoutHeight = height - (showTitle ? sTitleAreaHeight : 0) - legendOffset;
|
|
@@ -45239,7 +45643,10 @@ function renderCycle(container, parsed, palette, isDark, onClickItem, exportDims
|
|
|
45239
45643
|
groups: [],
|
|
45240
45644
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
45241
45645
|
mode: renderOptions?.exportMode ? "export" : "preview",
|
|
45242
|
-
controlsGroup
|
|
45646
|
+
controlsGroup,
|
|
45647
|
+
...renderOptions?.controlsHost !== void 0 && {
|
|
45648
|
+
controlsHost: renderOptions.controlsHost
|
|
45649
|
+
}
|
|
45243
45650
|
};
|
|
45244
45651
|
const legendState = {
|
|
45245
45652
|
activeGroup: null,
|
|
@@ -45493,7 +45900,7 @@ var init_renderer15 = __esm({
|
|
|
45493
45900
|
});
|
|
45494
45901
|
|
|
45495
45902
|
// src/map/geo.ts
|
|
45496
|
-
import { feature } from "topojson-client";
|
|
45903
|
+
import { feature, neighbors } from "topojson-client";
|
|
45497
45904
|
import { geoBounds, geoArea } from "d3-geo";
|
|
45498
45905
|
function geomObject(topo) {
|
|
45499
45906
|
const key = Object.keys(topo.objects)[0];
|
|
@@ -45511,6 +45918,107 @@ function featureIndex(topo) {
|
|
|
45511
45918
|
}
|
|
45512
45919
|
return idx;
|
|
45513
45920
|
}
|
|
45921
|
+
function buildAdjacency(topo) {
|
|
45922
|
+
const cached = adjacencyCache.get(topo);
|
|
45923
|
+
if (cached) return cached;
|
|
45924
|
+
const geometries = geomObject(topo).geometries;
|
|
45925
|
+
const nb = neighbors(geometries);
|
|
45926
|
+
const sets = /* @__PURE__ */ new Map();
|
|
45927
|
+
geometries.forEach((g, i) => {
|
|
45928
|
+
if (!g.type || g.type === "null") return;
|
|
45929
|
+
let set = sets.get(g.id);
|
|
45930
|
+
if (!set) {
|
|
45931
|
+
set = /* @__PURE__ */ new Set();
|
|
45932
|
+
sets.set(g.id, set);
|
|
45933
|
+
}
|
|
45934
|
+
for (const j of nb[i] ?? []) {
|
|
45935
|
+
const nid = geometries[j]?.id;
|
|
45936
|
+
if (nid && nid !== g.id) set.add(nid);
|
|
45937
|
+
}
|
|
45938
|
+
});
|
|
45939
|
+
const out = /* @__PURE__ */ new Map();
|
|
45940
|
+
for (const [iso, set] of sets) out.set(iso, [...set].sort());
|
|
45941
|
+
adjacencyCache.set(topo, out);
|
|
45942
|
+
return out;
|
|
45943
|
+
}
|
|
45944
|
+
function decodeFeatures(topo) {
|
|
45945
|
+
return geomObject(topo).geometries.map((g) => {
|
|
45946
|
+
const f = feature(topo, g);
|
|
45947
|
+
return {
|
|
45948
|
+
type: "Feature",
|
|
45949
|
+
id: g.id,
|
|
45950
|
+
properties: g.properties,
|
|
45951
|
+
geometry: f.geometry
|
|
45952
|
+
};
|
|
45953
|
+
});
|
|
45954
|
+
}
|
|
45955
|
+
function pointInRing(lon, lat, ring) {
|
|
45956
|
+
let inside = false;
|
|
45957
|
+
for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
|
|
45958
|
+
const xi = ring[i][0];
|
|
45959
|
+
const yi = ring[i][1];
|
|
45960
|
+
const xj = ring[j][0];
|
|
45961
|
+
const yj = ring[j][1];
|
|
45962
|
+
const intersect = yi > lat !== yj > lat && lon < (xj - xi) * (lat - yi) / (yj - yi) + xi;
|
|
45963
|
+
if (intersect) inside = !inside;
|
|
45964
|
+
}
|
|
45965
|
+
return inside;
|
|
45966
|
+
}
|
|
45967
|
+
function pointOnRingEdge(lon, lat, ring) {
|
|
45968
|
+
for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
|
|
45969
|
+
const xi = ring[i][0];
|
|
45970
|
+
const yi = ring[i][1];
|
|
45971
|
+
const xj = ring[j][0];
|
|
45972
|
+
const yj = ring[j][1];
|
|
45973
|
+
if (lon < Math.min(xi, xj) - EDGE_EPS || lon > Math.max(xi, xj) + EDGE_EPS)
|
|
45974
|
+
continue;
|
|
45975
|
+
if (lat < Math.min(yi, yj) - EDGE_EPS || lat > Math.max(yi, yj) + EDGE_EPS)
|
|
45976
|
+
continue;
|
|
45977
|
+
const cross = (xj - xi) * (lat - yi) - (yj - yi) * (lon - xi);
|
|
45978
|
+
if (Math.abs(cross) <= EDGE_EPS) return true;
|
|
45979
|
+
}
|
|
45980
|
+
return false;
|
|
45981
|
+
}
|
|
45982
|
+
function pointInGeometry(geometry, lon, lat) {
|
|
45983
|
+
const g = geometry;
|
|
45984
|
+
if (!g) return false;
|
|
45985
|
+
const polys = g.type === "Polygon" ? [g.coordinates] : g.type === "MultiPolygon" ? g.coordinates : [];
|
|
45986
|
+
for (const rings of polys) {
|
|
45987
|
+
if (!rings.length) continue;
|
|
45988
|
+
if (pointOnRingEdge(lon, lat, rings[0])) return true;
|
|
45989
|
+
if (!pointInRing(lon, lat, rings[0])) continue;
|
|
45990
|
+
let inHole = false;
|
|
45991
|
+
for (let h = 1; h < rings.length; h++) {
|
|
45992
|
+
if (pointInRing(lon, lat, rings[h]) && !pointOnRingEdge(lon, lat, rings[h])) {
|
|
45993
|
+
inHole = true;
|
|
45994
|
+
break;
|
|
45995
|
+
}
|
|
45996
|
+
}
|
|
45997
|
+
if (!inHole) return true;
|
|
45998
|
+
}
|
|
45999
|
+
return false;
|
|
46000
|
+
}
|
|
46001
|
+
function regionAt(lonLat, countries, states) {
|
|
46002
|
+
const lon = lonLat[0];
|
|
46003
|
+
const lat = lonLat[1];
|
|
46004
|
+
let country = null;
|
|
46005
|
+
for (const f of countries) {
|
|
46006
|
+
if (pointInGeometry(f.geometry, lon, lat)) {
|
|
46007
|
+
country = { iso: f.id, name: f.properties.name };
|
|
46008
|
+
break;
|
|
46009
|
+
}
|
|
46010
|
+
}
|
|
46011
|
+
let state = null;
|
|
46012
|
+
if (country?.iso === "US" && states) {
|
|
46013
|
+
for (const f of states) {
|
|
46014
|
+
if (pointInGeometry(f.geometry, lon, lat)) {
|
|
46015
|
+
state = { iso: f.id, name: f.properties.name };
|
|
46016
|
+
break;
|
|
46017
|
+
}
|
|
46018
|
+
}
|
|
46019
|
+
}
|
|
46020
|
+
return { country, state };
|
|
46021
|
+
}
|
|
45514
46022
|
function featureBbox(topo, geomId) {
|
|
45515
46023
|
const geom = geomObject(topo).geometries.find((g) => g.id === geomId);
|
|
45516
46024
|
if (!geom) return null;
|
|
@@ -45628,11 +46136,13 @@ function unionLongitudes(lons) {
|
|
|
45628
46136
|
}
|
|
45629
46137
|
return { west: pts[gapIdx], east: pts[gapIdx - 1] + 360 };
|
|
45630
46138
|
}
|
|
45631
|
-
var fold, DETACH_GAP_DEG, DETACH_AREA_FRAC;
|
|
46139
|
+
var fold, adjacencyCache, EDGE_EPS, DETACH_GAP_DEG, DETACH_AREA_FRAC;
|
|
45632
46140
|
var init_geo = __esm({
|
|
45633
46141
|
"src/map/geo.ts"() {
|
|
45634
46142
|
"use strict";
|
|
45635
46143
|
fold = (s) => s.normalize("NFD").replace(/\p{Diacritic}/gu, "").toLowerCase().trim();
|
|
46144
|
+
adjacencyCache = /* @__PURE__ */ new WeakMap();
|
|
46145
|
+
EDGE_EPS = 1e-9;
|
|
45636
46146
|
DETACH_GAP_DEG = 10;
|
|
45637
46147
|
DETACH_AREA_FRAC = 0.25;
|
|
45638
46148
|
}
|
|
@@ -45652,6 +46162,12 @@ function looksUS(lat, lon) {
|
|
|
45652
46162
|
if (lat < 15 || lat > 72) return false;
|
|
45653
46163
|
return lon >= -180 && lon <= -64 || lon >= 172;
|
|
45654
46164
|
}
|
|
46165
|
+
function looksNorthAmericaNeighbor(lat, lon) {
|
|
46166
|
+
return lat >= 14 && lat <= 72 && lon >= -141 && lon <= -52;
|
|
46167
|
+
}
|
|
46168
|
+
function isWholeSphere(bb) {
|
|
46169
|
+
return bb[0][0] <= -179 && bb[1][0] >= 179 && bb[0][1] <= -89 && bb[1][1] >= 89;
|
|
46170
|
+
}
|
|
45655
46171
|
function resolveMap(parsed, data) {
|
|
45656
46172
|
const diagnostics = [...parsed.diagnostics];
|
|
45657
46173
|
const err = (line12, message, code) => {
|
|
@@ -45662,9 +46178,6 @@ function resolveMap(parsed, data) {
|
|
|
45662
46178
|
};
|
|
45663
46179
|
const result = {
|
|
45664
46180
|
title: parsed.title,
|
|
45665
|
-
...parsed.directives.subtitle !== void 0 && {
|
|
45666
|
-
subtitle: parsed.directives.subtitle
|
|
45667
|
-
},
|
|
45668
46181
|
...parsed.directives.caption !== void 0 && {
|
|
45669
46182
|
caption: parsed.directives.caption
|
|
45670
46183
|
},
|
|
@@ -45674,7 +46187,7 @@ function resolveMap(parsed, data) {
|
|
|
45674
46187
|
// renderer's job (step 4) — the resolver only carries `tags` + `tagGroups`
|
|
45675
46188
|
// through; it never resolves a tag value to a palette color (#10).
|
|
45676
46189
|
directives: { ...parsed.directives },
|
|
45677
|
-
basemaps: { world: "
|
|
46190
|
+
basemaps: { world: "detail", subdivisions: [] },
|
|
45678
46191
|
regions: [],
|
|
45679
46192
|
pois: [],
|
|
45680
46193
|
edges: [],
|
|
@@ -45683,7 +46196,8 @@ function resolveMap(parsed, data) {
|
|
|
45683
46196
|
[-180, -85],
|
|
45684
46197
|
[180, 85]
|
|
45685
46198
|
],
|
|
45686
|
-
projection: "
|
|
46199
|
+
projection: "equirectangular",
|
|
46200
|
+
poiFrameContainers: [],
|
|
45687
46201
|
diagnostics,
|
|
45688
46202
|
error: parsed.error
|
|
45689
46203
|
};
|
|
@@ -45693,7 +46207,10 @@ function resolveMap(parsed, data) {
|
|
|
45693
46207
|
...[...countryIndex.values()].map((v) => v.name),
|
|
45694
46208
|
...[...usStateIndex.values()].map((v) => v.name)
|
|
45695
46209
|
];
|
|
45696
|
-
const
|
|
46210
|
+
const localeRaw = parsed.directives.locale?.toUpperCase();
|
|
46211
|
+
const localeCountry = localeRaw ? localeRaw.split("-")[0] : void 0;
|
|
46212
|
+
const localeSubdivision = localeRaw && /^[A-Z]{2}-/.test(localeRaw) ? localeRaw : void 0;
|
|
46213
|
+
const usScoped = localeCountry === "US" || parsed.regions.some((r) => {
|
|
45697
46214
|
const f = fold(r.name);
|
|
45698
46215
|
return usStateIndex.has(f) && !countryIndex.has(f);
|
|
45699
46216
|
}) || parsed.regions.some(
|
|
@@ -45844,7 +46361,7 @@ function resolveMap(parsed, data) {
|
|
|
45844
46361
|
if (!scope)
|
|
45845
46362
|
warn2(
|
|
45846
46363
|
line12,
|
|
45847
|
-
`"${name}" is ambiguous \u2014 resolved to the most-populous match.`,
|
|
46364
|
+
`"${name}" is ambiguous \u2014 resolved to the most-populous match. Set a default with \`locale <ISO>\` (e.g. \`locale US\` / \`locale US-GA\`) to steer it.`,
|
|
45848
46365
|
"W_MAP_AMBIGUOUS_NAME"
|
|
45849
46366
|
);
|
|
45850
46367
|
}
|
|
@@ -45857,17 +46374,21 @@ function resolveMap(parsed, data) {
|
|
|
45857
46374
|
return fold(pos.name);
|
|
45858
46375
|
};
|
|
45859
46376
|
const poiCountries = [];
|
|
45860
|
-
let
|
|
46377
|
+
let anyUsPoi = false;
|
|
46378
|
+
let anyNonNaPoi = false;
|
|
45861
46379
|
const noteCountry = (iso) => {
|
|
45862
46380
|
if (iso) {
|
|
45863
46381
|
poiCountries.push(iso);
|
|
45864
|
-
if (iso
|
|
46382
|
+
if (iso === "US") anyUsPoi = true;
|
|
46383
|
+
if (iso !== "US" && iso !== "CA" && iso !== "MX") anyNonNaPoi = true;
|
|
45865
46384
|
}
|
|
45866
46385
|
};
|
|
45867
46386
|
const deferred = [];
|
|
45868
46387
|
for (const p of parsed.pois) {
|
|
45869
46388
|
if (p.pos.kind === "coords") {
|
|
45870
|
-
if (
|
|
46389
|
+
if (looksUS(p.pos.lat, p.pos.lon)) anyUsPoi = true;
|
|
46390
|
+
else if (!looksNorthAmericaNeighbor(p.pos.lat, p.pos.lon))
|
|
46391
|
+
anyNonNaPoi = true;
|
|
45871
46392
|
addResolvedPoi(p.pos.lat, p.pos.lon, p);
|
|
45872
46393
|
continue;
|
|
45873
46394
|
}
|
|
@@ -45885,14 +46406,15 @@ function resolveMap(parsed, data) {
|
|
|
45885
46406
|
deferred.push(p);
|
|
45886
46407
|
}
|
|
45887
46408
|
}
|
|
45888
|
-
const inferredCountry =
|
|
46409
|
+
const inferredCountry = localeCountry ?? mostCommonCountry(regions, poiCountries) ?? void 0;
|
|
46410
|
+
const inferredScope = localeSubdivision ?? inferredCountry;
|
|
45889
46411
|
for (const p of deferred) {
|
|
45890
46412
|
if (p.pos.kind !== "name") continue;
|
|
45891
46413
|
const got = lookupName(
|
|
45892
46414
|
p.pos.name,
|
|
45893
46415
|
p.pos.scope,
|
|
45894
46416
|
p.lineNumber,
|
|
45895
|
-
|
|
46417
|
+
inferredScope,
|
|
45896
46418
|
true
|
|
45897
46419
|
);
|
|
45898
46420
|
if (got.kind === "ok") {
|
|
@@ -45962,7 +46484,8 @@ function resolveMap(parsed, data) {
|
|
|
45962
46484
|
const meta = sizeValue !== void 0 ? { value: sizeValue } : {};
|
|
45963
46485
|
if (pos.kind === "coords") {
|
|
45964
46486
|
const id = alias ? fold(alias) : `@${pos.lat},${pos.lon}`;
|
|
45965
|
-
if (
|
|
46487
|
+
if (looksUS(pos.lat, pos.lon)) anyUsPoi = true;
|
|
46488
|
+
else if (!looksNorthAmericaNeighbor(pos.lat, pos.lon)) anyNonNaPoi = true;
|
|
45966
46489
|
if (!registry.has(id)) {
|
|
45967
46490
|
registerPoi(
|
|
45968
46491
|
id,
|
|
@@ -45985,7 +46508,7 @@ function resolveMap(parsed, data) {
|
|
|
45985
46508
|
if (registry.has(f)) return f;
|
|
45986
46509
|
const aliased = declaredByName.get(f);
|
|
45987
46510
|
if (aliased) return aliased;
|
|
45988
|
-
const got = lookupName(pos.name, pos.scope, line12,
|
|
46511
|
+
const got = lookupName(pos.name, pos.scope, line12, inferredScope, true);
|
|
45989
46512
|
if (got.kind !== "ok") return null;
|
|
45990
46513
|
noteCountry(got.iso);
|
|
45991
46514
|
registerPoi(
|
|
@@ -46042,9 +46565,12 @@ function resolveMap(parsed, data) {
|
|
|
46042
46565
|
}
|
|
46043
46566
|
routes.push({ stopIds, legs, lineNumber: rt.lineNumber });
|
|
46044
46567
|
}
|
|
46568
|
+
const hasUsContent = usSubdivisionReferenced || anyUsPoi || localeCountry === "US";
|
|
46569
|
+
const usOriented = !anyNonNaPoi && !regions.some(
|
|
46570
|
+
(r) => r.layer === "country" && !["US", "CA", "MX"].includes(r.iso)
|
|
46571
|
+
) && hasUsContent;
|
|
46045
46572
|
const subdivisions = [];
|
|
46046
|
-
if (usSubdivisionReferenced ||
|
|
46047
|
-
subdivisions.push("us-states");
|
|
46573
|
+
if (usSubdivisionReferenced || usOriented) subdivisions.push("us-states");
|
|
46048
46574
|
const regionBoxes = [];
|
|
46049
46575
|
for (const ref of referencedRegionIds) {
|
|
46050
46576
|
const bb = featureBbox(data.usStates, ref.id);
|
|
@@ -46062,17 +46588,51 @@ function resolveMap(parsed, data) {
|
|
|
46062
46588
|
[-180, -85],
|
|
46063
46589
|
[180, 85]
|
|
46064
46590
|
];
|
|
46065
|
-
|
|
46591
|
+
const basePad = regions.length > 0 ? REGION_PAD_FRACTION : PAD_FRACTION;
|
|
46592
|
+
let extent2 = unioned ? pad(unioned, basePad) : DEFAULT_EXTENT;
|
|
46593
|
+
const isPoiOnly = pois.length > 0 && regions.length === 0;
|
|
46594
|
+
const containerRegionIds = [];
|
|
46595
|
+
if (isPoiOnly) {
|
|
46596
|
+
const countries = decodeFeatures(data.worldDetail);
|
|
46597
|
+
const states = decodeFeatures(data.usStates);
|
|
46598
|
+
const seen = /* @__PURE__ */ new Set();
|
|
46599
|
+
const containerBoxes = [];
|
|
46600
|
+
for (const p of pois) {
|
|
46601
|
+
const { country, state } = regionAt([p.lon, p.lat], countries, states);
|
|
46602
|
+
const id = state?.iso ?? country?.iso;
|
|
46603
|
+
if (!id || seen.has(id)) continue;
|
|
46604
|
+
seen.add(id);
|
|
46605
|
+
containerRegionIds.push(id);
|
|
46606
|
+
const bb = state ? featureBbox(data.usStates, id) : featureBboxPrimary(data.worldCoarse, id);
|
|
46607
|
+
if (bb && !isWholeSphere(bb)) containerBoxes.push(bb);
|
|
46608
|
+
}
|
|
46609
|
+
const containerUnion = unionExtent(containerBoxes, points);
|
|
46610
|
+
if (containerUnion) extent2 = pad(containerUnion, PAD_FRACTION);
|
|
46611
|
+
}
|
|
46612
|
+
if (isPoiOnly) {
|
|
46613
|
+
const cx = (extent2[0][0] + extent2[1][0]) / 2;
|
|
46614
|
+
const cy = (extent2[0][1] + extent2[1][1]) / 2;
|
|
46615
|
+
const lon = extent2[1][0] - extent2[0][0];
|
|
46616
|
+
const lat = extent2[1][1] - extent2[0][1];
|
|
46617
|
+
const longer = Math.max(lon, lat);
|
|
46618
|
+
if (longer > 0 && longer < POI_ZOOM_FLOOR_DEG) {
|
|
46619
|
+
const k = POI_ZOOM_FLOOR_DEG / longer;
|
|
46620
|
+
const halfLon = lon * k / 2;
|
|
46621
|
+
const halfLat = lat * k / 2;
|
|
46622
|
+
extent2 = [
|
|
46623
|
+
[cx - halfLon, cy - halfLat],
|
|
46624
|
+
[cx + halfLon, cy + halfLat]
|
|
46625
|
+
];
|
|
46626
|
+
}
|
|
46627
|
+
}
|
|
46066
46628
|
const lonSpan = extent2[1][0] - extent2[0][0];
|
|
46067
46629
|
const latSpan = extent2[1][1] - extent2[0][1];
|
|
46068
46630
|
const span = Math.max(lonSpan, latSpan);
|
|
46069
46631
|
const maxAbsLat = Math.max(Math.abs(extent2[0][1]), Math.abs(extent2[1][1]));
|
|
46070
|
-
const usDominant = (subdivisions.includes("us-states") || regions.some((r) => r.layer === "us-state")) && !regions.some((r) => r.layer === "country" && r.iso !== "US") && !anyNonUsPoi;
|
|
46071
46632
|
let projection;
|
|
46072
|
-
|
|
46073
|
-
|
|
46074
|
-
|
|
46075
|
-
} else if (usDominant) {
|
|
46633
|
+
if (isPoiOnly && usOriented && lonSpan < US_NATIONAL_LON_SPAN) {
|
|
46634
|
+
projection = "mercator";
|
|
46635
|
+
} else if (usOriented) {
|
|
46076
46636
|
projection = "albers-usa";
|
|
46077
46637
|
} else if (span > WORLD_SPAN || maxAbsLat > MERCATOR_MAX_LAT) {
|
|
46078
46638
|
projection = "equirectangular";
|
|
@@ -46090,11 +46650,20 @@ function resolveMap(parsed, data) {
|
|
|
46090
46650
|
result.edges = edges;
|
|
46091
46651
|
result.routes = routes;
|
|
46092
46652
|
result.basemaps = {
|
|
46093
|
-
|
|
46653
|
+
// Tier is intentionally pinned to detail (50m) at ALL scales. Diagrammo maps
|
|
46654
|
+
// are presentational (palette tints, relief hachures, POI hubs), not
|
|
46655
|
+
// survey-grade — recognizability > generalization: 110m coarse drops the
|
|
46656
|
+
// Italian boot to a stump at world scale. `WORLD_SPAN` lives on only for the
|
|
46657
|
+
// projection decision (the `usOriented`/`span > WORLD_SPAN` chain above); it
|
|
46658
|
+
// no longer gates basemap resolution.
|
|
46659
|
+
// `worldCoarse` is still loaded — it's the authoritative name/bbox index
|
|
46660
|
+
// (featureIndex, featureBboxPrimary), not dead code.
|
|
46661
|
+
world: "detail",
|
|
46094
46662
|
subdivisions
|
|
46095
46663
|
};
|
|
46096
46664
|
result.extent = extent2;
|
|
46097
46665
|
result.projection = projection;
|
|
46666
|
+
result.poiFrameContainers = containerRegionIds;
|
|
46098
46667
|
result.error = parsed.error ?? firstError(diagnostics);
|
|
46099
46668
|
return result;
|
|
46100
46669
|
}
|
|
@@ -46131,7 +46700,7 @@ function firstError(diags) {
|
|
|
46131
46700
|
const e = diags.find((d) => d.severity === "error");
|
|
46132
46701
|
return e ? formatDgmoError(e) : null;
|
|
46133
46702
|
}
|
|
46134
|
-
var WORLD_SPAN, MERCATOR_MAX_LAT, PAD_FRACTION, WORLD_LAT_SOUTH, WORLD_LAT_NORTH, REGION_ALIASES, US_STATE_POSTAL;
|
|
46703
|
+
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;
|
|
46135
46704
|
var init_resolver2 = __esm({
|
|
46136
46705
|
"src/map/resolver.ts"() {
|
|
46137
46706
|
"use strict";
|
|
@@ -46140,8 +46709,11 @@ var init_resolver2 = __esm({
|
|
|
46140
46709
|
WORLD_SPAN = 90;
|
|
46141
46710
|
MERCATOR_MAX_LAT = 80;
|
|
46142
46711
|
PAD_FRACTION = 0.05;
|
|
46712
|
+
REGION_PAD_FRACTION = 0.12;
|
|
46143
46713
|
WORLD_LAT_SOUTH = -58;
|
|
46144
46714
|
WORLD_LAT_NORTH = 78;
|
|
46715
|
+
POI_ZOOM_FLOOR_DEG = 7;
|
|
46716
|
+
US_NATIONAL_LON_SPAN = 48;
|
|
46145
46717
|
REGION_ALIASES = {
|
|
46146
46718
|
// Common everyday names → the Natural-Earth display name actually shipped.
|
|
46147
46719
|
"united states": "united states of america",
|
|
@@ -46219,10 +46791,277 @@ var init_resolver2 = __esm({
|
|
|
46219
46791
|
}
|
|
46220
46792
|
});
|
|
46221
46793
|
|
|
46794
|
+
// src/map/colorize.ts
|
|
46795
|
+
function assignColors(isos, adjacency) {
|
|
46796
|
+
const sorted = [...isos].sort();
|
|
46797
|
+
const byIso = /* @__PURE__ */ new Map();
|
|
46798
|
+
let maxIndex = -1;
|
|
46799
|
+
for (const iso of sorted) {
|
|
46800
|
+
const taken = /* @__PURE__ */ new Set();
|
|
46801
|
+
for (const n of adjacency.get(iso) ?? []) {
|
|
46802
|
+
const c = byIso.get(n);
|
|
46803
|
+
if (c !== void 0) taken.add(c);
|
|
46804
|
+
}
|
|
46805
|
+
let h = 0;
|
|
46806
|
+
while (taken.has(h)) h++;
|
|
46807
|
+
byIso.set(iso, h);
|
|
46808
|
+
if (h > maxIndex) maxIndex = h;
|
|
46809
|
+
}
|
|
46810
|
+
return { byIso, huesNeeded: maxIndex + 1 };
|
|
46811
|
+
}
|
|
46812
|
+
var init_colorize = __esm({
|
|
46813
|
+
"src/map/colorize.ts"() {
|
|
46814
|
+
"use strict";
|
|
46815
|
+
}
|
|
46816
|
+
});
|
|
46817
|
+
|
|
46818
|
+
// src/map/context-labels.ts
|
|
46819
|
+
function tierBand(maxSpanDeg) {
|
|
46820
|
+
if (maxSpanDeg >= 90) return "world";
|
|
46821
|
+
if (maxSpanDeg >= 20) return "continental";
|
|
46822
|
+
if (maxSpanDeg >= 5) return "regional";
|
|
46823
|
+
return "local";
|
|
46824
|
+
}
|
|
46825
|
+
function labelBudget(width, height, band) {
|
|
46826
|
+
const bandCap = {
|
|
46827
|
+
world: 6,
|
|
46828
|
+
continental: 5,
|
|
46829
|
+
regional: 4,
|
|
46830
|
+
local: 3
|
|
46831
|
+
};
|
|
46832
|
+
const area2 = Math.floor(Math.sqrt(Math.max(0, width * height)) / 150);
|
|
46833
|
+
return Math.max(0, Math.min(area2, bandCap[band]));
|
|
46834
|
+
}
|
|
46835
|
+
function waterEligible(tier, kind, band) {
|
|
46836
|
+
switch (band) {
|
|
46837
|
+
case "world":
|
|
46838
|
+
return tier <= 1 && (kind === "ocean" || kind === "sea");
|
|
46839
|
+
case "continental":
|
|
46840
|
+
return tier <= 2;
|
|
46841
|
+
case "regional":
|
|
46842
|
+
return tier <= 3;
|
|
46843
|
+
case "local":
|
|
46844
|
+
return tier <= 4;
|
|
46845
|
+
}
|
|
46846
|
+
}
|
|
46847
|
+
function insideViewport(p, width, height) {
|
|
46848
|
+
return !!p && Number.isFinite(p[0]) && Number.isFinite(p[1]) && p[0] >= 0 && p[0] <= width && p[1] >= 0 && p[1] <= height;
|
|
46849
|
+
}
|
|
46850
|
+
function labelWidth(text, letterSpacing) {
|
|
46851
|
+
const spacing = letterSpacing > 0 ? Math.max(0, text.length - 1) * letterSpacing : 0;
|
|
46852
|
+
return measureLegendText(text, FONT) + spacing + 2 * PADX;
|
|
46853
|
+
}
|
|
46854
|
+
function wrapLabel2(text, letterSpacing) {
|
|
46855
|
+
const words = text.split(/\s+/).filter(Boolean);
|
|
46856
|
+
if (words.length <= 1) return [text];
|
|
46857
|
+
const maxLines = words.length >= 4 ? 3 : 2;
|
|
46858
|
+
const n = words.length;
|
|
46859
|
+
let best = null;
|
|
46860
|
+
for (let mask = 0; mask < 1 << n - 1; mask++) {
|
|
46861
|
+
const lines = [];
|
|
46862
|
+
let cur = [words[0]];
|
|
46863
|
+
for (let i = 1; i < n; i++) {
|
|
46864
|
+
if (mask & 1 << i - 1) {
|
|
46865
|
+
lines.push(cur.join(" "));
|
|
46866
|
+
cur = [words[i]];
|
|
46867
|
+
} else cur.push(words[i]);
|
|
46868
|
+
}
|
|
46869
|
+
lines.push(cur.join(" "));
|
|
46870
|
+
if (lines.length > maxLines) continue;
|
|
46871
|
+
const cost = Math.round(
|
|
46872
|
+
Math.max(...lines.map((l) => labelWidth(l, letterSpacing)))
|
|
46873
|
+
);
|
|
46874
|
+
const head = labelWidth(lines[0], letterSpacing);
|
|
46875
|
+
if (!best || cost < best.cost || cost === best.cost && lines.length < best.lines.length || cost === best.cost && lines.length === best.lines.length && head > best.head)
|
|
46876
|
+
best = { lines, cost, head };
|
|
46877
|
+
}
|
|
46878
|
+
return best?.lines ?? [text];
|
|
46879
|
+
}
|
|
46880
|
+
function rectAround(cx, cy, lines, letterSpacing) {
|
|
46881
|
+
const w = Math.max(...lines.map((l) => labelWidth(l, letterSpacing)));
|
|
46882
|
+
const h = (lines.length - 1) * LINE_HEIGHT + FONT + 2 * PADY;
|
|
46883
|
+
return { x: cx - w / 2, y: cy - h / 2, w, h };
|
|
46884
|
+
}
|
|
46885
|
+
function rectFits(r, width, height) {
|
|
46886
|
+
return r.x >= 0 && r.y >= 0 && r.x + r.w <= width && r.y + r.h <= height;
|
|
46887
|
+
}
|
|
46888
|
+
function overlapsPadded(a, b, pad2) {
|
|
46889
|
+
return a.x - pad2 < b.x + b.w && a.x + a.w + pad2 > b.x && a.y - pad2 < b.y + b.h && a.y + a.h + pad2 > b.y;
|
|
46890
|
+
}
|
|
46891
|
+
function placeContextLabels(args) {
|
|
46892
|
+
const {
|
|
46893
|
+
projection,
|
|
46894
|
+
dLonSpan,
|
|
46895
|
+
dLatSpan,
|
|
46896
|
+
width,
|
|
46897
|
+
height,
|
|
46898
|
+
waterBodies,
|
|
46899
|
+
countries,
|
|
46900
|
+
palette,
|
|
46901
|
+
project,
|
|
46902
|
+
collides,
|
|
46903
|
+
overLand
|
|
46904
|
+
} = args;
|
|
46905
|
+
void projection;
|
|
46906
|
+
const band = tierBand(Math.max(dLonSpan, dLatSpan));
|
|
46907
|
+
const budget = labelBudget(width, height, band);
|
|
46908
|
+
if (budget <= 0) return [];
|
|
46909
|
+
const waterColor = mix(palette.colors.blue, palette.textMuted, 50);
|
|
46910
|
+
const countryColor = palette.textMuted;
|
|
46911
|
+
const haloColor = palette.bg;
|
|
46912
|
+
const candidates = [];
|
|
46913
|
+
const center = [width / 2, height / 2];
|
|
46914
|
+
for (const e of waterBodies?.entries ?? []) {
|
|
46915
|
+
const [lat, lon, name, tier, kind, alt] = e;
|
|
46916
|
+
if (!waterEligible(tier, kind, band)) continue;
|
|
46917
|
+
const wlines = wrapLabel2(name, WATER_LETTER_SPACING);
|
|
46918
|
+
const anchorsLngLat = [[lon, lat]];
|
|
46919
|
+
for (const a of alt ?? []) anchorsLngLat.push([a[1], a[0]]);
|
|
46920
|
+
let best = null;
|
|
46921
|
+
let bestD = Infinity;
|
|
46922
|
+
let nearestProj = null;
|
|
46923
|
+
let nearestProjD = Infinity;
|
|
46924
|
+
for (const [aLon, aLat] of anchorsLngLat) {
|
|
46925
|
+
const p = project(aLon, aLat);
|
|
46926
|
+
if (!p || !Number.isFinite(p[0]) || !Number.isFinite(p[1])) continue;
|
|
46927
|
+
const d = (p[0] - center[0]) ** 2 + (p[1] - center[1]) ** 2;
|
|
46928
|
+
if (d < nearestProjD) {
|
|
46929
|
+
nearestProjD = d;
|
|
46930
|
+
nearestProj = p;
|
|
46931
|
+
}
|
|
46932
|
+
if (!insideViewport(p, width, height)) continue;
|
|
46933
|
+
if (d < bestD) {
|
|
46934
|
+
bestD = d;
|
|
46935
|
+
best = p;
|
|
46936
|
+
}
|
|
46937
|
+
}
|
|
46938
|
+
if (!best && tier === 0 && nearestProj) {
|
|
46939
|
+
const overX = Math.max(0, -nearestProj[0], nearestProj[0] - width);
|
|
46940
|
+
const overY = Math.max(0, -nearestProj[1], nearestProj[1] - height);
|
|
46941
|
+
if (overX <= width * EDGE_CLAMP_OVERSHOOT && overY <= height * EDGE_CLAMP_OVERSHOOT) {
|
|
46942
|
+
const halfW = Math.max(...wlines.map((l) => labelWidth(l, WATER_LETTER_SPACING))) / 2;
|
|
46943
|
+
const halfH = ((wlines.length - 1) * LINE_HEIGHT + FONT + 2 * PADY) / 2;
|
|
46944
|
+
const m = EDGE_CLAMP_MARGIN;
|
|
46945
|
+
best = [
|
|
46946
|
+
Math.min(Math.max(nearestProj[0], halfW + m), width - halfW - m),
|
|
46947
|
+
Math.min(Math.max(nearestProj[1], halfH + m), height - halfH - m)
|
|
46948
|
+
];
|
|
46949
|
+
}
|
|
46950
|
+
}
|
|
46951
|
+
if (!best) continue;
|
|
46952
|
+
candidates.push({
|
|
46953
|
+
text: name,
|
|
46954
|
+
lines: wlines,
|
|
46955
|
+
cx: best[0],
|
|
46956
|
+
cy: best[1],
|
|
46957
|
+
italic: true,
|
|
46958
|
+
letterSpacing: WATER_LETTER_SPACING,
|
|
46959
|
+
color: waterColor,
|
|
46960
|
+
// Water before any country (×1000), then by tier, then kind, then name.
|
|
46961
|
+
sort: tier * 10 + KIND_ORDER[kind]
|
|
46962
|
+
});
|
|
46963
|
+
}
|
|
46964
|
+
const ranked = countries.map((c) => {
|
|
46965
|
+
const [x0, y0, x1, y1] = c.bbox;
|
|
46966
|
+
const w = x1 - x0;
|
|
46967
|
+
const h = y1 - y0;
|
|
46968
|
+
return { c, w, h, area: w * h };
|
|
46969
|
+
}).filter((r) => Number.isFinite(r.area) && r.area > 0).sort((a, b) => b.area - a.area);
|
|
46970
|
+
let ci = 0;
|
|
46971
|
+
for (const r of ranked) {
|
|
46972
|
+
const { c, w, h } = r;
|
|
46973
|
+
if (w > width * 0.66 || h > height * 0.66) continue;
|
|
46974
|
+
if (!insideViewport(c.anchor, width, height)) continue;
|
|
46975
|
+
const text = c.name;
|
|
46976
|
+
const tw = labelWidth(text, 0);
|
|
46977
|
+
if (tw > w || FONT + 2 * PADY > h) continue;
|
|
46978
|
+
candidates.push({
|
|
46979
|
+
text,
|
|
46980
|
+
lines: [text],
|
|
46981
|
+
cx: c.anchor[0],
|
|
46982
|
+
cy: c.anchor[1],
|
|
46983
|
+
italic: false,
|
|
46984
|
+
letterSpacing: 0,
|
|
46985
|
+
color: countryColor,
|
|
46986
|
+
// Always after every water body (+1e6); larger area = earlier.
|
|
46987
|
+
sort: 1e6 + ci++
|
|
46988
|
+
});
|
|
46989
|
+
}
|
|
46990
|
+
candidates.sort((a, b) => a.sort - b.sort);
|
|
46991
|
+
const placed = [];
|
|
46992
|
+
const placedRects = [];
|
|
46993
|
+
for (const cand of candidates) {
|
|
46994
|
+
if (placed.length >= budget) break;
|
|
46995
|
+
const rect = rectAround(cand.cx, cand.cy, cand.lines, cand.letterSpacing);
|
|
46996
|
+
if (!rectFits(rect, width, height)) continue;
|
|
46997
|
+
if (cand.italic && overLand) {
|
|
46998
|
+
const inset = 2;
|
|
46999
|
+
const top = cand.cy - (cand.lines.length - 1) / 2 * LINE_HEIGHT;
|
|
47000
|
+
const touchesLand = cand.lines.some((line12, li) => {
|
|
47001
|
+
const lw = labelWidth(line12, cand.letterSpacing);
|
|
47002
|
+
const x0 = cand.cx - lw / 2 + inset;
|
|
47003
|
+
const x1 = cand.cx + lw / 2 - inset;
|
|
47004
|
+
const xs = [x0, (x0 + cand.cx) / 2, cand.cx, (cand.cx + x1) / 2, x1];
|
|
47005
|
+
const base = top + li * LINE_HEIGHT;
|
|
47006
|
+
return [base, base - FONT * 0.4, base - FONT * 0.8].some(
|
|
47007
|
+
(y) => xs.some((x) => overLand(x, y))
|
|
47008
|
+
);
|
|
47009
|
+
});
|
|
47010
|
+
if (touchesLand) continue;
|
|
47011
|
+
}
|
|
47012
|
+
if (collides(rect)) continue;
|
|
47013
|
+
if (placedRects.some((r) => overlapsPadded(rect, r, CONTEXT_PAD))) continue;
|
|
47014
|
+
placedRects.push(rect);
|
|
47015
|
+
placed.push({
|
|
47016
|
+
x: cand.cx,
|
|
47017
|
+
y: cand.cy,
|
|
47018
|
+
text: cand.text,
|
|
47019
|
+
anchor: "middle",
|
|
47020
|
+
color: cand.color,
|
|
47021
|
+
// No halo: the bg-coloured outline reads as a ghost box behind the text
|
|
47022
|
+
// over the tinted water/land. Context labels are muted enough to sit
|
|
47023
|
+
// cleanly on the basemap without one.
|
|
47024
|
+
halo: false,
|
|
47025
|
+
haloColor,
|
|
47026
|
+
italic: cand.italic,
|
|
47027
|
+
letterSpacing: cand.letterSpacing,
|
|
47028
|
+
...cand.lines.length > 1 ? { lines: cand.lines } : {},
|
|
47029
|
+
lineNumber: 0
|
|
47030
|
+
});
|
|
47031
|
+
}
|
|
47032
|
+
return placed;
|
|
47033
|
+
}
|
|
47034
|
+
var FONT, LINE_HEIGHT, PADX, PADY, WATER_LETTER_SPACING, CONTEXT_PAD, EDGE_CLAMP_MARGIN, EDGE_CLAMP_OVERSHOOT, KIND_ORDER;
|
|
47035
|
+
var init_context_labels = __esm({
|
|
47036
|
+
"src/map/context-labels.ts"() {
|
|
47037
|
+
"use strict";
|
|
47038
|
+
init_color_utils();
|
|
47039
|
+
init_legend_constants();
|
|
47040
|
+
FONT = 11;
|
|
47041
|
+
LINE_HEIGHT = FONT + 2;
|
|
47042
|
+
PADX = 4;
|
|
47043
|
+
PADY = 3;
|
|
47044
|
+
WATER_LETTER_SPACING = 1.5;
|
|
47045
|
+
CONTEXT_PAD = 4;
|
|
47046
|
+
EDGE_CLAMP_MARGIN = 8;
|
|
47047
|
+
EDGE_CLAMP_OVERSHOOT = 0.35;
|
|
47048
|
+
KIND_ORDER = {
|
|
47049
|
+
ocean: 0,
|
|
47050
|
+
sea: 1,
|
|
47051
|
+
gulf: 2,
|
|
47052
|
+
bay: 3,
|
|
47053
|
+
strait: 4,
|
|
47054
|
+
channel: 5,
|
|
47055
|
+
sound: 6
|
|
47056
|
+
};
|
|
47057
|
+
}
|
|
47058
|
+
});
|
|
47059
|
+
|
|
46222
47060
|
// src/map/layout.ts
|
|
46223
47061
|
import {
|
|
46224
47062
|
geoPath,
|
|
46225
47063
|
geoNaturalEarth1,
|
|
47064
|
+
geoEqualEarth,
|
|
46226
47065
|
geoEquirectangular,
|
|
46227
47066
|
geoConicEqualArea,
|
|
46228
47067
|
geoMercator,
|
|
@@ -46234,12 +47073,34 @@ function geomObject2(topo) {
|
|
|
46234
47073
|
const key = Object.keys(topo.objects)[0];
|
|
46235
47074
|
return topo.objects[key];
|
|
46236
47075
|
}
|
|
47076
|
+
function mergeFeatures(a, b) {
|
|
47077
|
+
const polysOf = (f) => {
|
|
47078
|
+
const g = f.geometry;
|
|
47079
|
+
if (!g) return null;
|
|
47080
|
+
if (g.type === "Polygon") return [g.coordinates];
|
|
47081
|
+
if (g.type === "MultiPolygon") return g.coordinates;
|
|
47082
|
+
return null;
|
|
47083
|
+
};
|
|
47084
|
+
const pa = polysOf(a);
|
|
47085
|
+
const pb = polysOf(b);
|
|
47086
|
+
if (!pa || !pb) return a;
|
|
47087
|
+
return {
|
|
47088
|
+
...a,
|
|
47089
|
+
geometry: { type: "MultiPolygon", coordinates: [...pa, ...pb] }
|
|
47090
|
+
};
|
|
47091
|
+
}
|
|
46237
47092
|
function decodeLayer(topo) {
|
|
47093
|
+
const cached = decodeCache.get(topo);
|
|
47094
|
+
if (cached) return cached;
|
|
46238
47095
|
const out = /* @__PURE__ */ new Map();
|
|
46239
47096
|
for (const g of geomObject2(topo).geometries) {
|
|
46240
47097
|
const f = feature2(topo, g);
|
|
46241
|
-
|
|
47098
|
+
if (!f.geometry) continue;
|
|
47099
|
+
const tagged = { ...f, id: g.id };
|
|
47100
|
+
const existing = out.get(g.id);
|
|
47101
|
+
out.set(g.id, existing ? mergeFeatures(existing, tagged) : tagged);
|
|
46242
47102
|
}
|
|
47103
|
+
decodeCache.set(topo, out);
|
|
46243
47104
|
return out;
|
|
46244
47105
|
}
|
|
46245
47106
|
function projectionFor(family) {
|
|
@@ -46248,9 +47109,12 @@ function projectionFor(family) {
|
|
|
46248
47109
|
return usConusProjection();
|
|
46249
47110
|
case "mercator":
|
|
46250
47111
|
return geoMercator();
|
|
47112
|
+
case "equal-earth":
|
|
47113
|
+
return geoEqualEarth();
|
|
47114
|
+
case "equirectangular":
|
|
47115
|
+
return geoEquirectangular();
|
|
46251
47116
|
case "natural-earth":
|
|
46252
47117
|
return geoNaturalEarth1();
|
|
46253
|
-
case "equirectangular":
|
|
46254
47118
|
default:
|
|
46255
47119
|
return geoEquirectangular();
|
|
46256
47120
|
}
|
|
@@ -46269,13 +47133,11 @@ function mapNeutralLandColor(palette, isDark, _dataActive = false) {
|
|
|
46269
47133
|
isDark ? LAND_TINT_DARK : LAND_TINT_LIGHT
|
|
46270
47134
|
);
|
|
46271
47135
|
}
|
|
46272
|
-
function
|
|
46273
|
-
const { palette, isDark } = opts;
|
|
46274
|
-
const { width, height } = size;
|
|
47136
|
+
function buildMapProjection(resolved, data) {
|
|
46275
47137
|
const wantsUsStates = resolved.basemaps.subdivisions.includes("us-states");
|
|
46276
|
-
const usCrisp = resolved.projection === "albers-usa" && wantsUsStates && !!data.naLand;
|
|
47138
|
+
const usCrisp = (resolved.projection === "albers-usa" || resolved.projection === "mercator") && wantsUsStates && !!data.naLand;
|
|
46277
47139
|
const worldTopo = usCrisp ? data.worldDetail : resolved.basemaps.world === "detail" ? data.worldDetail : data.worldCoarse;
|
|
46278
|
-
const worldLayer = decodeLayer(worldTopo);
|
|
47140
|
+
const worldLayer = new Map(decodeLayer(worldTopo));
|
|
46279
47141
|
if (usCrisp && data.naLand) {
|
|
46280
47142
|
const [nbW, nbS, nbE, nbN] = [-140, 10, -52, 66];
|
|
46281
47143
|
const crisp = decodeLayer(data.naLand);
|
|
@@ -46284,16 +47146,109 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46284
47146
|
if (!base) continue;
|
|
46285
47147
|
const [[bw, bs], [be, bn]] = geoBounds2(base);
|
|
46286
47148
|
if (bw >= nbW && be <= nbE && bs >= nbS && bn <= nbN)
|
|
46287
|
-
worldLayer.set(iso, cf);
|
|
47149
|
+
worldLayer.set(iso, { ...cf, properties: base.properties });
|
|
46288
47150
|
}
|
|
46289
47151
|
}
|
|
46290
47152
|
const usLayer = wantsUsStates ? decodeLayer(data.usStates) : null;
|
|
47153
|
+
const extentOutline = () => {
|
|
47154
|
+
const [[w, s], [e, n]] = resolved.extent;
|
|
47155
|
+
const N = 16;
|
|
47156
|
+
const coords = [];
|
|
47157
|
+
for (let i = 0; i <= N; i++) {
|
|
47158
|
+
const t = i / N;
|
|
47159
|
+
const lon = w + (e - w) * t;
|
|
47160
|
+
const lat = s + (n - s) * t;
|
|
47161
|
+
coords.push([lon, s], [lon, n], [w, lat], [e, lat]);
|
|
47162
|
+
}
|
|
47163
|
+
return {
|
|
47164
|
+
type: "Feature",
|
|
47165
|
+
properties: {},
|
|
47166
|
+
geometry: { type: "MultiPoint", coordinates: coords }
|
|
47167
|
+
};
|
|
47168
|
+
};
|
|
47169
|
+
let fitFeatures;
|
|
47170
|
+
if (resolved.projection === "albers-usa" && usLayer) {
|
|
47171
|
+
fitFeatures = [...usLayer.entries()].filter(([iso]) => !US_NON_CONUS.has(iso)).map(([, f]) => f);
|
|
47172
|
+
const neighborPoints = resolved.pois.filter((p) => !inAlaska(p.lon, p.lat) && !inHawaii(p.lon, p.lat)).map((p) => [p.lon, p.lat]);
|
|
47173
|
+
if (neighborPoints.length > 0) {
|
|
47174
|
+
fitFeatures.push({
|
|
47175
|
+
type: "Feature",
|
|
47176
|
+
properties: {},
|
|
47177
|
+
geometry: { type: "MultiPoint", coordinates: neighborPoints }
|
|
47178
|
+
});
|
|
47179
|
+
}
|
|
47180
|
+
for (const r of resolved.regions) {
|
|
47181
|
+
if (r.layer === "country" && (r.iso === "CA" || r.iso === "MX")) {
|
|
47182
|
+
const cf = worldLayer.get(r.iso);
|
|
47183
|
+
if (cf) fitFeatures.push(cf);
|
|
47184
|
+
}
|
|
47185
|
+
}
|
|
47186
|
+
} else {
|
|
47187
|
+
fitFeatures = [extentOutline()];
|
|
47188
|
+
}
|
|
47189
|
+
const fitTarget = { type: "FeatureCollection", features: fitFeatures };
|
|
47190
|
+
const projection = projectionFor(resolved.projection);
|
|
47191
|
+
if (resolved.projection !== "albers-usa") {
|
|
47192
|
+
let centerLon = (resolved.extent[0][0] + resolved.extent[1][0]) / 2;
|
|
47193
|
+
if (centerLon > 180) centerLon -= 360;
|
|
47194
|
+
projection.rotate([-centerLon, 0]);
|
|
47195
|
+
}
|
|
47196
|
+
const fitGB = geoBounds2(fitTarget);
|
|
47197
|
+
const fitIsGlobal = fitGB[1][0] - fitGB[0][0] >= 270 || fitGB[1][1] - fitGB[0][1] >= 130;
|
|
47198
|
+
return {
|
|
47199
|
+
projection,
|
|
47200
|
+
fitTarget,
|
|
47201
|
+
fitIsGlobal,
|
|
47202
|
+
worldLayer,
|
|
47203
|
+
usLayer,
|
|
47204
|
+
usCrisp,
|
|
47205
|
+
wantsUsStates,
|
|
47206
|
+
worldTopo
|
|
47207
|
+
};
|
|
47208
|
+
}
|
|
47209
|
+
function parsePathRings(d) {
|
|
47210
|
+
const rings = [];
|
|
47211
|
+
let cur = [];
|
|
47212
|
+
const re = /([MLZ])([^MLZ]*)/g;
|
|
47213
|
+
let m;
|
|
47214
|
+
while (m = re.exec(d)) {
|
|
47215
|
+
if (m[1] === "Z") {
|
|
47216
|
+
if (cur.length) rings.push(cur);
|
|
47217
|
+
cur = [];
|
|
47218
|
+
continue;
|
|
47219
|
+
}
|
|
47220
|
+
if (m[1] === "M" && cur.length) {
|
|
47221
|
+
rings.push(cur);
|
|
47222
|
+
cur = [];
|
|
47223
|
+
}
|
|
47224
|
+
const nums = m[2].split(/[ ,]+/).map(Number);
|
|
47225
|
+
for (let i = 0; i + 1 < nums.length; i += 2) {
|
|
47226
|
+
const x = nums[i];
|
|
47227
|
+
const y = nums[i + 1];
|
|
47228
|
+
if (Number.isFinite(x) && Number.isFinite(y)) cur.push([x, y]);
|
|
47229
|
+
}
|
|
47230
|
+
}
|
|
47231
|
+
if (cur.length) rings.push(cur);
|
|
47232
|
+
return rings;
|
|
47233
|
+
}
|
|
47234
|
+
function layoutMap(resolved, data, size, opts) {
|
|
47235
|
+
const { palette, isDark } = opts;
|
|
47236
|
+
const { width, height } = size;
|
|
47237
|
+
const {
|
|
47238
|
+
projection,
|
|
47239
|
+
fitTarget,
|
|
47240
|
+
fitIsGlobal,
|
|
47241
|
+
worldLayer,
|
|
47242
|
+
usLayer,
|
|
47243
|
+
usCrisp,
|
|
47244
|
+
worldTopo
|
|
47245
|
+
} = buildMapProjection(resolved, data);
|
|
46291
47246
|
const usContext = usLayer !== null;
|
|
46292
47247
|
const regionStroke = isDark ? mix(palette.bg, palette.text, 78) : mix(palette.text, palette.bg, 78);
|
|
46293
47248
|
const values = resolved.regions.filter((r) => r.value !== void 0).map((r) => r.value);
|
|
46294
|
-
const
|
|
46295
|
-
const rampMin =
|
|
46296
|
-
const rampMax =
|
|
47249
|
+
const allNonNegative = values.length > 0 && values.every((v) => v >= 0);
|
|
47250
|
+
const rampMin = allNonNegative ? 0 : Math.min(...values);
|
|
47251
|
+
const rampMax = Math.max(...values);
|
|
46297
47252
|
const rampHue = resolveColor(resolved.directives.regionMetricColor ?? "", palette) ?? palette.colors.red;
|
|
46298
47253
|
const hasRamp = values.length > 0;
|
|
46299
47254
|
const VALUE_NAME = hasRamp ? resolved.directives.regionMetric?.trim() || "Value" : null;
|
|
@@ -46314,7 +47269,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46314
47269
|
activeGroup = VALUE_NAME ?? (resolved.tagGroups.length > 0 ? resolved.tagGroups[0].name : null);
|
|
46315
47270
|
}
|
|
46316
47271
|
const activeIsScore = VALUE_NAME !== null && activeGroup === VALUE_NAME;
|
|
46317
|
-
const mutedBasemap =
|
|
47272
|
+
const mutedBasemap = activeGroup !== null;
|
|
46318
47273
|
const neutralFill = mapNeutralLandColor(palette, isDark, mutedBasemap);
|
|
46319
47274
|
const water = mapBackgroundColor(palette, isDark, mutedBasemap);
|
|
46320
47275
|
const lakeStroke = mix(regionStroke, water, 45);
|
|
@@ -46323,6 +47278,39 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46323
47278
|
palette.bg,
|
|
46324
47279
|
mutedBasemap ? isDark ? MUTED_FOREIGN_DARK : MUTED_FOREIGN_LIGHT : isDark ? FOREIGN_TINT_DARK : FOREIGN_TINT_LIGHT
|
|
46325
47280
|
);
|
|
47281
|
+
const colorizeActive = resolved.directives.noColorize !== true && !hasRamp && resolved.tagGroups.length === 0;
|
|
47282
|
+
const colorByIso = /* @__PURE__ */ new Map();
|
|
47283
|
+
if (colorizeActive) {
|
|
47284
|
+
const adjacency = /* @__PURE__ */ new Map();
|
|
47285
|
+
const addEdges = (src) => {
|
|
47286
|
+
for (const [iso, ns] of src) {
|
|
47287
|
+
const cur = adjacency.get(iso);
|
|
47288
|
+
if (cur) cur.push(...ns);
|
|
47289
|
+
else adjacency.set(iso, [...ns]);
|
|
47290
|
+
}
|
|
47291
|
+
};
|
|
47292
|
+
addEdges(buildAdjacency(worldTopo));
|
|
47293
|
+
if (usLayer) {
|
|
47294
|
+
addEdges(buildAdjacency(data.usStates));
|
|
47295
|
+
for (const [country, states] of Object.entries(FOREIGN_BORDER)) {
|
|
47296
|
+
const cn = adjacency.get(country);
|
|
47297
|
+
if (!cn) continue;
|
|
47298
|
+
for (const st of states) {
|
|
47299
|
+
const sn = adjacency.get(st);
|
|
47300
|
+
if (!sn) continue;
|
|
47301
|
+
cn.push(st);
|
|
47302
|
+
sn.push(country);
|
|
47303
|
+
}
|
|
47304
|
+
}
|
|
47305
|
+
}
|
|
47306
|
+
const { byIso, huesNeeded } = assignColors(
|
|
47307
|
+
[...adjacency.keys()],
|
|
47308
|
+
adjacency
|
|
47309
|
+
);
|
|
47310
|
+
const tints = politicalTints(palette, huesNeeded, isDark);
|
|
47311
|
+
for (const [iso, idx] of byIso) colorByIso.set(iso, tints[idx]);
|
|
47312
|
+
}
|
|
47313
|
+
const colorizeStroke = (fill2) => mix(fill2, palette.text, 35);
|
|
46326
47314
|
const rampBase = isDark ? mix(palette.surface, palette.text, 28) : palette.bg;
|
|
46327
47315
|
const fillForValue = (s) => {
|
|
46328
47316
|
const t = rampMax > rampMin ? (s - rampMin) / (rampMax - rampMin) : 1;
|
|
@@ -46358,43 +47346,15 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46358
47346
|
if (activeIsScore) {
|
|
46359
47347
|
return r.value !== void 0 ? fillForValue(r.value) : neutralFill;
|
|
46360
47348
|
}
|
|
47349
|
+
if (colorizeActive) return (r.iso && colorByIso.get(r.iso)) ?? neutralFill;
|
|
46361
47350
|
return tagFill(r.tags, activeGroup) ?? neutralFill;
|
|
46362
47351
|
};
|
|
46363
47352
|
const regionById = new Map(resolved.regions.map((r) => [r.iso, r]));
|
|
46364
|
-
const
|
|
46365
|
-
const [[w, s], [e, n]] = resolved.extent;
|
|
46366
|
-
const N = 16;
|
|
46367
|
-
const coords = [];
|
|
46368
|
-
for (let i = 0; i <= N; i++) {
|
|
46369
|
-
const t = i / N;
|
|
46370
|
-
const lon = w + (e - w) * t;
|
|
46371
|
-
const lat = s + (n - s) * t;
|
|
46372
|
-
coords.push([lon, s], [lon, n], [w, lat], [e, lat]);
|
|
46373
|
-
}
|
|
46374
|
-
return {
|
|
46375
|
-
type: "Feature",
|
|
46376
|
-
properties: {},
|
|
46377
|
-
geometry: { type: "MultiPoint", coordinates: coords }
|
|
46378
|
-
};
|
|
46379
|
-
};
|
|
46380
|
-
let fitFeatures;
|
|
46381
|
-
if (resolved.projection === "albers-usa" && usLayer) {
|
|
46382
|
-
fitFeatures = [...usLayer.entries()].filter(([iso]) => !US_NON_CONUS.has(iso)).map(([, f]) => f);
|
|
46383
|
-
} else {
|
|
46384
|
-
fitFeatures = [extentOutline()];
|
|
46385
|
-
}
|
|
46386
|
-
const fitTarget = { type: "FeatureCollection", features: fitFeatures };
|
|
46387
|
-
const projection = projectionFor(resolved.projection);
|
|
46388
|
-
if (resolved.projection !== "albers-usa") {
|
|
46389
|
-
let centerLon = (resolved.extent[0][0] + resolved.extent[1][0]) / 2;
|
|
46390
|
-
if (centerLon > 180) centerLon -= 360;
|
|
46391
|
-
projection.rotate([-centerLon, 0]);
|
|
46392
|
-
}
|
|
46393
|
-
const TITLE_GAP = 16;
|
|
47353
|
+
const TITLE_GAP2 = 16;
|
|
46394
47354
|
let topPad = FIT_PAD;
|
|
46395
47355
|
if (resolved.title && resolved.pois.length > 0) {
|
|
46396
47356
|
const bannerBottom = (resolved.subtitle ? TITLE_Y + TITLE_FONT_SIZE : TITLE_Y) + TITLE_FONT_SIZE / 2;
|
|
46397
|
-
topPad = Math.max(FIT_PAD, bannerBottom +
|
|
47357
|
+
topPad = Math.max(FIT_PAD, bannerBottom + TITLE_GAP2);
|
|
46398
47358
|
}
|
|
46399
47359
|
const fitBox = [
|
|
46400
47360
|
[FIT_PAD, topPad],
|
|
@@ -46404,12 +47364,10 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46404
47364
|
]
|
|
46405
47365
|
];
|
|
46406
47366
|
projection.fitExtent(fitBox, fitTarget);
|
|
46407
|
-
const fitGB = geoBounds2(fitTarget);
|
|
46408
|
-
const fitIsGlobal = fitGB[1][0] - fitGB[0][0] >= 270 || fitGB[1][1] - fitGB[0][1] >= 130;
|
|
46409
47367
|
let path;
|
|
46410
47368
|
let project;
|
|
46411
47369
|
let stretchParams = null;
|
|
46412
|
-
if (fitIsGlobal) {
|
|
47370
|
+
if (fitIsGlobal && !opts.preferContain) {
|
|
46413
47371
|
const cb = geoPath(projection).bounds(fitTarget);
|
|
46414
47372
|
const bx0 = cb[0][0];
|
|
46415
47373
|
const by0 = cb[0][1];
|
|
@@ -46451,7 +47409,9 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46451
47409
|
const insets = [];
|
|
46452
47410
|
const insetRegions = [];
|
|
46453
47411
|
const insetLabelSeeds = [];
|
|
46454
|
-
|
|
47412
|
+
const akRef = resolved.regions.some((r) => r.iso === "US-AK") || resolved.pois.some((p) => inAlaska(p.lon, p.lat));
|
|
47413
|
+
const hiRef = resolved.regions.some((r) => r.iso === "US-HI") || resolved.pois.some((p) => inHawaii(p.lon, p.lat));
|
|
47414
|
+
if (resolved.projection === "albers-usa" && usLayer && (akRef || hiRef)) {
|
|
46455
47415
|
const PAD = 8;
|
|
46456
47416
|
const GAP = 12;
|
|
46457
47417
|
const yB = height - FIT_PAD;
|
|
@@ -46516,8 +47476,18 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46516
47476
|
);
|
|
46517
47477
|
const d = geoPath(proj)(f) ?? "";
|
|
46518
47478
|
if (!d) return xr;
|
|
47479
|
+
let contextLand;
|
|
47480
|
+
if (iso === "US-AK") {
|
|
47481
|
+
const can = worldLayer.get("CA");
|
|
47482
|
+
const cd = can ? geoPath(proj)(can) ?? "" : "";
|
|
47483
|
+
if (cd)
|
|
47484
|
+
contextLand = {
|
|
47485
|
+
d: cd,
|
|
47486
|
+
fill: colorizeActive ? colorByIso.get("CA") ?? foreignFill : foreignFill
|
|
47487
|
+
};
|
|
47488
|
+
}
|
|
46519
47489
|
const r = regionById.get(iso);
|
|
46520
|
-
let fill2 = neutralFill;
|
|
47490
|
+
let fill2 = colorizeActive ? colorByIso.get(iso) ?? neutralFill : neutralFill;
|
|
46521
47491
|
let lineNumber = -1;
|
|
46522
47492
|
if (r?.layer === "us-state") {
|
|
46523
47493
|
fill2 = regionFill(r);
|
|
@@ -46536,13 +47506,14 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46536
47506
|
],
|
|
46537
47507
|
// The FITTED inset projection (just fit to this box) — captured so the
|
|
46538
47508
|
// geo-query can invert pixels inside the frame back to AK/HI coords.
|
|
46539
|
-
projection: proj
|
|
47509
|
+
projection: proj,
|
|
47510
|
+
...contextLand && { contextLand }
|
|
46540
47511
|
});
|
|
46541
47512
|
insetRegions.push({
|
|
46542
47513
|
id: iso,
|
|
46543
47514
|
d,
|
|
46544
47515
|
fill: fill2,
|
|
46545
|
-
stroke: regionStroke,
|
|
47516
|
+
stroke: colorizeActive ? colorizeStroke(fill2) : regionStroke,
|
|
46546
47517
|
lineNumber,
|
|
46547
47518
|
layer: "us-state",
|
|
46548
47519
|
...r?.value !== void 0 && { value: r.value },
|
|
@@ -46555,13 +47526,16 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46555
47526
|
}
|
|
46556
47527
|
return xr;
|
|
46557
47528
|
};
|
|
46558
|
-
|
|
46559
|
-
|
|
46560
|
-
alaskaProjection(),
|
|
46561
|
-
|
|
46562
|
-
|
|
46563
|
-
|
|
46564
|
-
|
|
47529
|
+
let akRight = FIT_PAD;
|
|
47530
|
+
if (akRef)
|
|
47531
|
+
akRight = placeInset("US-AK", alaskaProjection(), FIT_PAD, width * 0.15);
|
|
47532
|
+
if (hiRef)
|
|
47533
|
+
placeInset(
|
|
47534
|
+
"US-HI",
|
|
47535
|
+
hawaiiProjection(),
|
|
47536
|
+
akRef ? akRight + 24 : FIT_PAD,
|
|
47537
|
+
width * 0.1
|
|
47538
|
+
);
|
|
46565
47539
|
}
|
|
46566
47540
|
const conusFit = resolved.projection === "albers-usa" && !!usLayer;
|
|
46567
47541
|
const classifyExtent = conusFit ? geoBounds2(fitTarget) : resolved.extent;
|
|
@@ -46577,15 +47551,24 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46577
47551
|
};
|
|
46578
47552
|
const ringOverlapsView = (ring) => {
|
|
46579
47553
|
let loMin = Infinity, loMax = -Infinity, rawMin = Infinity, rawMax = -Infinity;
|
|
47554
|
+
const lons = [];
|
|
46580
47555
|
for (const [rawLon] of ring) {
|
|
46581
47556
|
const lon = normLon(rawLon);
|
|
47557
|
+
lons.push(lon);
|
|
46582
47558
|
if (lon < loMin) loMin = lon;
|
|
46583
47559
|
if (lon > loMax) loMax = lon;
|
|
46584
47560
|
if (rawLon < rawMin) rawMin = rawLon;
|
|
46585
47561
|
if (rawLon > rawMax) rawMax = rawLon;
|
|
46586
47562
|
}
|
|
46587
|
-
|
|
46588
|
-
|
|
47563
|
+
lons.sort((a, b) => a - b);
|
|
47564
|
+
let maxGap = 0;
|
|
47565
|
+
for (let i = 1; i < lons.length; i++)
|
|
47566
|
+
maxGap = Math.max(maxGap, lons[i] - lons[i - 1]);
|
|
47567
|
+
if (lons.length > 1)
|
|
47568
|
+
maxGap = Math.max(maxGap, lons[0] + 360 - lons[lons.length - 1]);
|
|
47569
|
+
const occupiedArc = 360 - maxGap;
|
|
47570
|
+
if (occupiedArc > 270) return false;
|
|
47571
|
+
if (rawMax - rawMin > 180 && occupiedArc < 90) return false;
|
|
46589
47572
|
let px0 = Infinity, py0 = Infinity, px1 = -Infinity, py1 = -Infinity, anyFinite = false;
|
|
46590
47573
|
for (const [lon, lat] of ring) {
|
|
46591
47574
|
const p = project(lon, lat);
|
|
@@ -46658,7 +47641,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46658
47641
|
const regions = [];
|
|
46659
47642
|
const pushRegionLayer = (layerFeatures, layerKind, shouldCull) => {
|
|
46660
47643
|
for (const [iso, f] of layerFeatures) {
|
|
46661
|
-
if (layerKind === "us-state" && usContext && INSET_STATES.has(iso))
|
|
47644
|
+
if (layerKind === "us-state" && usContext && resolved.projection === "albers-usa" && INSET_STATES.has(iso))
|
|
46662
47645
|
continue;
|
|
46663
47646
|
if (layerKind === "country" && usContext && iso === "US") continue;
|
|
46664
47647
|
if (layerKind === "country" && iso === "AQ" && !regionById.has("AQ"))
|
|
@@ -46670,7 +47653,8 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46670
47653
|
if (!d) continue;
|
|
46671
47654
|
const isThisLayer = r?.layer === layerKind;
|
|
46672
47655
|
const isForeign = layerKind === "country" && usContext && iso !== "US";
|
|
46673
|
-
|
|
47656
|
+
const baseFill = isForeign ? foreignFill : neutralFill;
|
|
47657
|
+
let fill2 = colorizeActive ? colorByIso.get(iso) ?? baseFill : baseFill;
|
|
46674
47658
|
let label;
|
|
46675
47659
|
let lineNumber = -1;
|
|
46676
47660
|
let layer = "base";
|
|
@@ -46679,12 +47663,14 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46679
47663
|
lineNumber = r.lineNumber;
|
|
46680
47664
|
layer = layerKind;
|
|
46681
47665
|
label = r.name;
|
|
47666
|
+
} else {
|
|
47667
|
+
label = f.properties?.name;
|
|
46682
47668
|
}
|
|
46683
47669
|
regions.push({
|
|
46684
47670
|
id: iso,
|
|
46685
47671
|
d,
|
|
46686
47672
|
fill: fill2,
|
|
46687
|
-
stroke: regionStroke,
|
|
47673
|
+
stroke: colorizeActive ? colorizeStroke(fill2) : regionStroke,
|
|
46688
47674
|
lineNumber,
|
|
46689
47675
|
layer,
|
|
46690
47676
|
...label !== void 0 && { label },
|
|
@@ -46712,9 +47698,41 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46712
47698
|
});
|
|
46713
47699
|
}
|
|
46714
47700
|
}
|
|
47701
|
+
const pointInRings = (px, py, rings) => {
|
|
47702
|
+
let inside = false;
|
|
47703
|
+
for (const ring of rings) {
|
|
47704
|
+
for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
|
|
47705
|
+
const [xi, yi] = ring[i];
|
|
47706
|
+
const [xj, yj] = ring[j];
|
|
47707
|
+
if (yi > py !== yj > py && px < (xj - xi) * (py - yi) / (yj - yi) + xi)
|
|
47708
|
+
inside = !inside;
|
|
47709
|
+
}
|
|
47710
|
+
}
|
|
47711
|
+
return inside;
|
|
47712
|
+
};
|
|
47713
|
+
const fillHitTargets = [...regions, ...insetRegions].map((r) => ({
|
|
47714
|
+
fill: r.fill,
|
|
47715
|
+
rings: parsePathRings(r.d)
|
|
47716
|
+
}));
|
|
47717
|
+
const fillAt = (x, y) => {
|
|
47718
|
+
let hit = water;
|
|
47719
|
+
for (const t of fillHitTargets)
|
|
47720
|
+
if (pointInRings(x, y, t.rings)) hit = t.fill;
|
|
47721
|
+
return hit;
|
|
47722
|
+
};
|
|
47723
|
+
const labelOnFill = (fill2) => {
|
|
47724
|
+
const color = contrastRatio(fill2, palette.textOnFillDark) >= contrastRatio(fill2, palette.textOnFillLight) ? palette.textOnFillDark : palette.textOnFillLight;
|
|
47725
|
+
const haloColor = color === palette.textOnFillLight ? palette.textOnFillDark : palette.textOnFillLight;
|
|
47726
|
+
return {
|
|
47727
|
+
color,
|
|
47728
|
+
halo: contrastRatio(fill2, color) < REGION_LABEL_HALO_RATIO,
|
|
47729
|
+
haloColor
|
|
47730
|
+
};
|
|
47731
|
+
};
|
|
47732
|
+
const reliefAllowed = resolved.directives.noRelief !== true;
|
|
46715
47733
|
const relief = [];
|
|
46716
47734
|
let reliefHatch = null;
|
|
46717
|
-
if (
|
|
47735
|
+
if (reliefAllowed && data.mountainRanges) {
|
|
46718
47736
|
for (const [, f] of decodeLayer(data.mountainRanges)) {
|
|
46719
47737
|
const viewF = isGlobalView ? dropFrameFillers(f) : cullFeatureToView(f);
|
|
46720
47738
|
if (!viewF) continue;
|
|
@@ -46730,16 +47748,32 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46730
47748
|
if (relief.length) {
|
|
46731
47749
|
const darkTone = isDark ? palette.bg : palette.text;
|
|
46732
47750
|
const lightTone = isDark ? palette.text : palette.bg;
|
|
46733
|
-
const
|
|
47751
|
+
const reliefLandRef = colorizeActive ? isDark ? palette.surface : palette.bg : neutralFill;
|
|
47752
|
+
const landLum = relativeLuminance(reliefLandRef);
|
|
46734
47753
|
const tone = Math.abs(landLum - relativeLuminance(darkTone)) > 0.04 ? darkTone : lightTone;
|
|
46735
47754
|
reliefHatch = {
|
|
46736
|
-
color: mix(tone,
|
|
47755
|
+
color: mix(tone, reliefLandRef, RELIEF_HATCH_STRENGTH),
|
|
46737
47756
|
spacing: RELIEF_HATCH_SPACING,
|
|
46738
47757
|
width: RELIEF_HATCH_WIDTH
|
|
46739
47758
|
};
|
|
46740
47759
|
}
|
|
46741
47760
|
}
|
|
46742
|
-
|
|
47761
|
+
let coastlineStyle = null;
|
|
47762
|
+
if (resolved.directives.noCoastline !== true) {
|
|
47763
|
+
const minDim = Math.min(width, height);
|
|
47764
|
+
coastlineStyle = {
|
|
47765
|
+
color: mix(regionStroke, water, COASTLINE_STROKE_MIX),
|
|
47766
|
+
// N equal-width rings: distance steps outward by COASTLINE_STEP; opacity
|
|
47767
|
+
// fades linearly from NEAR (innermost) to FAR (outermost).
|
|
47768
|
+
lines: Array.from({ length: COASTLINE_RING_COUNT }, (_, k) => ({
|
|
47769
|
+
d: (COASTLINE_D0 + k * COASTLINE_STEP) * minDim,
|
|
47770
|
+
thickness: COASTLINE_THICKNESS * minDim,
|
|
47771
|
+
opacity: COASTLINE_OPACITY_NEAR + (COASTLINE_OPACITY_FAR - COASTLINE_OPACITY_NEAR) * k / (COASTLINE_RING_COUNT - 1)
|
|
47772
|
+
})),
|
|
47773
|
+
minExtent: (isGlobalView ? COASTLINE_MIN_EXTENT_GLOBAL : COASTLINE_MIN_EXTENT) * minDim
|
|
47774
|
+
};
|
|
47775
|
+
}
|
|
47776
|
+
const riverColor = mix(palette.colors.blue, water, 32);
|
|
46743
47777
|
const rivers = [];
|
|
46744
47778
|
if (data.rivers) {
|
|
46745
47779
|
for (const [, f] of decodeLayer(data.rivers)) {
|
|
@@ -46795,38 +47829,108 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46795
47829
|
const xy = project(p.lon, p.lat);
|
|
46796
47830
|
if (xy) projected.push({ p, xy });
|
|
46797
47831
|
}
|
|
46798
|
-
const
|
|
47832
|
+
const placePoi = (e, cx, cy, clusterId) => {
|
|
47833
|
+
const { fill: fill2, stroke: stroke2 } = poiFill(e.p);
|
|
47834
|
+
poiScreen.set(e.p.id, { cx, cy, r: radiusFor(e.p) });
|
|
47835
|
+
const num = routeNumberById.get(e.p.id);
|
|
47836
|
+
pois.push({
|
|
47837
|
+
id: e.p.id,
|
|
47838
|
+
cx,
|
|
47839
|
+
cy,
|
|
47840
|
+
r: radiusFor(e.p),
|
|
47841
|
+
fill: fill2,
|
|
47842
|
+
stroke: stroke2,
|
|
47843
|
+
lineNumber: e.p.lineNumber,
|
|
47844
|
+
implicit: !!e.p.implicit,
|
|
47845
|
+
isOrigin: originIds.has(e.p.id),
|
|
47846
|
+
...num !== void 0 && { routeNumber: num },
|
|
47847
|
+
...Object.keys(e.p.tags).length > 0 && { tags: e.p.tags },
|
|
47848
|
+
...clusterId !== void 0 && { clusterId }
|
|
47849
|
+
});
|
|
47850
|
+
};
|
|
47851
|
+
const clusters = [];
|
|
47852
|
+
const connected = /* @__PURE__ */ new Set();
|
|
47853
|
+
for (const e of resolved.edges) {
|
|
47854
|
+
connected.add(e.fromId);
|
|
47855
|
+
connected.add(e.toId);
|
|
47856
|
+
}
|
|
47857
|
+
for (const rt of resolved.routes) {
|
|
47858
|
+
rt.stopIds.forEach((id) => connected.add(id));
|
|
47859
|
+
}
|
|
47860
|
+
const radiusOf = (e) => radiusFor(e.p);
|
|
46799
47861
|
for (const e of projected) {
|
|
46800
|
-
|
|
46801
|
-
|
|
46802
|
-
|
|
46803
|
-
|
|
46804
|
-
|
|
46805
|
-
|
|
46806
|
-
|
|
46807
|
-
|
|
46808
|
-
|
|
46809
|
-
|
|
46810
|
-
|
|
46811
|
-
|
|
46812
|
-
|
|
46813
|
-
|
|
46814
|
-
|
|
46815
|
-
|
|
46816
|
-
|
|
46817
|
-
|
|
46818
|
-
|
|
46819
|
-
|
|
46820
|
-
|
|
46821
|
-
|
|
46822
|
-
|
|
46823
|
-
|
|
46824
|
-
|
|
46825
|
-
|
|
46826
|
-
|
|
46827
|
-
|
|
46828
|
-
|
|
46829
|
-
|
|
47862
|
+
if (connected.has(e.p.id)) placePoi(e, e.xy[0], e.xy[1]);
|
|
47863
|
+
}
|
|
47864
|
+
const groups = [];
|
|
47865
|
+
for (const e of projected) {
|
|
47866
|
+
if (connected.has(e.p.id)) continue;
|
|
47867
|
+
const r = radiusOf(e);
|
|
47868
|
+
const near = groups.find(
|
|
47869
|
+
(g) => g.some(
|
|
47870
|
+
(q) => Math.hypot(q.xy[0] - e.xy[0], q.xy[1] - e.xy[1]) < (r + radiusOf(q)) * STACK_OVERLAP
|
|
47871
|
+
)
|
|
47872
|
+
);
|
|
47873
|
+
if (near) near.push(e);
|
|
47874
|
+
else groups.push([e]);
|
|
47875
|
+
}
|
|
47876
|
+
for (const g of groups) {
|
|
47877
|
+
if (g.length === 1) {
|
|
47878
|
+
placePoi(g[0], g[0].xy[0], g[0].xy[1]);
|
|
47879
|
+
continue;
|
|
47880
|
+
}
|
|
47881
|
+
const clusterId = g[0].p.id;
|
|
47882
|
+
const cx0 = g.reduce((s, e) => s + e.xy[0], 0) / g.length;
|
|
47883
|
+
const cy0 = g.reduce((s, e) => s + e.xy[1], 0) / g.length;
|
|
47884
|
+
const maxR = Math.max(...g.map(radiusOf));
|
|
47885
|
+
const sep = 2 * maxR + STACK_RING_GAP;
|
|
47886
|
+
const ringR = Math.max(
|
|
47887
|
+
COLO_R,
|
|
47888
|
+
sep / (2 * Math.sin(Math.PI / Math.max(g.length, 2)))
|
|
47889
|
+
);
|
|
47890
|
+
const positions = g.map((e, i) => {
|
|
47891
|
+
if (g.length <= STACK_RING_MAX) {
|
|
47892
|
+
const ang2 = -Math.PI / 2 + i * 2 * Math.PI / g.length;
|
|
47893
|
+
return {
|
|
47894
|
+
e,
|
|
47895
|
+
mx: cx0 + Math.cos(ang2) * ringR,
|
|
47896
|
+
my: cy0 + Math.sin(ang2) * ringR
|
|
47897
|
+
};
|
|
47898
|
+
}
|
|
47899
|
+
const ang = i * GOLDEN_ANGLE;
|
|
47900
|
+
const rr = ringR * Math.sqrt((i + 1) / g.length);
|
|
47901
|
+
return { e, mx: cx0 + Math.cos(ang) * rr, my: cy0 + Math.sin(ang) * rr };
|
|
47902
|
+
});
|
|
47903
|
+
let minX = cx0 - maxR;
|
|
47904
|
+
let maxX = cx0 + maxR;
|
|
47905
|
+
let minY = cy0 - maxR;
|
|
47906
|
+
let maxY = cy0 + maxR;
|
|
47907
|
+
for (const { mx, my, e } of positions) {
|
|
47908
|
+
const r = radiusOf(e);
|
|
47909
|
+
minX = Math.min(minX, mx - r);
|
|
47910
|
+
maxX = Math.max(maxX, mx + r);
|
|
47911
|
+
minY = Math.min(minY, my - r);
|
|
47912
|
+
maxY = Math.max(maxY, my + r);
|
|
47913
|
+
}
|
|
47914
|
+
let dx = 0;
|
|
47915
|
+
let dy = 0;
|
|
47916
|
+
if (minX + dx < 2) dx = 2 - minX;
|
|
47917
|
+
if (maxX + dx > width - 2) dx = width - 2 - maxX;
|
|
47918
|
+
if (minY + dy < 2) dy = 2 - minY;
|
|
47919
|
+
if (maxY + dy > height - 2) dy = height - 2 - maxY;
|
|
47920
|
+
const legsOut = [];
|
|
47921
|
+
for (const { e, mx, my } of positions) {
|
|
47922
|
+
const fx = mx + dx;
|
|
47923
|
+
const fy = my + dy;
|
|
47924
|
+
placePoi(e, fx, fy, clusterId);
|
|
47925
|
+
legsOut.push({ x2: fx, y2: fy, color: poiFill(e.p).fill });
|
|
47926
|
+
}
|
|
47927
|
+
clusters.push({
|
|
47928
|
+
id: clusterId,
|
|
47929
|
+
cx: cx0 + dx,
|
|
47930
|
+
cy: cy0 + dy,
|
|
47931
|
+
count: g.length,
|
|
47932
|
+
hitR: ringR + maxR + 6,
|
|
47933
|
+
legs: legsOut
|
|
46830
47934
|
});
|
|
46831
47935
|
}
|
|
46832
47936
|
const legs = [];
|
|
@@ -46876,16 +47980,26 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46876
47980
|
if (!a || !b) continue;
|
|
46877
47981
|
const mx = (a.cx + b.cx) / 2;
|
|
46878
47982
|
const my = (a.cy + b.cy) / 2;
|
|
47983
|
+
const bow = {
|
|
47984
|
+
curved: leg.style === "arc",
|
|
47985
|
+
offset: 0,
|
|
47986
|
+
labelX: mx,
|
|
47987
|
+
labelY: my - 4
|
|
47988
|
+
};
|
|
47989
|
+
const routeLabelStyle = leg.label !== void 0 ? labelOnFill(fillAt(bow.labelX, bow.labelY)) : void 0;
|
|
46879
47990
|
legs.push({
|
|
46880
|
-
d: legPath(a, b,
|
|
47991
|
+
d: legPath(a, b, bow.curved, bow.offset),
|
|
46881
47992
|
width: routeWidthFor(Number(leg.value)),
|
|
46882
47993
|
color: mix(palette.text, palette.bg, 72),
|
|
46883
47994
|
arrow: true,
|
|
46884
47995
|
lineNumber: leg.lineNumber,
|
|
46885
47996
|
...leg.label !== void 0 && {
|
|
46886
47997
|
label: leg.label,
|
|
46887
|
-
labelX:
|
|
46888
|
-
labelY:
|
|
47998
|
+
labelX: bow.labelX,
|
|
47999
|
+
labelY: bow.labelY,
|
|
48000
|
+
labelColor: routeLabelStyle.color,
|
|
48001
|
+
labelHalo: routeLabelStyle.halo,
|
|
48002
|
+
labelHaloColor: routeLabelStyle.haloColor
|
|
46889
48003
|
}
|
|
46890
48004
|
});
|
|
46891
48005
|
}
|
|
@@ -46913,20 +48027,29 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46913
48027
|
const a = poiScreen.get(e.fromId);
|
|
46914
48028
|
const b = poiScreen.get(e.toId);
|
|
46915
48029
|
if (!a || !b) return;
|
|
46916
|
-
const
|
|
46917
|
-
const offset = n > 1 ? (i - (n - 1) / 2) * FAN_STEP : 0;
|
|
48030
|
+
const fanOffset = n > 1 ? (i - (n - 1) / 2) * FAN_STEP : 0;
|
|
46918
48031
|
const mx = (a.cx + b.cx) / 2;
|
|
46919
48032
|
const my = (a.cy + b.cy) / 2;
|
|
48033
|
+
const bow = {
|
|
48034
|
+
curved: e.style === "arc" || n > 1,
|
|
48035
|
+
offset: fanOffset,
|
|
48036
|
+
labelX: mx,
|
|
48037
|
+
labelY: my - 4
|
|
48038
|
+
};
|
|
48039
|
+
const edgeLabelStyle = e.label !== void 0 ? labelOnFill(fillAt(bow.labelX, bow.labelY)) : void 0;
|
|
46920
48040
|
legs.push({
|
|
46921
|
-
d: legPath(a, b, curved, offset),
|
|
48041
|
+
d: legPath(a, b, bow.curved, bow.offset),
|
|
46922
48042
|
width: widthFor(e),
|
|
46923
48043
|
color: mix(palette.text, palette.bg, 66),
|
|
46924
48044
|
arrow: e.directed,
|
|
46925
48045
|
lineNumber: e.lineNumber,
|
|
46926
48046
|
...e.label !== void 0 && {
|
|
46927
48047
|
label: e.label,
|
|
46928
|
-
labelX:
|
|
46929
|
-
labelY:
|
|
48048
|
+
labelX: bow.labelX,
|
|
48049
|
+
labelY: bow.labelY,
|
|
48050
|
+
labelColor: edgeLabelStyle.color,
|
|
48051
|
+
labelHalo: edgeLabelStyle.halo,
|
|
48052
|
+
labelHaloColor: edgeLabelStyle.haloColor
|
|
46930
48053
|
}
|
|
46931
48054
|
});
|
|
46932
48055
|
});
|
|
@@ -46968,25 +48091,25 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46968
48091
|
}
|
|
46969
48092
|
}
|
|
46970
48093
|
const collides = (rect) => markers.some((m) => rectCircleOverlap(rect, m)) || obstacles.some((o) => rectsOverlap(rect, o)) || legSegments.some((s) => segmentRectOverlap(s[0], s[1], s[2], s[3], rect));
|
|
46971
|
-
const
|
|
48094
|
+
const showRegionLabels = resolved.directives.noRegionLabels !== true;
|
|
48095
|
+
const isCompact = width < COMPACT_WIDTH_PX;
|
|
46972
48096
|
const LABEL_PADX = 6;
|
|
46973
48097
|
const LABEL_PADY = 3;
|
|
46974
|
-
const labelW = (text) => measureLegendText(text,
|
|
46975
|
-
const labelH =
|
|
48098
|
+
const labelW = (text) => measureLegendText(text, FONT2) + 2 * LABEL_PADX;
|
|
48099
|
+
const labelH = FONT2 + 2 * LABEL_PADY;
|
|
46976
48100
|
const pushRegionLabel = (x, y, text, fill2, lineNumber) => {
|
|
46977
|
-
const color =
|
|
46978
|
-
|
|
46979
|
-
|
|
46980
|
-
|
|
48101
|
+
const { color, haloColor } = labelOnFill(fill2);
|
|
48102
|
+
const halfW = measureLegendText(text, FONT2) / 2;
|
|
48103
|
+
const overflows = [y - FONT2 * 0.55, y - FONT2 * 0.1].some(
|
|
48104
|
+
(sy) => fillAt(x - halfW, sy) !== fill2 || fillAt(x + halfW, sy) !== fill2
|
|
46981
48105
|
);
|
|
46982
|
-
const haloColor = color === palette.textOnFillLight ? palette.textOnFillDark : palette.textOnFillLight;
|
|
46983
48106
|
labels.push({
|
|
46984
48107
|
x,
|
|
46985
48108
|
y,
|
|
46986
48109
|
text,
|
|
46987
48110
|
anchor: "middle",
|
|
46988
48111
|
color,
|
|
46989
|
-
halo:
|
|
48112
|
+
halo: overflows,
|
|
46990
48113
|
haloColor,
|
|
46991
48114
|
lineNumber
|
|
46992
48115
|
});
|
|
@@ -46995,21 +48118,50 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46995
48118
|
US: [-98.5, 39.5]
|
|
46996
48119
|
// CONUS geographic centre (near Lebanon, Kansas)
|
|
46997
48120
|
};
|
|
46998
|
-
|
|
46999
|
-
|
|
47000
|
-
|
|
47001
|
-
|
|
47002
|
-
|
|
48121
|
+
const REGION_LABEL_GAP = 2;
|
|
48122
|
+
const regionLabelRect = (cx, cy, text) => {
|
|
48123
|
+
const w = measureLegendText(text, FONT2) + 2 * REGION_LABEL_GAP;
|
|
48124
|
+
return { x: cx - w / 2, y: cy - FONT2 / 2, w, h: FONT2 };
|
|
48125
|
+
};
|
|
48126
|
+
if (showRegionLabels) {
|
|
48127
|
+
const frameContainers = new Set(resolved.poiFrameContainers);
|
|
48128
|
+
const entries = regions.map((r) => {
|
|
48129
|
+
const isContainer = frameContainers.has(r.id);
|
|
48130
|
+
if (r.layer === "base" && !isContainer || r.label === void 0)
|
|
48131
|
+
return null;
|
|
48132
|
+
const isUsState = r.layer === "us-state" || r.id.startsWith("US-");
|
|
48133
|
+
const f = isUsState ? usLayer?.get(r.id) : worldLayer.get(r.id);
|
|
48134
|
+
if (!f) return null;
|
|
47003
48135
|
const [[x0, y0], [x1, y1]] = path.bounds(f);
|
|
47004
|
-
const
|
|
47005
|
-
|
|
47006
|
-
const
|
|
48136
|
+
const boxW = x1 - x0;
|
|
48137
|
+
const boxH = y1 - y0;
|
|
48138
|
+
const abbrev = isUsState ? r.id.replace(/^US-/, "") : void 0;
|
|
48139
|
+
const candidates = abbrev !== void 0 ? isCompact ? [abbrev, r.label] : [r.label, abbrev] : [r.label];
|
|
48140
|
+
const anchor = !isUsState ? WORLD_LABEL_ANCHORS[r.id] : void 0;
|
|
47007
48141
|
const c = anchor ? project(anchor[0], anchor[1]) : path.centroid(f);
|
|
47008
|
-
if (!c || !Number.isFinite(c[0]))
|
|
48142
|
+
if (!c || !Number.isFinite(c[0])) return null;
|
|
48143
|
+
return { r, c, boxW, boxH, area: boxW * boxH, candidates };
|
|
48144
|
+
}).filter((e) => e !== null).sort((a, b) => b.area - a.area || a.r.lineNumber - b.r.lineNumber);
|
|
48145
|
+
const placedRegionRects = [];
|
|
48146
|
+
const POI_LABEL_PAD = 14;
|
|
48147
|
+
const poiObstacles = pois.map((p) => ({
|
|
48148
|
+
x: p.cx - p.r - POI_LABEL_PAD,
|
|
48149
|
+
y: p.cy - p.r - POI_LABEL_PAD,
|
|
48150
|
+
w: 2 * (p.r + POI_LABEL_PAD),
|
|
48151
|
+
h: 2 * (p.r + POI_LABEL_PAD)
|
|
48152
|
+
}));
|
|
48153
|
+
for (const { r, c, boxW, boxH, candidates } of entries) {
|
|
48154
|
+
const text = candidates.find((t) => {
|
|
48155
|
+
if (labelW(t) > boxW || labelH > boxH) return false;
|
|
48156
|
+
const rect = regionLabelRect(c[0], c[1], t);
|
|
48157
|
+
return !placedRegionRects.some((p) => rectsOverlap(rect, p)) && !poiObstacles.some((o) => rectsOverlap(rect, o));
|
|
48158
|
+
});
|
|
48159
|
+
if (text === void 0) continue;
|
|
48160
|
+
placedRegionRects.push(regionLabelRect(c[0], c[1], text));
|
|
47009
48161
|
pushRegionLabel(c[0], c[1], text, r.fill, r.lineNumber);
|
|
47010
48162
|
}
|
|
47011
48163
|
for (const seed of insetLabelSeeds) {
|
|
47012
|
-
const text =
|
|
48164
|
+
const text = isCompact ? seed.iso.replace(/^US-/, "") : seed.name;
|
|
47013
48165
|
const src = regionById.get(seed.iso);
|
|
47014
48166
|
pushRegionLabel(
|
|
47015
48167
|
seed.x,
|
|
@@ -47020,22 +48172,26 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47020
48172
|
);
|
|
47021
48173
|
}
|
|
47022
48174
|
}
|
|
47023
|
-
|
|
47024
|
-
|
|
47025
|
-
const ordered = [...pois].sort(
|
|
47026
|
-
(a, b) => a.lineNumber - b.lineNumber || (a.id < b.id ? -1 : 1)
|
|
47027
|
-
);
|
|
48175
|
+
if (resolved.directives.noPoiLabels !== true) {
|
|
48176
|
+
const ordered = [...pois].filter((p) => p.clusterId === void 0).sort((a, b) => a.lineNumber - b.lineNumber || (a.id < b.id ? -1 : 1));
|
|
47028
48177
|
const poiById = new Map(resolved.pois.map((q) => [q.id, q]));
|
|
47029
48178
|
const labelText = (p) => {
|
|
47030
48179
|
const src = poiById.get(p.id);
|
|
47031
48180
|
return src?.label ?? src?.name ?? p.id;
|
|
47032
48181
|
};
|
|
47033
|
-
const poiLabH =
|
|
48182
|
+
const poiLabH = FONT2 * 1.25;
|
|
47034
48183
|
const labelInfo = (p) => {
|
|
47035
48184
|
const text = labelText(p);
|
|
47036
|
-
return { text, w: measureLegendText(text,
|
|
48185
|
+
return { text, w: measureLegendText(text, FONT2) };
|
|
47037
48186
|
};
|
|
47038
48187
|
const GAP = 3;
|
|
48188
|
+
const clusterMembersById = /* @__PURE__ */ new Map();
|
|
48189
|
+
for (const p of pois) {
|
|
48190
|
+
if (p.clusterId === void 0) continue;
|
|
48191
|
+
const arr = clusterMembersById.get(p.clusterId);
|
|
48192
|
+
if (arr) arr.push(p);
|
|
48193
|
+
else clusterMembersById.set(p.clusterId, [p]);
|
|
48194
|
+
}
|
|
47039
48195
|
const inlineRect = (p, w, side) => {
|
|
47040
48196
|
switch (side) {
|
|
47041
48197
|
case "right":
|
|
@@ -47065,11 +48221,11 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47065
48221
|
const x = side === "right" ? rect.x : side === "left" ? rect.x + w : p.cx;
|
|
47066
48222
|
labels.push({
|
|
47067
48223
|
x,
|
|
47068
|
-
y: rect.y + poiLabH / 2 +
|
|
48224
|
+
y: rect.y + poiLabH / 2 + FONT2 / 3,
|
|
47069
48225
|
text,
|
|
47070
48226
|
anchor,
|
|
47071
48227
|
color: palette.text,
|
|
47072
|
-
halo:
|
|
48228
|
+
halo: false,
|
|
47073
48229
|
haloColor: palette.bg,
|
|
47074
48230
|
poiId: p.id,
|
|
47075
48231
|
lineNumber: p.lineNumber
|
|
@@ -47080,43 +48236,60 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47080
48236
|
return rect.x >= 0 && rect.x + rect.w <= width && rect.y >= 0 && rect.y + rect.h <= height && !collides(rect);
|
|
47081
48237
|
};
|
|
47082
48238
|
const GROUP_R = 30;
|
|
47083
|
-
const
|
|
48239
|
+
const groups2 = [];
|
|
47084
48240
|
for (const p of ordered) {
|
|
47085
|
-
const near =
|
|
48241
|
+
const near = groups2.find(
|
|
47086
48242
|
(g) => g.some((q) => Math.hypot(q.cx - p.cx, q.cy - p.cy) < GROUP_R)
|
|
47087
48243
|
);
|
|
47088
48244
|
if (near) near.push(p);
|
|
47089
|
-
else
|
|
48245
|
+
else groups2.push([p]);
|
|
47090
48246
|
}
|
|
47091
48247
|
const ROW_GAP2 = 3;
|
|
47092
48248
|
const step = poiLabH + ROW_GAP2;
|
|
47093
48249
|
const COL_GAP = 16;
|
|
47094
|
-
const
|
|
47095
|
-
|
|
48250
|
+
const makeItems = (group) => group.map((p) => ({ p, ...labelInfo(p) })).sort((a, b) => a.p.cy - b.p.cy || (a.text < b.text ? -1 : 1));
|
|
48251
|
+
const columnRows = (items, side) => {
|
|
47096
48252
|
const left = Math.min(...items.map((o) => o.p.cx - o.p.r));
|
|
47097
48253
|
const right = Math.max(...items.map((o) => o.p.cx + o.p.r));
|
|
47098
|
-
const cyMid = (Math.min(...items.map((o) => o.p.cy)) + Math.max(...items.map((o) => o.p.cy))) / 2;
|
|
47099
48254
|
const maxW = Math.max(...items.map((o) => o.w));
|
|
47100
|
-
const
|
|
47101
|
-
const colX = side === "right" ? right + COL_GAP : left - COL_GAP;
|
|
48255
|
+
const cyMid = (Math.min(...items.map((o) => o.p.cy)) + Math.max(...items.map((o) => o.p.cy))) / 2;
|
|
48256
|
+
const colX = side === "right" ? Math.min(right + COL_GAP, width - 2 - maxW) : Math.max(left - COL_GAP, 2 + maxW);
|
|
47102
48257
|
const totalH = items.length * step;
|
|
47103
48258
|
let startY = cyMid - totalH / 2;
|
|
47104
48259
|
startY = Math.max(2, Math.min(startY, height - totalH - 2));
|
|
47105
|
-
items.
|
|
48260
|
+
return items.map((o, i) => {
|
|
47106
48261
|
const rowCy = startY + i * step + step / 2;
|
|
47107
|
-
|
|
47108
|
-
|
|
47109
|
-
|
|
47110
|
-
|
|
47111
|
-
|
|
47112
|
-
|
|
48262
|
+
return {
|
|
48263
|
+
o,
|
|
48264
|
+
colX,
|
|
48265
|
+
rowCy,
|
|
48266
|
+
rect: {
|
|
48267
|
+
x: side === "right" ? colX : colX - o.w,
|
|
48268
|
+
y: rowCy - poiLabH / 2,
|
|
48269
|
+
w: o.w,
|
|
48270
|
+
h: poiLabH
|
|
48271
|
+
}
|
|
48272
|
+
};
|
|
48273
|
+
});
|
|
48274
|
+
};
|
|
48275
|
+
const wouldColumnBeClean = (items, side) => columnRows(items, side).every(
|
|
48276
|
+
({ rect }) => rect.x >= 0 && rect.x + rect.w <= width && rect.y >= 0 && rect.y + rect.h <= height && !collides(rect)
|
|
48277
|
+
);
|
|
48278
|
+
const defaultColumnSide = (items) => {
|
|
48279
|
+
const right = Math.max(...items.map((o) => o.p.cx + o.p.r));
|
|
48280
|
+
const maxW = Math.max(...items.map((o) => o.w));
|
|
48281
|
+
return right + COL_GAP + maxW <= width - 2 ? "right" : "left";
|
|
48282
|
+
};
|
|
48283
|
+
const commitColumn = (items, side, clusterId) => {
|
|
48284
|
+
for (const { o, colX, rowCy, rect } of columnRows(items, side)) {
|
|
48285
|
+
obstacles.push(rect);
|
|
47113
48286
|
labels.push({
|
|
47114
48287
|
x: colX,
|
|
47115
|
-
y: rowCy +
|
|
48288
|
+
y: rowCy + FONT2 / 3,
|
|
47116
48289
|
text: o.text,
|
|
47117
48290
|
anchor: side === "right" ? "start" : "end",
|
|
47118
48291
|
color: palette.text,
|
|
47119
|
-
halo:
|
|
48292
|
+
halo: false,
|
|
47120
48293
|
haloColor: palette.bg,
|
|
47121
48294
|
leader: {
|
|
47122
48295
|
x1: o.p.cx,
|
|
@@ -47126,24 +48299,141 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47126
48299
|
},
|
|
47127
48300
|
leaderColor: o.p.fill,
|
|
47128
48301
|
poiId: o.p.id,
|
|
47129
|
-
lineNumber: o.p.lineNumber
|
|
48302
|
+
lineNumber: o.p.lineNumber,
|
|
48303
|
+
...clusterId !== void 0 && { clusterMember: clusterId }
|
|
47130
48304
|
});
|
|
48305
|
+
}
|
|
48306
|
+
};
|
|
48307
|
+
const pushHidden = (p) => {
|
|
48308
|
+
const { text, w } = labelInfo(p);
|
|
48309
|
+
let x = p.cx + p.r + GAP;
|
|
48310
|
+
let anchor = "start";
|
|
48311
|
+
if (x + w > width) {
|
|
48312
|
+
x = p.cx - p.r - GAP - w;
|
|
48313
|
+
anchor = "end";
|
|
48314
|
+
}
|
|
48315
|
+
const y = Math.max(0, Math.min(p.cy - poiLabH / 2, height - poiLabH));
|
|
48316
|
+
labels.push({
|
|
48317
|
+
x: anchor === "start" ? x : x + w,
|
|
48318
|
+
y: y + poiLabH / 2 + FONT2 / 3,
|
|
48319
|
+
text,
|
|
48320
|
+
anchor,
|
|
48321
|
+
color: palette.text,
|
|
48322
|
+
halo: false,
|
|
48323
|
+
haloColor: palette.bg,
|
|
48324
|
+
poiId: p.id,
|
|
48325
|
+
hidden: true,
|
|
48326
|
+
lineNumber: p.lineNumber
|
|
47131
48327
|
});
|
|
47132
48328
|
};
|
|
47133
|
-
for (const
|
|
48329
|
+
for (const [clusterId, members] of clusterMembersById) {
|
|
48330
|
+
if (members.length === 0) continue;
|
|
48331
|
+
const items = makeItems(members);
|
|
48332
|
+
const side = wouldColumnBeClean(items, "right") ? "right" : wouldColumnBeClean(items, "left") ? "left" : defaultColumnSide(items);
|
|
48333
|
+
commitColumn(items, side, clusterId);
|
|
48334
|
+
}
|
|
48335
|
+
const maxExtent = MAX_CLUSTER_EXTENT_FACTOR * Math.min(width, height);
|
|
48336
|
+
const clusterPending = [];
|
|
48337
|
+
for (const g of groups2) {
|
|
48338
|
+
const items = makeItems(g);
|
|
47134
48339
|
if (g.length === 1) {
|
|
47135
|
-
const p =
|
|
47136
|
-
const { text, w } = labelInfo(p);
|
|
48340
|
+
const { p, text, w } = items[0];
|
|
47137
48341
|
const side = ["right", "left", "above", "below"].find(
|
|
47138
48342
|
(s) => inlineFits(p, w, s)
|
|
47139
48343
|
);
|
|
47140
|
-
if (side)
|
|
47141
|
-
|
|
47142
|
-
|
|
48344
|
+
if (side) pushInline(p, text, w, side);
|
|
48345
|
+
else commitColumn(items, defaultColumnSide(items));
|
|
48346
|
+
continue;
|
|
48347
|
+
}
|
|
48348
|
+
const left = Math.min(...items.map((o) => o.p.cx - o.p.r));
|
|
48349
|
+
const right = Math.max(...items.map((o) => o.p.cx + o.p.r));
|
|
48350
|
+
const minCy = Math.min(...items.map((o) => o.p.cy));
|
|
48351
|
+
const maxCy = Math.max(...items.map((o) => o.p.cy));
|
|
48352
|
+
const diag = Math.hypot(right - left, maxCy - minCy);
|
|
48353
|
+
if (diag > maxExtent || items.length > MAX_COLUMN_ROWS) {
|
|
48354
|
+
items.forEach((o) => pushHidden(o.p));
|
|
48355
|
+
} else {
|
|
48356
|
+
clusterPending.push(items);
|
|
48357
|
+
}
|
|
48358
|
+
}
|
|
48359
|
+
for (const items of clusterPending) {
|
|
48360
|
+
const side = ["right", "left"].find(
|
|
48361
|
+
(s) => wouldColumnBeClean(items, s)
|
|
48362
|
+
);
|
|
48363
|
+
if (side) commitColumn(items, side);
|
|
48364
|
+
else items.forEach((o) => pushHidden(o.p));
|
|
48365
|
+
}
|
|
48366
|
+
}
|
|
48367
|
+
if (resolved.directives.noContextLabels !== true) {
|
|
48368
|
+
for (const l of labels) {
|
|
48369
|
+
if (l.hidden) continue;
|
|
48370
|
+
const w = labelW(l.text);
|
|
48371
|
+
const x = l.anchor === "start" ? l.x : l.anchor === "end" ? l.x - w : l.x - w / 2;
|
|
48372
|
+
obstacles.push({ x, y: l.y - labelH / 2, w, h: labelH });
|
|
48373
|
+
}
|
|
48374
|
+
for (const box of insets)
|
|
48375
|
+
obstacles.push({ x: box.x, y: box.y, w: box.w, h: box.h });
|
|
48376
|
+
const countryCandidates = [];
|
|
48377
|
+
for (const f of worldLayer.values()) {
|
|
48378
|
+
const iso = typeof f.id === "string" ? f.id : String(f.id ?? "");
|
|
48379
|
+
if (!iso || regionById.has(iso)) continue;
|
|
48380
|
+
let hasReferencedSub = false;
|
|
48381
|
+
for (const k of regionById.keys())
|
|
48382
|
+
if (k.startsWith(iso + "-")) {
|
|
48383
|
+
hasReferencedSub = true;
|
|
48384
|
+
break;
|
|
47143
48385
|
}
|
|
48386
|
+
if (hasReferencedSub) continue;
|
|
48387
|
+
const b = path.bounds(f);
|
|
48388
|
+
const [x0, y0] = b[0];
|
|
48389
|
+
const [x1, y1] = b[1];
|
|
48390
|
+
if (!Number.isFinite(x0) || !Number.isFinite(x1)) continue;
|
|
48391
|
+
const anchorLngLat = WORLD_LABEL_ANCHORS[iso];
|
|
48392
|
+
const a = anchorLngLat ? project(anchorLngLat[0], anchorLngLat[1]) : path.centroid(f);
|
|
48393
|
+
countryCandidates.push({
|
|
48394
|
+
name: f.properties?.name ?? iso,
|
|
48395
|
+
bbox: [x0, y0, x1, y1],
|
|
48396
|
+
anchor: a && Number.isFinite(a[0]) ? [a[0], a[1]] : null
|
|
48397
|
+
});
|
|
48398
|
+
}
|
|
48399
|
+
const framedStateContainers = (resolved.poiFrameContainers ?? []).some(
|
|
48400
|
+
(id) => id.startsWith("US-")
|
|
48401
|
+
);
|
|
48402
|
+
if (usLayer && framedStateContainers) {
|
|
48403
|
+
const containerSet = new Set(resolved.poiFrameContainers);
|
|
48404
|
+
for (const [iso, f] of usLayer) {
|
|
48405
|
+
if (containerSet.has(iso) || regionById.has(iso)) continue;
|
|
48406
|
+
const viewF = cullFeatureToView(f);
|
|
48407
|
+
if (!viewF) continue;
|
|
48408
|
+
const b = path.bounds(viewF);
|
|
48409
|
+
const [x0, y0] = b[0];
|
|
48410
|
+
const [x1, y1] = b[1];
|
|
48411
|
+
if (!Number.isFinite(x0) || !Number.isFinite(x1)) continue;
|
|
48412
|
+
const a = path.centroid(viewF);
|
|
48413
|
+
countryCandidates.push({
|
|
48414
|
+
name: f.properties?.name ?? iso,
|
|
48415
|
+
bbox: [x0, y0, x1, y1],
|
|
48416
|
+
anchor: a && Number.isFinite(a[0]) ? [a[0], a[1]] : null
|
|
48417
|
+
});
|
|
47144
48418
|
}
|
|
47145
|
-
placeColumn(g);
|
|
47146
48419
|
}
|
|
48420
|
+
const contextLabels = placeContextLabels({
|
|
48421
|
+
projection: resolved.projection,
|
|
48422
|
+
dLonSpan,
|
|
48423
|
+
dLatSpan,
|
|
48424
|
+
width,
|
|
48425
|
+
height,
|
|
48426
|
+
waterBodies: data.waterBodies,
|
|
48427
|
+
countries: countryCandidates,
|
|
48428
|
+
palette,
|
|
48429
|
+
project,
|
|
48430
|
+
collides,
|
|
48431
|
+
// Water labels must stay over open water — `fillAt` returns the ocean
|
|
48432
|
+
// backdrop colour off-land and a region fill on-land (lakes/states count
|
|
48433
|
+
// as land here, which is the safe side for an ocean name).
|
|
48434
|
+
overLand: (x, y) => fillAt(x, y) !== water
|
|
48435
|
+
});
|
|
48436
|
+
labels.push(...contextLabels);
|
|
47147
48437
|
}
|
|
47148
48438
|
let legend = null;
|
|
47149
48439
|
if (!resolved.directives.noLegend) {
|
|
@@ -47180,25 +48470,31 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47180
48470
|
rivers,
|
|
47181
48471
|
relief,
|
|
47182
48472
|
reliefHatch,
|
|
48473
|
+
coastlineStyle,
|
|
47183
48474
|
legs,
|
|
47184
48475
|
pois,
|
|
48476
|
+
clusters,
|
|
47185
48477
|
labels,
|
|
47186
48478
|
legend,
|
|
47187
48479
|
insets,
|
|
47188
48480
|
insetRegions,
|
|
47189
48481
|
projection,
|
|
47190
|
-
stretch: stretchParams
|
|
48482
|
+
stretch: stretchParams,
|
|
48483
|
+
diagnostics: []
|
|
47191
48484
|
};
|
|
47192
48485
|
}
|
|
47193
|
-
var FIT_PAD, RAMP_FLOOR, R_DEFAULT, R_MIN, R_MAX, W_MIN, W_MAX,
|
|
48486
|
+
var FIT_PAD, RAMP_FLOOR, R_DEFAULT, R_MIN, R_MAX, W_MIN, W_MAX, FONT2, 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;
|
|
47194
48487
|
var init_layout15 = __esm({
|
|
47195
48488
|
"src/map/layout.ts"() {
|
|
47196
48489
|
"use strict";
|
|
47197
48490
|
init_color_utils();
|
|
48491
|
+
init_geo();
|
|
48492
|
+
init_colorize();
|
|
47198
48493
|
init_colors();
|
|
47199
48494
|
init_label_layout();
|
|
47200
48495
|
init_legend_constants();
|
|
47201
48496
|
init_title_constants();
|
|
48497
|
+
init_context_labels();
|
|
47202
48498
|
FIT_PAD = 24;
|
|
47203
48499
|
RAMP_FLOOR = 15;
|
|
47204
48500
|
R_DEFAULT = 6;
|
|
@@ -47206,32 +48502,66 @@ var init_layout15 = __esm({
|
|
|
47206
48502
|
R_MAX = 22;
|
|
47207
48503
|
W_MIN = 1.25;
|
|
47208
48504
|
W_MAX = 8;
|
|
47209
|
-
|
|
47210
|
-
|
|
48505
|
+
FONT2 = 11;
|
|
48506
|
+
MAX_CLUSTER_EXTENT_FACTOR = 0.18;
|
|
48507
|
+
MAX_COLUMN_ROWS = 7;
|
|
48508
|
+
REGION_LABEL_HALO_RATIO = 4.5;
|
|
47211
48509
|
LAND_TINT_LIGHT = 12;
|
|
47212
48510
|
LAND_TINT_DARK = 24;
|
|
47213
48511
|
TAG_TINT_LIGHT = 60;
|
|
47214
48512
|
TAG_TINT_DARK = 68;
|
|
47215
|
-
WATER_TINT_LIGHT =
|
|
47216
|
-
WATER_TINT_DARK =
|
|
48513
|
+
WATER_TINT_LIGHT = 24;
|
|
48514
|
+
WATER_TINT_DARK = 24;
|
|
47217
48515
|
RIVER_WIDTH = 1.3;
|
|
48516
|
+
COMPACT_WIDTH_PX = 480;
|
|
47218
48517
|
RELIEF_MIN_AREA = 12;
|
|
47219
48518
|
RELIEF_MIN_DIM = 2;
|
|
47220
|
-
RELIEF_HATCH_SPACING =
|
|
47221
|
-
RELIEF_HATCH_WIDTH = 0.
|
|
48519
|
+
RELIEF_HATCH_SPACING = 2;
|
|
48520
|
+
RELIEF_HATCH_WIDTH = 0.15;
|
|
47222
48521
|
RELIEF_HATCH_STRENGTH = 32;
|
|
48522
|
+
COASTLINE_RING_COUNT = 5;
|
|
48523
|
+
COASTLINE_D0 = 16e-4;
|
|
48524
|
+
COASTLINE_STEP = 28e-4;
|
|
48525
|
+
COASTLINE_THICKNESS = 14e-4;
|
|
48526
|
+
COASTLINE_OPACITY_NEAR = 0.5;
|
|
48527
|
+
COASTLINE_OPACITY_FAR = 0.1;
|
|
48528
|
+
COASTLINE_MIN_EXTENT = 6e-4;
|
|
48529
|
+
COASTLINE_MIN_EXTENT_GLOBAL = 6e-4;
|
|
48530
|
+
COASTLINE_STROKE_MIX = 32;
|
|
47223
48531
|
FOREIGN_TINT_LIGHT = 30;
|
|
47224
48532
|
FOREIGN_TINT_DARK = 62;
|
|
47225
48533
|
MUTED_FOREIGN_LIGHT = 28;
|
|
47226
48534
|
MUTED_FOREIGN_DARK = 16;
|
|
47227
48535
|
COLO_R = 9;
|
|
47228
48536
|
GOLDEN_ANGLE = 2.399963229728653;
|
|
48537
|
+
STACK_OVERLAP = 1;
|
|
48538
|
+
STACK_RING_MAX = 8;
|
|
48539
|
+
STACK_RING_GAP = 4;
|
|
47229
48540
|
FAN_STEP = 16;
|
|
47230
48541
|
ARC_CURVE_FRAC = 0.18;
|
|
48542
|
+
decodeCache = /* @__PURE__ */ new WeakMap();
|
|
47231
48543
|
usConusProjection = () => geoConicEqualArea().parallels([29.5, 45.5]).rotate([96, 0]);
|
|
47232
48544
|
alaskaProjection = () => geoConicEqualArea().rotate([154, 0]).center([-2, 58.5]).parallels([55, 65]);
|
|
47233
48545
|
hawaiiProjection = () => geoMercator();
|
|
47234
48546
|
INSET_STATES = /* @__PURE__ */ new Set(["US-AK", "US-HI"]);
|
|
48547
|
+
inAlaska = (lon, lat) => lat >= 51 && (lon <= -129 || lon >= 172);
|
|
48548
|
+
inHawaii = (lon, lat) => lat >= 18 && lat <= 23 && lon >= -161 && lon <= -154;
|
|
48549
|
+
FOREIGN_BORDER = {
|
|
48550
|
+
CA: [
|
|
48551
|
+
"US-AK",
|
|
48552
|
+
"US-WA",
|
|
48553
|
+
"US-ID",
|
|
48554
|
+
"US-MT",
|
|
48555
|
+
"US-ND",
|
|
48556
|
+
"US-MN",
|
|
48557
|
+
"US-MI",
|
|
48558
|
+
"US-NY",
|
|
48559
|
+
"US-VT",
|
|
48560
|
+
"US-NH",
|
|
48561
|
+
"US-ME"
|
|
48562
|
+
],
|
|
48563
|
+
MX: ["US-CA", "US-AZ", "US-NM", "US-TX"]
|
|
48564
|
+
};
|
|
47235
48565
|
US_NON_CONUS = /* @__PURE__ */ new Set([
|
|
47236
48566
|
"US-AK",
|
|
47237
48567
|
"US-HI",
|
|
@@ -47251,6 +48581,58 @@ __export(renderer_exports16, {
|
|
|
47251
48581
|
renderMapForExport: () => renderMapForExport
|
|
47252
48582
|
});
|
|
47253
48583
|
import * as d3Selection18 from "d3-selection";
|
|
48584
|
+
function pointInRing2(px, py, ring) {
|
|
48585
|
+
let inside = false;
|
|
48586
|
+
for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
|
|
48587
|
+
const [xi, yi] = ring[i];
|
|
48588
|
+
const [xj, yj] = ring[j];
|
|
48589
|
+
if (yi > py !== yj > py && px < (xj - xi) * (py - yi) / (yj - yi) + xi)
|
|
48590
|
+
inside = !inside;
|
|
48591
|
+
}
|
|
48592
|
+
return inside;
|
|
48593
|
+
}
|
|
48594
|
+
function ringToPath(ring) {
|
|
48595
|
+
let d = "";
|
|
48596
|
+
for (let i = 0; i < ring.length; i++)
|
|
48597
|
+
d += (i ? "L" : "M") + ring[i][0] + "," + ring[i][1];
|
|
48598
|
+
return d + "Z";
|
|
48599
|
+
}
|
|
48600
|
+
function coastlineOuterRings(regions, minExtent) {
|
|
48601
|
+
const paths = [];
|
|
48602
|
+
for (const r of regions) {
|
|
48603
|
+
const rings = parsePathRings(r.d);
|
|
48604
|
+
for (let i = 0; i < rings.length; i++) {
|
|
48605
|
+
const ring = rings[i];
|
|
48606
|
+
if (ring.length < 3) continue;
|
|
48607
|
+
let minX = Infinity;
|
|
48608
|
+
let minY = Infinity;
|
|
48609
|
+
let maxX = -Infinity;
|
|
48610
|
+
let maxY = -Infinity;
|
|
48611
|
+
for (const [x, y] of ring) {
|
|
48612
|
+
if (x < minX) minX = x;
|
|
48613
|
+
if (x > maxX) maxX = x;
|
|
48614
|
+
if (y < minY) minY = y;
|
|
48615
|
+
if (y > maxY) maxY = y;
|
|
48616
|
+
}
|
|
48617
|
+
if (Math.max(maxX - minX, maxY - minY) < minExtent) continue;
|
|
48618
|
+
const [fx, fy] = ring[0];
|
|
48619
|
+
let depth = 0;
|
|
48620
|
+
for (let j = 0; j < rings.length; j++)
|
|
48621
|
+
if (j !== i && pointInRing2(fx, fy, rings[j])) depth++;
|
|
48622
|
+
if (depth % 2 === 1) continue;
|
|
48623
|
+
paths.push(ringToPath(ring));
|
|
48624
|
+
}
|
|
48625
|
+
}
|
|
48626
|
+
return paths;
|
|
48627
|
+
}
|
|
48628
|
+
function appendWaterLines(g, outerRings, style, flatWater) {
|
|
48629
|
+
const d = outerRings.join(" ");
|
|
48630
|
+
const linesOuterFirst = [...style.lines].sort((a, b) => b.d - a.d);
|
|
48631
|
+
for (const line12 of linesOuterFirst) {
|
|
48632
|
+
g.append("path").attr("d", d).attr("stroke", style.color).attr("stroke-width", 2 * (line12.d + line12.thickness)).attr("stroke-opacity", line12.opacity).attr("stroke-linejoin", "round").attr("stroke-linecap", "round");
|
|
48633
|
+
g.append("path").attr("d", d).attr("stroke", flatWater).attr("stroke-width", 2 * line12.d).attr("stroke-linejoin", "round").attr("stroke-linecap", "round");
|
|
48634
|
+
}
|
|
48635
|
+
}
|
|
47254
48636
|
function renderMap(container, resolved, data, palette, isDark, onClickItem, exportDims, activeGroupOverride) {
|
|
47255
48637
|
d3Selection18.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
47256
48638
|
const width = exportDims?.width ?? container.clientWidth;
|
|
@@ -47263,6 +48645,11 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47263
48645
|
{
|
|
47264
48646
|
palette,
|
|
47265
48647
|
isDark,
|
|
48648
|
+
// Export-only: forward the contain-fit request from mapExportDimensions so a
|
|
48649
|
+
// clamped/floored (off-aspect) export canvas letterboxes instead of
|
|
48650
|
+
// stretch-distorting. The in-app preview pane passes no exportDims → unset →
|
|
48651
|
+
// keeps the global stretch-fill.
|
|
48652
|
+
preferContain: exportDims?.preferContain ?? false,
|
|
47266
48653
|
...activeGroupOverride !== void 0 && {
|
|
47267
48654
|
activeGroup: activeGroupOverride
|
|
47268
48655
|
}
|
|
@@ -47276,6 +48663,7 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47276
48663
|
const gRegions = svg.append("g").attr("class", "dgmo-map-regions");
|
|
47277
48664
|
const drawRegion = (g, r, strokeWidth) => {
|
|
47278
48665
|
const p = g.append("path").attr("d", r.d).attr("fill", r.fill).attr("stroke", r.stroke).attr("stroke-width", strokeWidth);
|
|
48666
|
+
if (r.label) p.attr("data-region-name", r.label);
|
|
47279
48667
|
if (r.layer !== "base") {
|
|
47280
48668
|
p.classed("dgmo-map-region", true).attr("data-region", r.id);
|
|
47281
48669
|
if (r.value !== void 0) p.attr("data-value", r.value);
|
|
@@ -47310,6 +48698,38 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47310
48698
|
gRelief.append("line").attr("x1", 0).attr("y1", y).attr("x2", width).attr("y2", y);
|
|
47311
48699
|
}
|
|
47312
48700
|
}
|
|
48701
|
+
if (layout.coastlineStyle) {
|
|
48702
|
+
const cs = layout.coastlineStyle;
|
|
48703
|
+
const maskId = "dgmo-map-water-mask";
|
|
48704
|
+
const mask = defs.append("mask").attr("id", maskId).attr("maskUnits", "userSpaceOnUse").attr("x", 0).attr("y", 0).attr("width", width).attr("height", height);
|
|
48705
|
+
mask.append("rect").attr("x", 0).attr("y", 0).attr("width", width).attr("height", height).attr("fill", "white");
|
|
48706
|
+
const landD = layout.regions.filter((r) => r.id !== "lake").map((r) => r.d).join(" ");
|
|
48707
|
+
const lakeD = layout.regions.filter((r) => r.id === "lake").map((r) => r.d).join(" ");
|
|
48708
|
+
if (landD) mask.append("path").attr("d", landD).attr("fill", "black");
|
|
48709
|
+
if (lakeD) mask.append("path").attr("d", lakeD).attr("fill", "white");
|
|
48710
|
+
if (layout.insets.length) {
|
|
48711
|
+
const reach = Math.max(0, ...cs.lines.map((l) => l.d + l.thickness));
|
|
48712
|
+
for (const box of layout.insets) {
|
|
48713
|
+
const d = box.points.map((p, i) => `${i ? "L" : "M"}${p[0]},${p[1]}`).join("") + "Z";
|
|
48714
|
+
mask.append("path").attr("d", d).attr("fill", "black").attr("stroke", "black").attr("stroke-width", 2 * reach).attr("stroke-linejoin", "round");
|
|
48715
|
+
}
|
|
48716
|
+
}
|
|
48717
|
+
const gWater = svg.append("g").attr("class", "dgmo-map-water-lines").attr("fill", "none").attr("mask", `url(#${maskId})`);
|
|
48718
|
+
appendWaterLines(
|
|
48719
|
+
gWater,
|
|
48720
|
+
coastlineOuterRings(layout.regions, cs.minExtent),
|
|
48721
|
+
cs,
|
|
48722
|
+
layout.background
|
|
48723
|
+
);
|
|
48724
|
+
const byStroke = /* @__PURE__ */ new Map();
|
|
48725
|
+
for (const r of layout.regions) {
|
|
48726
|
+
const arr = byStroke.get(r.stroke);
|
|
48727
|
+
if (arr) arr.push(r.d);
|
|
48728
|
+
else byStroke.set(r.stroke, [r.d]);
|
|
48729
|
+
}
|
|
48730
|
+
for (const [stroke2, ds] of byStroke)
|
|
48731
|
+
gWater.append("path").attr("d", ds.join(" ")).attr("stroke", stroke2).attr("stroke-width", 0.5).attr("stroke-linejoin", "round");
|
|
48732
|
+
}
|
|
47313
48733
|
if (layout.rivers.length) {
|
|
47314
48734
|
const gRivers = svg.append("g").attr("class", "dgmo-map-rivers").attr("fill", "none");
|
|
47315
48735
|
for (const r of layout.rivers) {
|
|
@@ -47318,15 +48738,61 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47318
48738
|
}
|
|
47319
48739
|
if (layout.insets.length) {
|
|
47320
48740
|
const insetG = svg.append("g").attr("class", "dgmo-map-insets");
|
|
47321
|
-
|
|
48741
|
+
layout.insets.forEach((box, bi) => {
|
|
47322
48742
|
const d = box.points.map((p, i) => `${i ? "L" : "M"}${p[0]},${p[1]}`).join("") + "Z";
|
|
47323
48743
|
insetG.append("path").attr("d", d).attr("fill", layout.background).attr("stroke", mix(palette.text, palette.bg, 55)).attr("stroke-width", 1).attr("stroke-linejoin", "round");
|
|
47324
|
-
|
|
48744
|
+
if (box.contextLand) {
|
|
48745
|
+
const clipId = `dgmo-map-inset-clip-${bi}`;
|
|
48746
|
+
defs.append("clipPath").attr("id", clipId).append("path").attr("d", d);
|
|
48747
|
+
insetG.append("path").attr("d", box.contextLand.d).attr("fill", box.contextLand.fill).attr("clip-path", `url(#${clipId})`);
|
|
48748
|
+
}
|
|
48749
|
+
});
|
|
47325
48750
|
for (const r of layout.insetRegions) drawRegion(insetG, r, 0.5);
|
|
47326
|
-
|
|
48751
|
+
if (layout.coastlineStyle) {
|
|
48752
|
+
const cs = layout.coastlineStyle;
|
|
48753
|
+
const maskId = "dgmo-map-inset-water-mask";
|
|
48754
|
+
const mask = defs.append("mask").attr("id", maskId).attr("maskUnits", "userSpaceOnUse").attr("x", 0).attr("y", 0).attr("width", width).attr("height", height);
|
|
48755
|
+
for (const box of layout.insets) {
|
|
48756
|
+
const d = box.points.map((p, i) => `${i ? "L" : "M"}${p[0]},${p[1]}`).join("") + "Z";
|
|
48757
|
+
mask.append("path").attr("d", d).attr("fill", "white");
|
|
48758
|
+
}
|
|
48759
|
+
layout.insets.forEach((box, bi) => {
|
|
48760
|
+
if (box.contextLand)
|
|
48761
|
+
mask.append("path").attr("d", box.contextLand.d).attr("fill", "black").attr("clip-path", `url(#dgmo-map-inset-clip-${bi})`);
|
|
48762
|
+
});
|
|
48763
|
+
for (const r of layout.insetRegions)
|
|
48764
|
+
if (r.id !== "lake")
|
|
48765
|
+
mask.append("path").attr("d", r.d).attr("fill", "black");
|
|
48766
|
+
for (const r of layout.insetRegions)
|
|
48767
|
+
if (r.id === "lake")
|
|
48768
|
+
mask.append("path").attr("d", r.d).attr("fill", "white");
|
|
48769
|
+
const clipId = "dgmo-map-inset-water-clip";
|
|
48770
|
+
const clip = defs.append("clipPath").attr("id", clipId);
|
|
48771
|
+
for (const box of layout.insets) {
|
|
48772
|
+
const d = box.points.map((p, i) => `${i ? "L" : "M"}${p[0]},${p[1]}`).join("") + "Z";
|
|
48773
|
+
clip.append("path").attr("d", d);
|
|
48774
|
+
}
|
|
48775
|
+
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})`);
|
|
48776
|
+
appendWaterLines(
|
|
48777
|
+
gInsetWater,
|
|
48778
|
+
coastlineOuterRings(layout.insetRegions, cs.minExtent),
|
|
48779
|
+
cs,
|
|
48780
|
+
layout.background
|
|
48781
|
+
);
|
|
48782
|
+
for (const r of layout.insetRegions)
|
|
48783
|
+
gInsetWater.append("path").attr("d", r.d).attr("stroke", r.stroke).attr("stroke-width", 0.5).attr("stroke-linejoin", "round");
|
|
48784
|
+
}
|
|
48785
|
+
}
|
|
48786
|
+
const wireSync = (sel, lineNumber) => {
|
|
48787
|
+
if (lineNumber < 1) return;
|
|
48788
|
+
sel.attr("data-line-number", lineNumber);
|
|
48789
|
+
if (onClickItem)
|
|
48790
|
+
sel.style("cursor", "pointer").on("click", () => onClickItem(lineNumber));
|
|
48791
|
+
};
|
|
47327
48792
|
const gLegs = svg.append("g").attr("class", "dgmo-map-legs").attr("fill", "none");
|
|
47328
48793
|
layout.legs.forEach((leg, i) => {
|
|
47329
48794
|
const p = gLegs.append("path").attr("d", leg.d).attr("stroke", leg.color).attr("stroke-width", leg.width).attr("stroke-linecap", "round");
|
|
48795
|
+
wireSync(p, leg.lineNumber);
|
|
47330
48796
|
if (leg.arrow) {
|
|
47331
48797
|
const id = `dgmo-map-arrow-${i}`;
|
|
47332
48798
|
const s = arrowSize(leg.width);
|
|
@@ -47334,25 +48800,38 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47334
48800
|
p.attr("marker-end", `url(#${id})`);
|
|
47335
48801
|
}
|
|
47336
48802
|
if (leg.label !== void 0 && leg.labelX !== void 0) {
|
|
47337
|
-
emitText(
|
|
48803
|
+
const lt = emitText(
|
|
47338
48804
|
gLegs,
|
|
47339
48805
|
leg.labelX,
|
|
47340
48806
|
leg.labelY ?? 0,
|
|
47341
48807
|
leg.label,
|
|
47342
48808
|
"middle",
|
|
47343
|
-
palette.textMuted,
|
|
47344
|
-
haloColor,
|
|
47345
|
-
true,
|
|
48809
|
+
leg.labelColor ?? palette.textMuted,
|
|
48810
|
+
leg.labelHaloColor ?? haloColor,
|
|
48811
|
+
leg.labelHalo ?? true,
|
|
47346
48812
|
LABEL_FONT - 1
|
|
47347
48813
|
);
|
|
48814
|
+
wireSync(lt, leg.lineNumber);
|
|
47348
48815
|
}
|
|
47349
48816
|
});
|
|
48817
|
+
const gSpider = svg.append("g").attr("class", "dgmo-map-spider");
|
|
48818
|
+
for (const cl of layout.clusters) {
|
|
48819
|
+
if (!exportDims) {
|
|
48820
|
+
gSpider.append("circle").attr("cx", cl.cx).attr("cy", cl.cy).attr("r", cl.hitR).attr("fill", "transparent").attr("data-cluster-hit", cl.id).style("cursor", "pointer");
|
|
48821
|
+
}
|
|
48822
|
+
for (const leg of cl.legs) {
|
|
48823
|
+
gSpider.append("line").attr("x1", cl.cx).attr("y1", cl.cy).attr("x2", leg.x2).attr("y2", leg.y2).attr("stroke", leg.color).attr("stroke-width", 1).attr("data-cluster-deco", cl.id).style("pointer-events", "none");
|
|
48824
|
+
}
|
|
48825
|
+
gSpider.append("circle").attr("cx", cl.cx).attr("cy", cl.cy).attr("r", 2).attr("fill", mix(palette.textMuted, palette.bg, 40)).attr("data-cluster-deco", cl.id).style("pointer-events", "none");
|
|
48826
|
+
}
|
|
47350
48827
|
const gPois = svg.append("g").attr("class", "dgmo-map-pois");
|
|
47351
48828
|
for (const poi of layout.pois) {
|
|
47352
48829
|
if (poi.isOrigin) {
|
|
47353
48830
|
gPois.append("circle").attr("cx", poi.cx).attr("cy", poi.cy).attr("r", poi.r + 3).attr("fill", "none").attr("stroke", poi.stroke).attr("stroke-width", 1.5);
|
|
47354
48831
|
}
|
|
47355
48832
|
const c = gPois.append("circle").attr("cx", poi.cx).attr("cy", poi.cy).attr("r", poi.r).attr("fill", poi.fill).attr("stroke", poi.stroke).attr("stroke-width", 1).attr("data-line-number", poi.lineNumber).attr("data-poi", poi.id);
|
|
48833
|
+
if (poi.clusterId !== void 0)
|
|
48834
|
+
c.attr("data-cluster-member", poi.clusterId);
|
|
47356
48835
|
if (poi.tags) {
|
|
47357
48836
|
for (const [group, value] of Object.entries(poi.tags)) {
|
|
47358
48837
|
c.attr(`data-tag-${group.toLowerCase()}`, value.toLowerCase());
|
|
@@ -47380,12 +48859,32 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47380
48859
|
}
|
|
47381
48860
|
const gLabels = svg.append("g").attr("class", "dgmo-map-labels");
|
|
47382
48861
|
for (const lab of layout.labels) {
|
|
48862
|
+
if (lab.hidden) {
|
|
48863
|
+
if (exportDims) continue;
|
|
48864
|
+
emitText(
|
|
48865
|
+
gLabels,
|
|
48866
|
+
lab.x,
|
|
48867
|
+
lab.y,
|
|
48868
|
+
lab.text,
|
|
48869
|
+
lab.anchor,
|
|
48870
|
+
lab.color,
|
|
48871
|
+
lab.haloColor,
|
|
48872
|
+
lab.halo,
|
|
48873
|
+
LABEL_FONT,
|
|
48874
|
+
lab.italic,
|
|
48875
|
+
lab.letterSpacing
|
|
48876
|
+
).attr("data-poi", lab.poiId ?? null).attr("data-poi-hidden", "").style("opacity", 0).style("pointer-events", "none");
|
|
48877
|
+
continue;
|
|
48878
|
+
}
|
|
47383
48879
|
if (lab.leader) {
|
|
47384
48880
|
const line12 = gLabels.append("line").attr("x1", lab.leader.x1).attr("y1", lab.leader.y1).attr("x2", lab.leader.x2).attr("y2", lab.leader.y2).attr(
|
|
47385
48881
|
"stroke",
|
|
47386
48882
|
lab.leaderColor ?? mix(palette.textMuted, palette.bg, 60)
|
|
47387
48883
|
).attr("stroke-width", lab.leaderColor ? 1 : 0.75);
|
|
47388
48884
|
if (lab.poiId !== void 0) line12.attr("data-poi", lab.poiId);
|
|
48885
|
+
if (lab.clusterMember !== void 0)
|
|
48886
|
+
line12.attr("data-cluster-member", lab.clusterMember);
|
|
48887
|
+
wireSync(line12, lab.lineNumber);
|
|
47389
48888
|
}
|
|
47390
48889
|
const t = emitText(
|
|
47391
48890
|
gLabels,
|
|
@@ -47396,11 +48895,38 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47396
48895
|
lab.color,
|
|
47397
48896
|
lab.haloColor,
|
|
47398
48897
|
lab.halo,
|
|
47399
|
-
LABEL_FONT
|
|
48898
|
+
LABEL_FONT,
|
|
48899
|
+
lab.italic,
|
|
48900
|
+
lab.letterSpacing,
|
|
48901
|
+
lab.lines
|
|
47400
48902
|
);
|
|
47401
48903
|
if (lab.poiId !== void 0) {
|
|
47402
48904
|
t.attr("data-poi", lab.poiId).style("cursor", "default");
|
|
47403
48905
|
}
|
|
48906
|
+
if (lab.clusterMember !== void 0) {
|
|
48907
|
+
t.attr("data-cluster-member", lab.clusterMember);
|
|
48908
|
+
}
|
|
48909
|
+
wireSync(t, lab.lineNumber);
|
|
48910
|
+
}
|
|
48911
|
+
if (!exportDims && layout.clusters.length) {
|
|
48912
|
+
const gBadge = svg.append("g").attr("class", "dgmo-map-cluster-badges");
|
|
48913
|
+
for (const cl of layout.clusters) {
|
|
48914
|
+
const g = gBadge.append("g").attr("data-cluster", cl.id).style("opacity", 0).style("pointer-events", "none");
|
|
48915
|
+
const R = 9;
|
|
48916
|
+
g.append("circle").attr("cx", cl.cx).attr("cy", cl.cy).attr("r", R).attr("fill", mix(palette.textMuted, palette.bg, 35)).attr("stroke", palette.textMuted).attr("stroke-width", 1);
|
|
48917
|
+
g.append("circle").attr("cx", cl.cx).attr("cy", cl.cy).attr("r", R + 2.5).attr("fill", "none").attr("stroke", palette.textMuted).attr("stroke-width", 1);
|
|
48918
|
+
emitText(
|
|
48919
|
+
g,
|
|
48920
|
+
cl.cx,
|
|
48921
|
+
cl.cy + 3,
|
|
48922
|
+
String(cl.count),
|
|
48923
|
+
"middle",
|
|
48924
|
+
palette.text,
|
|
48925
|
+
palette.bg,
|
|
48926
|
+
false,
|
|
48927
|
+
LABEL_FONT
|
|
48928
|
+
);
|
|
48929
|
+
}
|
|
47404
48930
|
}
|
|
47405
48931
|
if (layout.legend) {
|
|
47406
48932
|
const legendY = (layout.title ? TITLE_Y + TITLE_FONT_SIZE : 0) + (layout.subtitle ? TITLE_FONT_SIZE : 0) + 8;
|
|
@@ -47437,7 +48963,7 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47437
48963
|
svg.append("text").attr("class", "dgmo-map-title").attr("x", width / 2).attr("y", TITLE_Y).attr("text-anchor", "middle").attr("font-size", TITLE_FONT_SIZE).attr("font-weight", TITLE_FONT_WEIGHT).attr("fill", palette.text).attr("paint-order", "stroke fill").attr("stroke", palette.bg).attr("stroke-width", 4).attr("stroke-linejoin", "round").attr("stroke-opacity", 0.7).text(layout.title);
|
|
47438
48964
|
}
|
|
47439
48965
|
if (layout.subtitle) {
|
|
47440
|
-
svg.append("text").attr("x", width / 2).attr("y", TITLE_Y + TITLE_FONT_SIZE).attr("text-anchor", "middle").attr("font-size", LABEL_FONT + 1).attr("fill", palette.textMuted).attr("paint-order", "stroke fill").attr("stroke", palette.bg).attr("stroke-width", 3).attr("stroke-linejoin", "round").attr("stroke-opacity", 0.7).text(layout.subtitle);
|
|
48966
|
+
svg.append("text").attr("class", "dgmo-map-subtitle").attr("x", width / 2).attr("y", TITLE_Y + TITLE_FONT_SIZE).attr("text-anchor", "middle").attr("font-size", LABEL_FONT + 1).attr("fill", palette.textMuted).attr("paint-order", "stroke fill").attr("stroke", palette.bg).attr("stroke-width", 3).attr("stroke-linejoin", "round").attr("stroke-opacity", 0.7).text(layout.subtitle);
|
|
47441
48967
|
}
|
|
47442
48968
|
if (layout.caption) {
|
|
47443
48969
|
svg.append("text").attr("x", width / 2).attr("y", height - 8).attr("text-anchor", "middle").attr("font-size", LABEL_FONT).attr("fill", palette.textMuted).attr("paint-order", "stroke fill").attr("stroke", palette.bg).attr("stroke-width", 3).attr("stroke-linejoin", "round").attr("stroke-opacity", 0.7).text(layout.caption);
|
|
@@ -47446,10 +48972,21 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47446
48972
|
function renderMapForExport(container, resolved, data, palette, isDark, exportDims) {
|
|
47447
48973
|
renderMap(container, resolved, data, palette, isDark, void 0, exportDims);
|
|
47448
48974
|
}
|
|
47449
|
-
function emitText(g, x, y, text, anchor, color, halo, withHalo, fontSize) {
|
|
47450
|
-
const t = g.append("text").attr("x", x).attr("y", y).attr("text-anchor", anchor).attr("font-size", fontSize).attr("fill", color)
|
|
48975
|
+
function emitText(g, x, y, text, anchor, color, halo, withHalo, fontSize, italic, letterSpacing, lines) {
|
|
48976
|
+
const t = g.append("text").attr("x", x).attr("y", y).attr("text-anchor", anchor).attr("font-size", fontSize).attr("fill", color);
|
|
48977
|
+
if (lines && lines.length > 1) {
|
|
48978
|
+
const lineHeight = fontSize + 2;
|
|
48979
|
+
const startDy = -((lines.length - 1) / 2) * lineHeight;
|
|
48980
|
+
lines.forEach((ln, i) => {
|
|
48981
|
+
t.append("tspan").attr("x", x).attr("dy", i === 0 ? startDy : lineHeight).text(ln);
|
|
48982
|
+
});
|
|
48983
|
+
} else {
|
|
48984
|
+
t.text(text);
|
|
48985
|
+
}
|
|
48986
|
+
if (italic) t.attr("font-style", "italic");
|
|
48987
|
+
if (letterSpacing) t.attr("letter-spacing", letterSpacing);
|
|
47451
48988
|
if (withHalo) {
|
|
47452
|
-
t.attr("paint-order", "stroke fill").attr("stroke", halo).attr("stroke-width",
|
|
48989
|
+
t.attr("paint-order", "stroke fill").attr("stroke", halo).attr("stroke-width", 2).attr("stroke-linejoin", "round").attr("stroke-linecap", "round").attr("stroke-opacity", 0.55);
|
|
47453
48990
|
}
|
|
47454
48991
|
return t;
|
|
47455
48992
|
}
|
|
@@ -47466,6 +49003,56 @@ var init_renderer16 = __esm({
|
|
|
47466
49003
|
}
|
|
47467
49004
|
});
|
|
47468
49005
|
|
|
49006
|
+
// src/map/dimensions.ts
|
|
49007
|
+
var dimensions_exports = {};
|
|
49008
|
+
__export(dimensions_exports, {
|
|
49009
|
+
mapContentAspect: () => mapContentAspect,
|
|
49010
|
+
mapExportDimensions: () => mapExportDimensions
|
|
49011
|
+
});
|
|
49012
|
+
import { geoPath as geoPath2 } from "d3-geo";
|
|
49013
|
+
function mapContentAspect(resolved, data, ref = REF) {
|
|
49014
|
+
const { projection, fitTarget } = buildMapProjection(resolved, data);
|
|
49015
|
+
projection.fitSize([ref, ref], fitTarget);
|
|
49016
|
+
const b = geoPath2(projection).bounds(fitTarget);
|
|
49017
|
+
const w = b[1][0] - b[0][0];
|
|
49018
|
+
const h = b[1][1] - b[0][1];
|
|
49019
|
+
const aspect = w / h;
|
|
49020
|
+
return Number.isFinite(aspect) && aspect > 0 ? aspect : FALLBACK_ASPECT;
|
|
49021
|
+
}
|
|
49022
|
+
function mapExportDimensions(resolved, data, baseWidth = 1200) {
|
|
49023
|
+
const raw = mapContentAspect(resolved, data);
|
|
49024
|
+
const clamped = Math.max(ASPECT_MIN, Math.min(ASPECT_MAX, raw));
|
|
49025
|
+
const width = baseWidth;
|
|
49026
|
+
let height = Math.round(width / clamped);
|
|
49027
|
+
let chromeReserve = 0;
|
|
49028
|
+
if (resolved.title && resolved.pois.length > 0) {
|
|
49029
|
+
const bannerBottom = (resolved.subtitle ? TITLE_Y + TITLE_FONT_SIZE : TITLE_Y) + TITLE_FONT_SIZE / 2;
|
|
49030
|
+
chromeReserve += Math.max(FIT_PAD2, bannerBottom + TITLE_GAP) - FIT_PAD2;
|
|
49031
|
+
}
|
|
49032
|
+
let floored = false;
|
|
49033
|
+
if (height - chromeReserve < MIN_MAP_BAND) {
|
|
49034
|
+
height = Math.round(chromeReserve + MIN_MAP_BAND);
|
|
49035
|
+
floored = true;
|
|
49036
|
+
}
|
|
49037
|
+
const preferContain = clamped !== raw || floored;
|
|
49038
|
+
return { width, height, preferContain };
|
|
49039
|
+
}
|
|
49040
|
+
var FIT_PAD2, TITLE_GAP, ASPECT_MAX, ASPECT_MIN, MIN_MAP_BAND, FALLBACK_ASPECT, REF;
|
|
49041
|
+
var init_dimensions = __esm({
|
|
49042
|
+
"src/map/dimensions.ts"() {
|
|
49043
|
+
"use strict";
|
|
49044
|
+
init_title_constants();
|
|
49045
|
+
init_layout15();
|
|
49046
|
+
FIT_PAD2 = 24;
|
|
49047
|
+
TITLE_GAP = 16;
|
|
49048
|
+
ASPECT_MAX = 3;
|
|
49049
|
+
ASPECT_MIN = 0.9;
|
|
49050
|
+
MIN_MAP_BAND = 200;
|
|
49051
|
+
FALLBACK_ASPECT = 1.5;
|
|
49052
|
+
REF = 1e3;
|
|
49053
|
+
}
|
|
49054
|
+
});
|
|
49055
|
+
|
|
47469
49056
|
// src/map/load-data.ts
|
|
47470
49057
|
var load_data_exports = {};
|
|
47471
49058
|
__export(load_data_exports, {
|
|
@@ -47524,12 +49111,17 @@ function loadMapData() {
|
|
|
47524
49111
|
mountainRanges,
|
|
47525
49112
|
naLand,
|
|
47526
49113
|
naLakes,
|
|
49114
|
+
waterBodies,
|
|
47527
49115
|
gazetteer
|
|
47528
49116
|
] = await Promise.all([
|
|
49117
|
+
// worldCoarse (110m) is LOAD-BEARING but NOT a render source: the world
|
|
49118
|
+
// basemap renders from worldDetail (50m) at all scales (resolver pins
|
|
49119
|
+
// basemaps.world = 'detail'). Coarse stays as the authoritative region
|
|
49120
|
+
// name index + dominant-landmass bbox source in resolver.ts. Do not drop it.
|
|
47529
49121
|
readJson(nb, dir, FILES.worldCoarse),
|
|
47530
49122
|
readJson(nb, dir, FILES.worldDetail),
|
|
47531
49123
|
readJson(nb, dir, FILES.usStates),
|
|
47532
|
-
// Lakes/rivers/mountain/NA assets are optional — older bundles may predate them.
|
|
49124
|
+
// Lakes/rivers/mountain/NA/water assets are optional — older bundles may predate them.
|
|
47533
49125
|
readJson(nb, dir, FILES.lakes).catch(() => void 0),
|
|
47534
49126
|
readJson(nb, dir, FILES.rivers).catch(() => void 0),
|
|
47535
49127
|
readJson(nb, dir, FILES.mountainRanges).catch(
|
|
@@ -47537,6 +49129,7 @@ function loadMapData() {
|
|
|
47537
49129
|
),
|
|
47538
49130
|
readJson(nb, dir, FILES.naLand).catch(() => void 0),
|
|
47539
49131
|
readJson(nb, dir, FILES.naLakes).catch(() => void 0),
|
|
49132
|
+
readJson(nb, dir, FILES.waterBodies).catch(() => void 0),
|
|
47540
49133
|
readJson(nb, dir, FILES.gazetteer)
|
|
47541
49134
|
]);
|
|
47542
49135
|
return validate({
|
|
@@ -47548,7 +49141,8 @@ function loadMapData() {
|
|
|
47548
49141
|
...rivers && { rivers },
|
|
47549
49142
|
...mountainRanges && { mountainRanges },
|
|
47550
49143
|
...naLand && { naLand },
|
|
47551
|
-
...naLakes && { naLakes }
|
|
49144
|
+
...naLakes && { naLakes },
|
|
49145
|
+
...waterBodies && { waterBodies }
|
|
47552
49146
|
});
|
|
47553
49147
|
})().catch((e) => {
|
|
47554
49148
|
cache = void 0;
|
|
@@ -47569,6 +49163,7 @@ var init_load_data = __esm({
|
|
|
47569
49163
|
mountainRanges: "mountain-ranges.json",
|
|
47570
49164
|
naLand: "na-land.json",
|
|
47571
49165
|
naLakes: "na-lakes.json",
|
|
49166
|
+
waterBodies: "water-bodies.json",
|
|
47572
49167
|
gazetteer: "gazetteer.json"
|
|
47573
49168
|
};
|
|
47574
49169
|
CANDIDATE_DIRS = [
|
|
@@ -49582,8 +51177,8 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
|
|
|
49582
51177
|
const lines = splitParticipantLabel(p.label, LABEL_MAX_CHARS);
|
|
49583
51178
|
if (lines.length === 0) continue;
|
|
49584
51179
|
const widest = Math.max(...lines.map((l) => l.length));
|
|
49585
|
-
const
|
|
49586
|
-
uniformBoxWidth = Math.max(uniformBoxWidth,
|
|
51180
|
+
const labelWidth2 = widest * LABEL_CHAR_WIDTH + 10;
|
|
51181
|
+
uniformBoxWidth = Math.max(uniformBoxWidth, labelWidth2);
|
|
49587
51182
|
}
|
|
49588
51183
|
uniformBoxWidth = Math.min(MAX_BOX_WIDTH, uniformBoxWidth);
|
|
49589
51184
|
const effectiveGap = Math.max(PARTICIPANT_GAP, uniformBoxWidth + 30);
|
|
@@ -52282,15 +53877,15 @@ function renderArcDiagram(container, parsed, palette, _isDark, onClickItem, expo
|
|
|
52282
53877
|
textColor,
|
|
52283
53878
|
onClickItem
|
|
52284
53879
|
);
|
|
52285
|
-
const
|
|
52286
|
-
for (const node of nodes)
|
|
53880
|
+
const neighbors2 = /* @__PURE__ */ new Map();
|
|
53881
|
+
for (const node of nodes) neighbors2.set(node, /* @__PURE__ */ new Set());
|
|
52287
53882
|
for (const link of links) {
|
|
52288
|
-
|
|
52289
|
-
|
|
53883
|
+
neighbors2.get(link.source).add(link.target);
|
|
53884
|
+
neighbors2.get(link.target).add(link.source);
|
|
52290
53885
|
}
|
|
52291
53886
|
const FADE_OPACITY3 = 0.1;
|
|
52292
53887
|
function handleMouseEnter(hovered) {
|
|
52293
|
-
const connected =
|
|
53888
|
+
const connected = neighbors2.get(hovered);
|
|
52294
53889
|
g.selectAll(".arc-link").each(function() {
|
|
52295
53890
|
const el = d3Selection23.select(this);
|
|
52296
53891
|
const src = el.attr("data-source");
|
|
@@ -54225,7 +55820,7 @@ function renderVenn(container, parsed, palette, _isDark, onClickItem, exportDims
|
|
|
54225
55820
|
8,
|
|
54226
55821
|
Math.floor(OVERLAP_WRAP_TARGET_W / OVERLAP_CH_W)
|
|
54227
55822
|
);
|
|
54228
|
-
function
|
|
55823
|
+
function wrapLabel3(text, maxChars) {
|
|
54229
55824
|
const words = text.split(/\s+/).filter(Boolean);
|
|
54230
55825
|
const lines = [];
|
|
54231
55826
|
let cur = "";
|
|
@@ -54271,7 +55866,7 @@ function renderVenn(container, parsed, palette, _isDark, onClickItem, exportDims
|
|
|
54271
55866
|
if (!ov.label) continue;
|
|
54272
55867
|
const idxs = ov.sets.map((s) => vennSets.findIndex((vs) => vs.name === s));
|
|
54273
55868
|
if (idxs.some((idx) => idx < 0)) continue;
|
|
54274
|
-
const lines =
|
|
55869
|
+
const lines = wrapLabel3(ov.label, MAX_WRAP_CHARS);
|
|
54275
55870
|
wrappedOverlapLabels.set(ov, lines);
|
|
54276
55871
|
const dir = predictOverlapDirRaw(idxs);
|
|
54277
55872
|
const longest = lines.reduce((m, l) => Math.max(m, l.length), 0);
|
|
@@ -55709,6 +57304,7 @@ async function renderForExport(content, theme, palette, viewState, options) {
|
|
|
55709
57304
|
const { parseMap: parseMap2 } = await Promise.resolve().then(() => (init_parser12(), parser_exports11));
|
|
55710
57305
|
const { resolveMap: resolveMap2 } = await Promise.resolve().then(() => (init_resolver2(), resolver_exports));
|
|
55711
57306
|
const { renderMapForExport: renderMapForExport2 } = await Promise.resolve().then(() => (init_renderer16(), renderer_exports16));
|
|
57307
|
+
const { mapExportDimensions: mapExportDimensions2 } = await Promise.resolve().then(() => (init_dimensions(), dimensions_exports));
|
|
55712
57308
|
const effectivePalette2 = await resolveExportPalette(theme, palette);
|
|
55713
57309
|
const mapParsed = parseMap2(content);
|
|
55714
57310
|
let mapData = options?.mapData;
|
|
@@ -55721,14 +57317,15 @@ async function renderForExport(content, theme, palette, viewState, options) {
|
|
|
55721
57317
|
}
|
|
55722
57318
|
}
|
|
55723
57319
|
const mapResolved = resolveMap2(mapParsed, mapData);
|
|
55724
|
-
const
|
|
57320
|
+
const dims2 = mapExportDimensions2(mapResolved, mapData, EXPORT_WIDTH);
|
|
57321
|
+
const container2 = createExportContainer(dims2.width, dims2.height);
|
|
55725
57322
|
renderMapForExport2(
|
|
55726
57323
|
container2,
|
|
55727
57324
|
mapResolved,
|
|
55728
57325
|
mapData,
|
|
55729
57326
|
effectivePalette2,
|
|
55730
57327
|
theme === "dark",
|
|
55731
|
-
|
|
57328
|
+
dims2
|
|
55732
57329
|
);
|
|
55733
57330
|
return finalizeSvgExport(container2, theme, effectivePalette2);
|
|
55734
57331
|
}
|
|
@@ -56570,7 +58167,8 @@ async function render(content, options) {
|
|
|
56570
58167
|
...options?.c4Container !== void 0 && {
|
|
56571
58168
|
c4Container: options.c4Container
|
|
56572
58169
|
},
|
|
56573
|
-
...options?.tagGroup !== void 0 && { tagGroup: options.tagGroup }
|
|
58170
|
+
...options?.tagGroup !== void 0 && { tagGroup: options.tagGroup },
|
|
58171
|
+
...options?.mapData !== void 0 && { mapData: options.mapData }
|
|
56574
58172
|
});
|
|
56575
58173
|
if (chartType === "map") {
|
|
56576
58174
|
try {
|
|
@@ -56581,7 +58179,7 @@ async function render(content, options) {
|
|
|
56581
58179
|
Promise.resolve().then(() => (init_load_data(), load_data_exports))
|
|
56582
58180
|
]
|
|
56583
58181
|
);
|
|
56584
|
-
const data = await loadMapData2();
|
|
58182
|
+
const data = options?.mapData ?? await loadMapData2();
|
|
56585
58183
|
diagnostics = [...resolveMap2(parseMap2(content), data).diagnostics];
|
|
56586
58184
|
} catch {
|
|
56587
58185
|
}
|
|
@@ -56749,22 +58347,20 @@ var DIRECTIVE_KEYWORDS = /* @__PURE__ */ new Set([
|
|
|
56749
58347
|
// Sequence
|
|
56750
58348
|
"activations",
|
|
56751
58349
|
"no-activations",
|
|
56752
|
-
// Map (§24B) directives
|
|
56753
|
-
"region",
|
|
56754
|
-
"projection",
|
|
58350
|
+
// Map (§24B) directives — cosmetics on by default, bare `no-*` opt-outs
|
|
56755
58351
|
"region-metric",
|
|
56756
58352
|
"poi-metric",
|
|
56757
58353
|
"flow-metric",
|
|
56758
|
-
"
|
|
56759
|
-
"
|
|
56760
|
-
"default-country",
|
|
56761
|
-
"default-state",
|
|
56762
|
-
"no-legend",
|
|
56763
|
-
"no-insets",
|
|
56764
|
-
"muted",
|
|
56765
|
-
"natural",
|
|
56766
|
-
"subtitle",
|
|
58354
|
+
"locale",
|
|
58355
|
+
"active-tag",
|
|
56767
58356
|
"caption",
|
|
58357
|
+
"no-legend",
|
|
58358
|
+
"no-coastline",
|
|
58359
|
+
"no-relief",
|
|
58360
|
+
"no-context-labels",
|
|
58361
|
+
"no-region-labels",
|
|
58362
|
+
"no-poi-labels",
|
|
58363
|
+
"no-colorize",
|
|
56768
58364
|
"poi",
|
|
56769
58365
|
"route",
|
|
56770
58366
|
// Data charts
|
|
@@ -57057,7 +58653,11 @@ var ATTRIBUTE_KEYS = /* @__PURE__ */ new Set([
|
|
|
57057
58653
|
"collapsed",
|
|
57058
58654
|
"tech",
|
|
57059
58655
|
"span",
|
|
57060
|
-
"split"
|
|
58656
|
+
"split",
|
|
58657
|
+
// Map (§24B) reserved keys
|
|
58658
|
+
"value",
|
|
58659
|
+
"label",
|
|
58660
|
+
"style"
|
|
57061
58661
|
]);
|
|
57062
58662
|
function applyAttributeKeys(tokens) {
|
|
57063
58663
|
for (let i = 0; i < tokens.length - 1; i++) {
|
|
@@ -57430,7 +59030,7 @@ pre.dgmo, code.language-dgmo, pre > code.language-dgmo,
|
|
|
57430
59030
|
|
|
57431
59031
|
// src/auto/index.ts
|
|
57432
59032
|
init_safe_href();
|
|
57433
|
-
var VERSION = "0.
|
|
59033
|
+
var VERSION = "0.22.0";
|
|
57434
59034
|
var DEFAULTS = {
|
|
57435
59035
|
theme: "auto",
|
|
57436
59036
|
palette: "nord",
|