@diagrammo/dgmo 0.21.0 → 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 +2521 -623
- package/dist/advanced.d.cts +917 -534
- package/dist/advanced.d.ts +917 -534
- package/dist/advanced.js +2516 -623
- package/dist/auto.cjs +2333 -608
- package/dist/auto.js +119 -119
- package/dist/auto.mjs +2335 -609
- package/dist/cli.cjs +168 -168
- package/dist/editor.cjs +13 -15
- package/dist/editor.js +13 -15
- package/dist/highlight.cjs +15 -12
- package/dist/highlight.js +15 -12
- package/dist/index.cjs +2317 -595
- package/dist/index.d.cts +4 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +2319 -596
- package/dist/internal.cjs +2521 -623
- package/dist/internal.d.cts +917 -534
- package/dist/internal.d.ts +917 -534
- package/dist/internal.js +2516 -623
- package/dist/map-data/PROVENANCE.json +1 -1
- package/dist/map-data/mountain-ranges.json +1 -0
- package/dist/map-data/water-bodies.json +1 -0
- package/docs/language-reference.md +44 -31
- 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 +9 -0
- 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 +26 -1
- package/src/boxes-and-lines/renderer.ts +39 -12
- package/src/cli.ts +1 -1
- package/src/completion.ts +32 -24
- package/src/cycle/renderer.ts +14 -1
- package/src/d3.ts +23 -11
- package/src/editor/highlight-api.ts +4 -0
- package/src/editor/keywords.ts +13 -15
- 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/PROVENANCE.json +1 -1
- package/src/map/data/mountain-ranges.json +1 -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 +295 -0
- package/src/map/geo.ts +305 -2
- package/src/map/invert.ts +111 -0
- package/src/map/layout.ts +1504 -335
- package/src/map/load-data.ts +16 -2
- package/src/map/parser.ts +57 -111
- package/src/map/renderer.ts +556 -13
- package/src/map/resolved-types.ts +24 -2
- package/src/map/resolver.ts +237 -67
- package/src/map/types.ts +39 -23
- 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,28 +16305,13 @@ 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
|
-
case "region-metric":
|
|
16308
|
+
case "region-metric": {
|
|
15895
16309
|
dup(d.regionMetric);
|
|
15896
|
-
|
|
16310
|
+
const { label: rmLabel, colorName: rmColor } = peelTrailingColorName(value);
|
|
16311
|
+
d.regionMetric = rmLabel;
|
|
16312
|
+
if (rmColor) d.regionMetricColor = rmColor;
|
|
15897
16313
|
break;
|
|
16314
|
+
}
|
|
15898
16315
|
case "poi-metric":
|
|
15899
16316
|
dup(d.poiMetric);
|
|
15900
16317
|
d.poiMetric = value;
|
|
@@ -15903,85 +16320,43 @@ function parseMap(content) {
|
|
|
15903
16320
|
dup(d.flowMetric);
|
|
15904
16321
|
d.flowMetric = value;
|
|
15905
16322
|
break;
|
|
15906
|
-
case "
|
|
15907
|
-
dup(d.
|
|
15908
|
-
|
|
15909
|
-
const s = parseScale(value, line12);
|
|
15910
|
-
if (s) d.scale = s;
|
|
15911
|
-
}
|
|
15912
|
-
break;
|
|
15913
|
-
case "region-labels":
|
|
15914
|
-
dup(d.regionLabels);
|
|
15915
|
-
if (value && !["full", "abbrev", "off"].includes(value))
|
|
15916
|
-
pushWarning(
|
|
15917
|
-
line12,
|
|
15918
|
-
`Unknown region-labels "${value}" (expected full | abbrev | off).`
|
|
15919
|
-
);
|
|
15920
|
-
d.regionLabels = value;
|
|
15921
|
-
break;
|
|
15922
|
-
case "poi-labels":
|
|
15923
|
-
dup(d.poiLabels);
|
|
15924
|
-
if (value && !["off", "auto", "all"].includes(value))
|
|
15925
|
-
pushWarning(
|
|
15926
|
-
line12,
|
|
15927
|
-
`Unknown poi-labels "${value}" (expected off | auto | all).`
|
|
15928
|
-
);
|
|
15929
|
-
d.poiLabels = value;
|
|
15930
|
-
break;
|
|
15931
|
-
case "default-country":
|
|
15932
|
-
dup(d.defaultCountry);
|
|
15933
|
-
d.defaultCountry = value;
|
|
15934
|
-
break;
|
|
15935
|
-
case "default-state":
|
|
15936
|
-
dup(d.defaultState);
|
|
15937
|
-
d.defaultState = value;
|
|
16323
|
+
case "locale":
|
|
16324
|
+
dup(d.locale);
|
|
16325
|
+
d.locale = value;
|
|
15938
16326
|
break;
|
|
15939
16327
|
case "active-tag":
|
|
15940
16328
|
dup(d.activeTag);
|
|
15941
16329
|
d.activeTag = value;
|
|
15942
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. ──
|
|
15943
16337
|
case "no-legend":
|
|
15944
16338
|
d.noLegend = true;
|
|
15945
16339
|
break;
|
|
15946
|
-
case "
|
|
15947
|
-
|
|
15948
|
-
if (d.basemapStyle !== void 0 && d.basemapStyle !== key)
|
|
15949
|
-
pushWarning(
|
|
15950
|
-
line12,
|
|
15951
|
-
`Conflicting basemap dress \u2014 "${d.basemapStyle}" then "${key}"; last wins.`
|
|
15952
|
-
);
|
|
15953
|
-
d.basemapStyle = key;
|
|
16340
|
+
case "no-coastline":
|
|
16341
|
+
d.noCoastline = true;
|
|
15954
16342
|
break;
|
|
15955
|
-
case "
|
|
15956
|
-
|
|
15957
|
-
d.subtitle = value;
|
|
16343
|
+
case "no-relief":
|
|
16344
|
+
d.noRelief = true;
|
|
15958
16345
|
break;
|
|
15959
|
-
case "
|
|
15960
|
-
|
|
15961
|
-
|
|
16346
|
+
case "no-context-labels":
|
|
16347
|
+
d.noContextLabels = true;
|
|
16348
|
+
break;
|
|
16349
|
+
case "no-region-labels":
|
|
16350
|
+
d.noRegionLabels = true;
|
|
16351
|
+
break;
|
|
16352
|
+
case "no-poi-labels":
|
|
16353
|
+
d.noPoiLabels = true;
|
|
16354
|
+
break;
|
|
16355
|
+
case "no-colorize":
|
|
16356
|
+
d.noColorize = true;
|
|
15962
16357
|
break;
|
|
15963
16358
|
}
|
|
15964
16359
|
}
|
|
15965
|
-
function parseScale(value, line12) {
|
|
15966
|
-
const toks = value.split(/\s+/).filter(Boolean);
|
|
15967
|
-
const min = Number(toks[0]);
|
|
15968
|
-
const max = Number(toks[1]);
|
|
15969
|
-
if (!Number.isFinite(min) || !Number.isFinite(max)) {
|
|
15970
|
-
pushError(line12, `scale requires numeric <min> <max> (got "${value}").`);
|
|
15971
|
-
return null;
|
|
15972
|
-
}
|
|
15973
|
-
const scale = { min, max };
|
|
15974
|
-
if (toks[2] === "center") {
|
|
15975
|
-
const c = Number(toks[3]);
|
|
15976
|
-
if (Number.isFinite(c)) scale.center = c;
|
|
15977
|
-
else
|
|
15978
|
-
pushError(
|
|
15979
|
-
line12,
|
|
15980
|
-
`scale center requires a number (got "${toks[3] ?? ""}").`
|
|
15981
|
-
);
|
|
15982
|
-
}
|
|
15983
|
-
return scale;
|
|
15984
|
-
}
|
|
15985
16360
|
function handleTag(trimmed, line12) {
|
|
15986
16361
|
const m = matchTagBlockHeading(trimmed);
|
|
15987
16362
|
if (!m) {
|
|
@@ -16055,6 +16430,7 @@ function parseMap(content) {
|
|
|
16055
16430
|
};
|
|
16056
16431
|
if (regionScope !== void 0) region.scope = regionScope;
|
|
16057
16432
|
if (valueNum !== void 0) region.value = valueNum;
|
|
16433
|
+
if (split.color) region.color = split.color;
|
|
16058
16434
|
regions.push(region);
|
|
16059
16435
|
}
|
|
16060
16436
|
function handlePoi(rest, line12, indent) {
|
|
@@ -16079,6 +16455,7 @@ function parseMap(content) {
|
|
|
16079
16455
|
const poi = { pos, tags, meta, lineNumber: line12 };
|
|
16080
16456
|
if (split.alias) poi.alias = split.alias;
|
|
16081
16457
|
if (label !== void 0) poi.label = label;
|
|
16458
|
+
if (split.color) poi.color = split.color;
|
|
16082
16459
|
pois.push(poi);
|
|
16083
16460
|
open.poi = { poi, indent };
|
|
16084
16461
|
}
|
|
@@ -16179,13 +16556,15 @@ function parseMap(content) {
|
|
|
16179
16556
|
pushError(line12, `Edge has an empty endpoint: "${trimmed}".`);
|
|
16180
16557
|
continue;
|
|
16181
16558
|
}
|
|
16182
|
-
const
|
|
16559
|
+
const isLast = k === links.length - 1;
|
|
16560
|
+
const meta = isLast ? lastSplit.meta : {};
|
|
16561
|
+
const style = links[k].style === "arc" ? "arc" : "straight";
|
|
16183
16562
|
edges.push({
|
|
16184
16563
|
from,
|
|
16185
16564
|
to,
|
|
16186
16565
|
...links[k].label !== void 0 && { label: links[k].label },
|
|
16187
16566
|
directed: links[k].directed,
|
|
16188
|
-
style
|
|
16567
|
+
style,
|
|
16189
16568
|
meta,
|
|
16190
16569
|
lineNumber: line12
|
|
16191
16570
|
});
|
|
@@ -16271,20 +16650,19 @@ var init_parser12 = __esm({
|
|
|
16271
16650
|
LEG_ARROW_RE = /^(-[^>]*?->|->|~[^>]*?~>|~>|--)\s+(.+)$/;
|
|
16272
16651
|
AT_RE = /(^|[\s,])at\s*:/i;
|
|
16273
16652
|
DIRECTIVE_SET = /* @__PURE__ */ new Set([
|
|
16274
|
-
"region",
|
|
16275
|
-
"projection",
|
|
16276
16653
|
"region-metric",
|
|
16277
16654
|
"poi-metric",
|
|
16278
16655
|
"flow-metric",
|
|
16279
|
-
"
|
|
16280
|
-
"region-labels",
|
|
16281
|
-
"poi-labels",
|
|
16282
|
-
"default-country",
|
|
16283
|
-
"default-state",
|
|
16656
|
+
"locale",
|
|
16284
16657
|
"active-tag",
|
|
16658
|
+
"caption",
|
|
16285
16659
|
"no-legend",
|
|
16286
|
-
"
|
|
16287
|
-
"
|
|
16660
|
+
"no-coastline",
|
|
16661
|
+
"no-relief",
|
|
16662
|
+
"no-context-labels",
|
|
16663
|
+
"no-region-labels",
|
|
16664
|
+
"no-poi-labels",
|
|
16665
|
+
"no-colorize"
|
|
16288
16666
|
]);
|
|
16289
16667
|
}
|
|
16290
16668
|
});
|
|
@@ -24206,8 +24584,8 @@ function renderKanban(container, parsed, palette, isDark, options) {
|
|
|
24206
24584
|
let metaY = separatorY + sCardSeparatorGap + sCardMetaFontSize;
|
|
24207
24585
|
for (const meta of tagMeta) {
|
|
24208
24586
|
cg.append("text").attr("x", cx + sCardPaddingX).attr("y", metaY).attr("font-size", sCardMetaFontSize).attr("fill", onCardText).text(`${meta.label}: `);
|
|
24209
|
-
const
|
|
24210
|
-
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);
|
|
24211
24589
|
metaY += sCardMetaLineHeight;
|
|
24212
24590
|
}
|
|
24213
24591
|
for (const detail of card.details) {
|
|
@@ -24551,8 +24929,8 @@ function renderSwimlaneCard(parent, cardLayout, tagGroups, activeTagGroup, palet
|
|
|
24551
24929
|
let metaY = separatorY + sCardSeparatorGap + sCardMetaFontSize;
|
|
24552
24930
|
for (const meta of tagMeta) {
|
|
24553
24931
|
cg.append("text").attr("x", cx + sCardPaddingX).attr("y", metaY).attr("font-size", sCardMetaFontSize).attr("fill", palette.textMuted).text(`${meta.label}: `);
|
|
24554
|
-
const
|
|
24555
|
-
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);
|
|
24556
24934
|
metaY += sCardMetaLineHeight;
|
|
24557
24935
|
}
|
|
24558
24936
|
for (const detail of card.details) {
|
|
@@ -25386,8 +25764,8 @@ function classifyEREntities(tables, relationships) {
|
|
|
25386
25764
|
}
|
|
25387
25765
|
}
|
|
25388
25766
|
const mmParticipants = /* @__PURE__ */ new Set();
|
|
25389
|
-
for (const [id,
|
|
25390
|
-
if (
|
|
25767
|
+
for (const [id, neighbors2] of tableStarNeighbors) {
|
|
25768
|
+
if (neighbors2.size >= 2) mmParticipants.add(id);
|
|
25391
25769
|
}
|
|
25392
25770
|
const indegreeValues = Object.values(indegreeMap);
|
|
25393
25771
|
const mean = indegreeValues.reduce((a, b) => a + b, 0) / indegreeValues.length;
|
|
@@ -26060,7 +26438,8 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26060
26438
|
controlsExpanded,
|
|
26061
26439
|
onToggleDescriptions,
|
|
26062
26440
|
onToggleControlsExpand,
|
|
26063
|
-
exportMode = false
|
|
26441
|
+
exportMode = false,
|
|
26442
|
+
controlsHost
|
|
26064
26443
|
} = options ?? {};
|
|
26065
26444
|
d3Selection6.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
26066
26445
|
const width = exportDims?.width ?? container.clientWidth;
|
|
@@ -26078,7 +26457,11 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26078
26457
|
const sGroupLabelZone = sctx.structural(GROUP_LABEL_ZONE);
|
|
26079
26458
|
const sTitleFontSize = sctx.text(TITLE_FONT_SIZE);
|
|
26080
26459
|
const sTitleY = sctx.structural(TITLE_Y);
|
|
26081
|
-
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(
|
|
26082
26465
|
getMaxLegendReservedHeight(
|
|
26083
26466
|
{
|
|
26084
26467
|
groups: parsed.tagGroups,
|
|
@@ -26087,7 +26470,7 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26087
26470
|
},
|
|
26088
26471
|
width
|
|
26089
26472
|
)
|
|
26090
|
-
);
|
|
26473
|
+
) : 0;
|
|
26091
26474
|
const activeGroup = resolveActiveTagGroup(
|
|
26092
26475
|
parsed.tagGroups,
|
|
26093
26476
|
parsed.options["active-tag"],
|
|
@@ -26402,10 +26785,10 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26402
26785
|
const hasDescriptions = parsed.nodes.some(
|
|
26403
26786
|
(n) => n.description && n.description.length > 0
|
|
26404
26787
|
);
|
|
26405
|
-
const hasLegend = parsed.tagGroups.length > 0 || hasDescriptions;
|
|
26788
|
+
const hasLegend = parsed.tagGroups.length > 0 || hasDescriptions && controlsHost !== "app";
|
|
26406
26789
|
if (hasLegend) {
|
|
26407
26790
|
let controlsGroup;
|
|
26408
|
-
if (hasDescriptions && onToggleDescriptions) {
|
|
26791
|
+
if (hasDescriptions && (onToggleDescriptions || controlsHost === "app")) {
|
|
26409
26792
|
controlsGroup = {
|
|
26410
26793
|
toggles: [
|
|
26411
26794
|
{
|
|
@@ -26423,7 +26806,14 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26423
26806
|
groups: parsed.tagGroups,
|
|
26424
26807
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
26425
26808
|
mode: exportMode ? "export" : "preview",
|
|
26426
|
-
|
|
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 }
|
|
26427
26817
|
};
|
|
26428
26818
|
const legendState = {
|
|
26429
26819
|
activeGroup,
|
|
@@ -27670,8 +28060,9 @@ function renderMindmap(container, parsed, layout, palette, isDark, onClickItem,
|
|
|
27670
28060
|
const containerHeight = exportDims?.height ?? (container.getBoundingClientRect().height || 600);
|
|
27671
28061
|
d3Selection7.select(container).selectAll("*").remove();
|
|
27672
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";
|
|
27673
28064
|
const hasControls = !!options?.onToggleColorByDepth || !!options?.onToggleDescriptions;
|
|
27674
|
-
const hasLegend = parsed.tagGroups.length > 0 || hasControls;
|
|
28065
|
+
const hasLegend = parsed.tagGroups.length > 0 || hasControls && !appHosted;
|
|
27675
28066
|
const fixedLegend = !isExport && hasLegend;
|
|
27676
28067
|
const legendReserve = fixedLegend ? getMaxLegendReservedHeight(
|
|
27677
28068
|
{
|
|
@@ -27765,7 +28156,10 @@ function renderMindmap(container, parsed, layout, palette, isDark, onClickItem,
|
|
|
27765
28156
|
}),
|
|
27766
28157
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
27767
28158
|
mode: options?.exportMode ? "export" : "preview",
|
|
27768
|
-
...controlsToggles !== void 0 && { controlsGroup: controlsToggles }
|
|
28159
|
+
...controlsToggles !== void 0 && { controlsGroup: controlsToggles },
|
|
28160
|
+
...options?.controlsHost !== void 0 && {
|
|
28161
|
+
controlsHost: options.controlsHost
|
|
28162
|
+
}
|
|
27769
28163
|
};
|
|
27770
28164
|
const legendState = {
|
|
27771
28165
|
activeGroup: options?.colorByDepth ? null : activeTagGroup !== void 0 ? activeTagGroup : parsed.options["active-tag"] ?? null,
|
|
@@ -28208,8 +28602,8 @@ function computeFieldAlignX(children) {
|
|
|
28208
28602
|
for (const child of children) {
|
|
28209
28603
|
if (child.metadata["_labelField"] === "true" && child.children.length >= 2) {
|
|
28210
28604
|
const labelEl = child.children[0];
|
|
28211
|
-
const
|
|
28212
|
-
maxLabelWidth = Math.max(maxLabelWidth,
|
|
28605
|
+
const labelWidth2 = labelEl.label.length * CHAR_WIDTH5;
|
|
28606
|
+
maxLabelWidth = Math.max(maxLabelWidth, labelWidth2);
|
|
28213
28607
|
labelFieldCount++;
|
|
28214
28608
|
}
|
|
28215
28609
|
}
|
|
@@ -33174,7 +33568,7 @@ function hasRoles(node) {
|
|
|
33174
33568
|
function computeNodeWidth2(node, expanded, options) {
|
|
33175
33569
|
const badgeVal = node.computedConcurrentInvocations === 0 && node.computedInstances > 1 ? node.computedInstances : 0;
|
|
33176
33570
|
const badgeLen = badgeVal > 0 ? `${badgeVal}x`.length + 2 : 0;
|
|
33177
|
-
const
|
|
33571
|
+
const labelWidth2 = (node.label.length + badgeLen) * CHAR_WIDTH7 + PADDING_X3;
|
|
33178
33572
|
const allKeys = [];
|
|
33179
33573
|
if (node.computedRps > 0) allKeys.push("RPS");
|
|
33180
33574
|
if (expanded) {
|
|
@@ -33218,7 +33612,7 @@ function computeNodeWidth2(node, expanded, options) {
|
|
|
33218
33612
|
allKeys.push("overflow");
|
|
33219
33613
|
}
|
|
33220
33614
|
}
|
|
33221
|
-
if (allKeys.length === 0) return Math.max(MIN_NODE_WIDTH2,
|
|
33615
|
+
if (allKeys.length === 0) return Math.max(MIN_NODE_WIDTH2, labelWidth2);
|
|
33222
33616
|
const maxKeyLen = Math.max(...allKeys.map((k) => k.length));
|
|
33223
33617
|
let maxRowWidth = 0;
|
|
33224
33618
|
if (node.computedRps > 0) {
|
|
@@ -33306,7 +33700,7 @@ function computeNodeWidth2(node, expanded, options) {
|
|
|
33306
33700
|
truncated.length * META_CHAR_WIDTH3 + PADDING_X3
|
|
33307
33701
|
);
|
|
33308
33702
|
}
|
|
33309
|
-
return Math.max(MIN_NODE_WIDTH2,
|
|
33703
|
+
return Math.max(MIN_NODE_WIDTH2, labelWidth2, maxRowWidth + 20, descWidth);
|
|
33310
33704
|
}
|
|
33311
33705
|
function computeNodeHeight2(node, expanded, options) {
|
|
33312
33706
|
const propCount = countDisplayProps(node, expanded, options);
|
|
@@ -34856,8 +35250,9 @@ function computeInfraLegendGroups(nodes, tagGroups, palette, edges) {
|
|
|
34856
35250
|
}
|
|
34857
35251
|
return groups;
|
|
34858
35252
|
}
|
|
34859
|
-
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) {
|
|
34860
35254
|
if (legendGroups.length === 0 && !playback) return;
|
|
35255
|
+
const appHostedPlayback = controlsHost === "app" && !!playback;
|
|
34861
35256
|
const legendG = rootSvg.append("g").attr("transform", `translate(0, ${legendY})`);
|
|
34862
35257
|
if (activeGroup) {
|
|
34863
35258
|
legendG.attr("data-legend-active", activeGroup.toLowerCase());
|
|
@@ -34866,14 +35261,29 @@ function renderLegend3(rootSvg, legendGroups, totalWidth, legendY, palette, isDa
|
|
|
34866
35261
|
name: g.name,
|
|
34867
35262
|
entries: g.entries.map((e) => ({ value: e.value, color: e.color }))
|
|
34868
35263
|
}));
|
|
34869
|
-
if (playback) {
|
|
35264
|
+
if (playback && !appHostedPlayback) {
|
|
34870
35265
|
allGroups.push({ name: "Playback", entries: [] });
|
|
34871
35266
|
}
|
|
34872
35267
|
const legendConfig = {
|
|
34873
35268
|
groups: allGroups,
|
|
34874
35269
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
34875
35270
|
mode: exportMode ? "export" : "preview",
|
|
34876
|
-
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
|
+
}
|
|
34877
35287
|
};
|
|
34878
35288
|
const legendState = { activeGroup };
|
|
34879
35289
|
renderLegendD3(
|
|
@@ -34924,8 +35334,9 @@ function renderLegend3(rootSvg, legendGroups, totalWidth, legendY, palette, isDa
|
|
|
34924
35334
|
}
|
|
34925
35335
|
}
|
|
34926
35336
|
}
|
|
34927
|
-
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) {
|
|
34928
35338
|
d3Selection11.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
35339
|
+
const appHostedPlayback = controlsHost === "app" && !!playback;
|
|
34929
35340
|
const ctx = ScaleContext.identity();
|
|
34930
35341
|
const sc = buildScaledConstants(ctx);
|
|
34931
35342
|
const legendGroups = computeInfraLegendGroups(
|
|
@@ -34934,7 +35345,7 @@ function renderInfra(container, layout, palette, isDark, title, titleLineNumber,
|
|
|
34934
35345
|
palette,
|
|
34935
35346
|
layout.edges
|
|
34936
35347
|
);
|
|
34937
|
-
const hasLegend = legendGroups.length > 0 || !!playback;
|
|
35348
|
+
const hasLegend = legendGroups.length > 0 || !!playback && !appHostedPlayback;
|
|
34938
35349
|
const fixedLegend = !exportMode && hasLegend;
|
|
34939
35350
|
const legendDynamicH = hasLegend ? getMaxLegendReservedHeight(
|
|
34940
35351
|
{
|
|
@@ -35078,7 +35489,8 @@ function renderInfra(container, layout, palette, isDark, title, titleLineNumber,
|
|
|
35078
35489
|
isDark,
|
|
35079
35490
|
activeGroup ?? null,
|
|
35080
35491
|
playback ?? void 0,
|
|
35081
|
-
exportMode
|
|
35492
|
+
exportMode,
|
|
35493
|
+
controlsHost
|
|
35082
35494
|
);
|
|
35083
35495
|
legendSvg.selectAll(".infra-legend-group").style("pointer-events", "auto");
|
|
35084
35496
|
} else {
|
|
@@ -35091,7 +35503,8 @@ function renderInfra(container, layout, palette, isDark, title, titleLineNumber,
|
|
|
35091
35503
|
isDark,
|
|
35092
35504
|
activeGroup ?? null,
|
|
35093
35505
|
playback ?? void 0,
|
|
35094
|
-
exportMode
|
|
35506
|
+
exportMode,
|
|
35507
|
+
controlsHost
|
|
35095
35508
|
);
|
|
35096
35509
|
}
|
|
35097
35510
|
}
|
|
@@ -42725,6 +43138,9 @@ function renderTechRadar(container, parsed, palette, isDark, onClickItem, export
|
|
|
42725
43138
|
onToggle: (active) => options.onToggleListing(active)
|
|
42726
43139
|
}
|
|
42727
43140
|
]
|
|
43141
|
+
},
|
|
43142
|
+
...options.controlsHost !== void 0 && {
|
|
43143
|
+
controlsHost: options.controlsHost
|
|
42728
43144
|
}
|
|
42729
43145
|
};
|
|
42730
43146
|
const legendState = {
|
|
@@ -44547,7 +44963,7 @@ function computeCycleLayout(parsed, options) {
|
|
|
44547
44963
|
const circleNodes = parsed.options["circle-nodes"] === "true";
|
|
44548
44964
|
const nodeDims = parsed.nodes.map((node) => {
|
|
44549
44965
|
const hasDesc = !hideDescriptions && node.description.length > 0;
|
|
44550
|
-
const
|
|
44966
|
+
const labelWidth2 = Math.max(
|
|
44551
44967
|
MIN_NODE_WIDTH4,
|
|
44552
44968
|
node.label.length * LABEL_CHAR_W + NODE_PAD_X * 2
|
|
44553
44969
|
);
|
|
@@ -44556,12 +44972,12 @@ function computeCycleLayout(parsed, options) {
|
|
|
44556
44972
|
}
|
|
44557
44973
|
if (!hasDesc) {
|
|
44558
44974
|
return {
|
|
44559
|
-
width: Math.min(MAX_NODE_WIDTH3,
|
|
44975
|
+
width: Math.min(MAX_NODE_WIDTH3, labelWidth2),
|
|
44560
44976
|
height: PLAIN_NODE_HEIGHT,
|
|
44561
44977
|
wrappedDesc: []
|
|
44562
44978
|
};
|
|
44563
44979
|
}
|
|
44564
|
-
return chooseDescribedRectDims(node.description,
|
|
44980
|
+
return chooseDescribedRectDims(node.description, labelWidth2);
|
|
44565
44981
|
});
|
|
44566
44982
|
if (circleNodes) {
|
|
44567
44983
|
const maxDiam = Math.max(...nodeDims.map((d) => d.width));
|
|
@@ -44757,10 +45173,10 @@ function computeCycleLayout(parsed, options) {
|
|
|
44757
45173
|
scale
|
|
44758
45174
|
};
|
|
44759
45175
|
}
|
|
44760
|
-
function chooseDescribedRectDims(description,
|
|
45176
|
+
function chooseDescribedRectDims(description, labelWidth2) {
|
|
44761
45177
|
const minW = Math.min(
|
|
44762
45178
|
MAX_NODE_WIDTH3,
|
|
44763
|
-
Math.max(MIN_NODE_WIDTH4,
|
|
45179
|
+
Math.max(MIN_NODE_WIDTH4, labelWidth2, DESC_MIN_WIDTH)
|
|
44764
45180
|
);
|
|
44765
45181
|
let best = null;
|
|
44766
45182
|
let bestScore = Infinity;
|
|
@@ -45189,7 +45605,8 @@ function renderCycle(container, parsed, palette, isDark, onClickItem, exportDims
|
|
|
45189
45605
|
const hideDescriptions = (renderOptions?.hideDescriptions ?? false) || parsed.options["no-descriptions"] === "true" || viewState?.hd === true;
|
|
45190
45606
|
const showDescriptions = !hideDescriptions;
|
|
45191
45607
|
const hasDescriptions = parsed.nodes.some((n) => n.description.length > 0) || parsed.edges.some((e) => e.description.length > 0);
|
|
45192
|
-
const
|
|
45608
|
+
const appHostedControls = renderOptions?.controlsHost === "app";
|
|
45609
|
+
const hasLegend = !appHostedControls && hasDescriptions && !!renderOptions?.onToggleDescriptions;
|
|
45193
45610
|
const showTitle = !!parsed.title && parsed.options["no-title"] !== "on";
|
|
45194
45611
|
const legendOffset = hasLegend ? sLegendHeight : 0;
|
|
45195
45612
|
const layoutHeight = height - (showTitle ? sTitleAreaHeight : 0) - legendOffset;
|
|
@@ -45226,7 +45643,10 @@ function renderCycle(container, parsed, palette, isDark, onClickItem, exportDims
|
|
|
45226
45643
|
groups: [],
|
|
45227
45644
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
45228
45645
|
mode: renderOptions?.exportMode ? "export" : "preview",
|
|
45229
|
-
controlsGroup
|
|
45646
|
+
controlsGroup,
|
|
45647
|
+
...renderOptions?.controlsHost !== void 0 && {
|
|
45648
|
+
controlsHost: renderOptions.controlsHost
|
|
45649
|
+
}
|
|
45230
45650
|
};
|
|
45231
45651
|
const legendState = {
|
|
45232
45652
|
activeGroup: null,
|
|
@@ -45480,8 +45900,8 @@ var init_renderer15 = __esm({
|
|
|
45480
45900
|
});
|
|
45481
45901
|
|
|
45482
45902
|
// src/map/geo.ts
|
|
45483
|
-
import { feature } from "topojson-client";
|
|
45484
|
-
import { geoBounds } from "d3-geo";
|
|
45903
|
+
import { feature, neighbors } from "topojson-client";
|
|
45904
|
+
import { geoBounds, geoArea } from "d3-geo";
|
|
45485
45905
|
function geomObject(topo) {
|
|
45486
45906
|
const key = Object.keys(topo.objects)[0];
|
|
45487
45907
|
return topo.objects[key];
|
|
@@ -45498,6 +45918,107 @@ function featureIndex(topo) {
|
|
|
45498
45918
|
}
|
|
45499
45919
|
return idx;
|
|
45500
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
|
+
}
|
|
45501
46022
|
function featureBbox(topo, geomId) {
|
|
45502
46023
|
const geom = geomObject(topo).geometries.find((g) => g.id === geomId);
|
|
45503
46024
|
if (!geom) return null;
|
|
@@ -45509,6 +46030,74 @@ function featureBbox(topo, geomId) {
|
|
|
45509
46030
|
[b[1][0], b[1][1]]
|
|
45510
46031
|
];
|
|
45511
46032
|
}
|
|
46033
|
+
function explodePolygons(gj) {
|
|
46034
|
+
const g = gj.geometry ?? gj;
|
|
46035
|
+
const t = g.type;
|
|
46036
|
+
const coords = g.coordinates;
|
|
46037
|
+
if (t === "Polygon") {
|
|
46038
|
+
return [
|
|
46039
|
+
{ type: "Feature", geometry: { type: "Polygon", coordinates: coords } }
|
|
46040
|
+
];
|
|
46041
|
+
}
|
|
46042
|
+
if (t === "MultiPolygon") {
|
|
46043
|
+
return coords.map((rings) => ({
|
|
46044
|
+
type: "Feature",
|
|
46045
|
+
geometry: { type: "Polygon", coordinates: rings }
|
|
46046
|
+
}));
|
|
46047
|
+
}
|
|
46048
|
+
return [];
|
|
46049
|
+
}
|
|
46050
|
+
function bboxGap(a, b) {
|
|
46051
|
+
const lonGap = Math.max(0, a[0][0] - b[1][0], b[0][0] - a[1][0]);
|
|
46052
|
+
const latGap = Math.max(0, a[0][1] - b[1][1], b[0][1] - a[1][1]);
|
|
46053
|
+
return Math.max(lonGap, latGap);
|
|
46054
|
+
}
|
|
46055
|
+
function featureBboxPrimary(topo, geomId) {
|
|
46056
|
+
const geom = geomObject(topo).geometries.find((g) => g.id === geomId);
|
|
46057
|
+
if (!geom) return null;
|
|
46058
|
+
const gj = feature(topo, geom);
|
|
46059
|
+
const parts = explodePolygons(gj);
|
|
46060
|
+
if (parts.length <= 1) return featureBbox(topo, geomId);
|
|
46061
|
+
const polys = parts.map((p) => {
|
|
46062
|
+
const b = geoBounds(p);
|
|
46063
|
+
if (!b || !Number.isFinite(b[0][0])) return null;
|
|
46064
|
+
const wraps = b[1][0] < b[0][0];
|
|
46065
|
+
const bbox = [
|
|
46066
|
+
[b[0][0], b[0][1]],
|
|
46067
|
+
[b[1][0], b[1][1]]
|
|
46068
|
+
];
|
|
46069
|
+
return { bbox, area: geoArea(p), wraps };
|
|
46070
|
+
}).filter(
|
|
46071
|
+
(p) => p !== null
|
|
46072
|
+
);
|
|
46073
|
+
if (polys.length <= 1 || polys.some((p) => p.wraps))
|
|
46074
|
+
return featureBbox(topo, geomId);
|
|
46075
|
+
const maxArea = Math.max(...polys.map((p) => p.area));
|
|
46076
|
+
const anchor = polys.find((p) => p.area === maxArea);
|
|
46077
|
+
const cluster = [
|
|
46078
|
+
[anchor.bbox[0][0], anchor.bbox[0][1]],
|
|
46079
|
+
[anchor.bbox[1][0], anchor.bbox[1][1]]
|
|
46080
|
+
];
|
|
46081
|
+
const remaining = polys.filter((p) => p !== anchor);
|
|
46082
|
+
let added = true;
|
|
46083
|
+
while (added) {
|
|
46084
|
+
added = false;
|
|
46085
|
+
for (let i = remaining.length - 1; i >= 0; i--) {
|
|
46086
|
+
const p = remaining[i];
|
|
46087
|
+
const near = bboxGap(p.bbox, cluster) <= DETACH_GAP_DEG;
|
|
46088
|
+
const large = p.area >= DETACH_AREA_FRAC * maxArea;
|
|
46089
|
+
if (near || large) {
|
|
46090
|
+
cluster[0][0] = Math.min(cluster[0][0], p.bbox[0][0]);
|
|
46091
|
+
cluster[0][1] = Math.min(cluster[0][1], p.bbox[0][1]);
|
|
46092
|
+
cluster[1][0] = Math.max(cluster[1][0], p.bbox[1][0]);
|
|
46093
|
+
cluster[1][1] = Math.max(cluster[1][1], p.bbox[1][1]);
|
|
46094
|
+
remaining.splice(i, 1);
|
|
46095
|
+
added = true;
|
|
46096
|
+
}
|
|
46097
|
+
}
|
|
46098
|
+
}
|
|
46099
|
+
return cluster;
|
|
46100
|
+
}
|
|
45512
46101
|
function unionExtent(boxes, points) {
|
|
45513
46102
|
const lats = [];
|
|
45514
46103
|
const lons = [];
|
|
@@ -45547,11 +46136,15 @@ function unionLongitudes(lons) {
|
|
|
45547
46136
|
}
|
|
45548
46137
|
return { west: pts[gapIdx], east: pts[gapIdx - 1] + 360 };
|
|
45549
46138
|
}
|
|
45550
|
-
var fold;
|
|
46139
|
+
var fold, adjacencyCache, EDGE_EPS, DETACH_GAP_DEG, DETACH_AREA_FRAC;
|
|
45551
46140
|
var init_geo = __esm({
|
|
45552
46141
|
"src/map/geo.ts"() {
|
|
45553
46142
|
"use strict";
|
|
45554
46143
|
fold = (s) => s.normalize("NFD").replace(/\p{Diacritic}/gu, "").toLowerCase().trim();
|
|
46144
|
+
adjacencyCache = /* @__PURE__ */ new WeakMap();
|
|
46145
|
+
EDGE_EPS = 1e-9;
|
|
46146
|
+
DETACH_GAP_DEG = 10;
|
|
46147
|
+
DETACH_AREA_FRAC = 0.25;
|
|
45555
46148
|
}
|
|
45556
46149
|
});
|
|
45557
46150
|
|
|
@@ -45569,6 +46162,12 @@ function looksUS(lat, lon) {
|
|
|
45569
46162
|
if (lat < 15 || lat > 72) return false;
|
|
45570
46163
|
return lon >= -180 && lon <= -64 || lon >= 172;
|
|
45571
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
|
+
}
|
|
45572
46171
|
function resolveMap(parsed, data) {
|
|
45573
46172
|
const diagnostics = [...parsed.diagnostics];
|
|
45574
46173
|
const err = (line12, message, code) => {
|
|
@@ -45579,9 +46178,6 @@ function resolveMap(parsed, data) {
|
|
|
45579
46178
|
};
|
|
45580
46179
|
const result = {
|
|
45581
46180
|
title: parsed.title,
|
|
45582
|
-
...parsed.directives.subtitle !== void 0 && {
|
|
45583
|
-
subtitle: parsed.directives.subtitle
|
|
45584
|
-
},
|
|
45585
46181
|
...parsed.directives.caption !== void 0 && {
|
|
45586
46182
|
caption: parsed.directives.caption
|
|
45587
46183
|
},
|
|
@@ -45591,7 +46187,7 @@ function resolveMap(parsed, data) {
|
|
|
45591
46187
|
// renderer's job (step 4) — the resolver only carries `tags` + `tagGroups`
|
|
45592
46188
|
// through; it never resolves a tag value to a palette color (#10).
|
|
45593
46189
|
directives: { ...parsed.directives },
|
|
45594
|
-
basemaps: { world: "
|
|
46190
|
+
basemaps: { world: "detail", subdivisions: [] },
|
|
45595
46191
|
regions: [],
|
|
45596
46192
|
pois: [],
|
|
45597
46193
|
edges: [],
|
|
@@ -45600,7 +46196,8 @@ function resolveMap(parsed, data) {
|
|
|
45600
46196
|
[-180, -85],
|
|
45601
46197
|
[180, 85]
|
|
45602
46198
|
],
|
|
45603
|
-
projection: "
|
|
46199
|
+
projection: "equirectangular",
|
|
46200
|
+
poiFrameContainers: [],
|
|
45604
46201
|
diagnostics,
|
|
45605
46202
|
error: parsed.error
|
|
45606
46203
|
};
|
|
@@ -45610,7 +46207,10 @@ function resolveMap(parsed, data) {
|
|
|
45610
46207
|
...[...countryIndex.values()].map((v) => v.name),
|
|
45611
46208
|
...[...usStateIndex.values()].map((v) => v.name)
|
|
45612
46209
|
];
|
|
45613
|
-
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) => {
|
|
45614
46214
|
const f = fold(r.name);
|
|
45615
46215
|
return usStateIndex.has(f) && !countryIndex.has(f);
|
|
45616
46216
|
}) || parsed.regions.some(
|
|
@@ -45655,12 +46255,12 @@ function resolveMap(parsed, data) {
|
|
|
45655
46255
|
chosen = { ...inState, layer: "us-state" };
|
|
45656
46256
|
} else {
|
|
45657
46257
|
chosen = { ...inCountry, layer: "country" };
|
|
46258
|
+
warn2(
|
|
46259
|
+
r.lineNumber,
|
|
46260
|
+
`"${r.name}" is both a country and a US state \u2014 resolved as ${chosen.layer} (${chosen.id}). Pin it with an ISO code (${inState.id} / ${inCountry.id}) or name + scope ("${r.name} US" / "${r.name} ${inCountry.id}").`,
|
|
46261
|
+
"W_MAP_REGION_AMBIGUOUS"
|
|
46262
|
+
);
|
|
45658
46263
|
}
|
|
45659
|
-
warn2(
|
|
45660
|
-
r.lineNumber,
|
|
45661
|
-
`"${r.name}" is both a country and a US state \u2014 resolved as ${chosen.layer} (${chosen.id}). Pin it with an ISO code (${inState.id} / ${inCountry.id}) or name + scope ("${r.name} US" / "${r.name} ${inCountry.id}").`,
|
|
45662
|
-
"W_MAP_REGION_AMBIGUOUS"
|
|
45663
|
-
);
|
|
45664
46264
|
} else if (inState) {
|
|
45665
46265
|
chosen = { ...inState, layer: "us-state" };
|
|
45666
46266
|
} else if (inCountry) {
|
|
@@ -45684,6 +46284,7 @@ function resolveMap(parsed, data) {
|
|
|
45684
46284
|
name: chosen.name,
|
|
45685
46285
|
layer: chosen.layer,
|
|
45686
46286
|
...r.value !== void 0 && { value: r.value },
|
|
46287
|
+
...r.color !== void 0 && { color: r.color },
|
|
45687
46288
|
tags: r.tags,
|
|
45688
46289
|
meta: r.meta,
|
|
45689
46290
|
lineNumber: r.lineNumber
|
|
@@ -45760,7 +46361,7 @@ function resolveMap(parsed, data) {
|
|
|
45760
46361
|
if (!scope)
|
|
45761
46362
|
warn2(
|
|
45762
46363
|
line12,
|
|
45763
|
-
`"${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.`,
|
|
45764
46365
|
"W_MAP_AMBIGUOUS_NAME"
|
|
45765
46366
|
);
|
|
45766
46367
|
}
|
|
@@ -45773,17 +46374,21 @@ function resolveMap(parsed, data) {
|
|
|
45773
46374
|
return fold(pos.name);
|
|
45774
46375
|
};
|
|
45775
46376
|
const poiCountries = [];
|
|
45776
|
-
let
|
|
46377
|
+
let anyUsPoi = false;
|
|
46378
|
+
let anyNonNaPoi = false;
|
|
45777
46379
|
const noteCountry = (iso) => {
|
|
45778
46380
|
if (iso) {
|
|
45779
46381
|
poiCountries.push(iso);
|
|
45780
|
-
if (iso
|
|
46382
|
+
if (iso === "US") anyUsPoi = true;
|
|
46383
|
+
if (iso !== "US" && iso !== "CA" && iso !== "MX") anyNonNaPoi = true;
|
|
45781
46384
|
}
|
|
45782
46385
|
};
|
|
45783
46386
|
const deferred = [];
|
|
45784
46387
|
for (const p of parsed.pois) {
|
|
45785
46388
|
if (p.pos.kind === "coords") {
|
|
45786
|
-
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;
|
|
45787
46392
|
addResolvedPoi(p.pos.lat, p.pos.lon, p);
|
|
45788
46393
|
continue;
|
|
45789
46394
|
}
|
|
@@ -45801,14 +46406,15 @@ function resolveMap(parsed, data) {
|
|
|
45801
46406
|
deferred.push(p);
|
|
45802
46407
|
}
|
|
45803
46408
|
}
|
|
45804
|
-
const inferredCountry =
|
|
46409
|
+
const inferredCountry = localeCountry ?? mostCommonCountry(regions, poiCountries) ?? void 0;
|
|
46410
|
+
const inferredScope = localeSubdivision ?? inferredCountry;
|
|
45805
46411
|
for (const p of deferred) {
|
|
45806
46412
|
if (p.pos.kind !== "name") continue;
|
|
45807
46413
|
const got = lookupName(
|
|
45808
46414
|
p.pos.name,
|
|
45809
46415
|
p.pos.scope,
|
|
45810
46416
|
p.lineNumber,
|
|
45811
|
-
|
|
46417
|
+
inferredScope,
|
|
45812
46418
|
true
|
|
45813
46419
|
);
|
|
45814
46420
|
if (got.kind === "ok") {
|
|
@@ -45825,6 +46431,7 @@ function resolveMap(parsed, data) {
|
|
|
45825
46431
|
lat,
|
|
45826
46432
|
lon,
|
|
45827
46433
|
...p.label !== void 0 && { label: p.label },
|
|
46434
|
+
...p.color !== void 0 && { color: p.color },
|
|
45828
46435
|
tags: p.tags,
|
|
45829
46436
|
meta: p.meta,
|
|
45830
46437
|
lineNumber: p.lineNumber
|
|
@@ -45877,7 +46484,8 @@ function resolveMap(parsed, data) {
|
|
|
45877
46484
|
const meta = sizeValue !== void 0 ? { value: sizeValue } : {};
|
|
45878
46485
|
if (pos.kind === "coords") {
|
|
45879
46486
|
const id = alias ? fold(alias) : `@${pos.lat},${pos.lon}`;
|
|
45880
|
-
if (
|
|
46487
|
+
if (looksUS(pos.lat, pos.lon)) anyUsPoi = true;
|
|
46488
|
+
else if (!looksNorthAmericaNeighbor(pos.lat, pos.lon)) anyNonNaPoi = true;
|
|
45881
46489
|
if (!registry.has(id)) {
|
|
45882
46490
|
registerPoi(
|
|
45883
46491
|
id,
|
|
@@ -45900,7 +46508,7 @@ function resolveMap(parsed, data) {
|
|
|
45900
46508
|
if (registry.has(f)) return f;
|
|
45901
46509
|
const aliased = declaredByName.get(f);
|
|
45902
46510
|
if (aliased) return aliased;
|
|
45903
|
-
const got = lookupName(pos.name, pos.scope, line12,
|
|
46511
|
+
const got = lookupName(pos.name, pos.scope, line12, inferredScope, true);
|
|
45904
46512
|
if (got.kind !== "ok") return null;
|
|
45905
46513
|
noteCountry(got.iso);
|
|
45906
46514
|
registerPoi(
|
|
@@ -45957,9 +46565,12 @@ function resolveMap(parsed, data) {
|
|
|
45957
46565
|
}
|
|
45958
46566
|
routes.push({ stopIds, legs, lineNumber: rt.lineNumber });
|
|
45959
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;
|
|
45960
46572
|
const subdivisions = [];
|
|
45961
|
-
if (usSubdivisionReferenced ||
|
|
45962
|
-
subdivisions.push("us-states");
|
|
46573
|
+
if (usSubdivisionReferenced || usOriented) subdivisions.push("us-states");
|
|
45963
46574
|
const regionBoxes = [];
|
|
45964
46575
|
for (const ref of referencedRegionIds) {
|
|
45965
46576
|
const bb = featureBbox(data.usStates, ref.id);
|
|
@@ -45967,7 +46578,7 @@ function resolveMap(parsed, data) {
|
|
|
45967
46578
|
}
|
|
45968
46579
|
for (const r of regions) {
|
|
45969
46580
|
if (r.layer === "country") {
|
|
45970
|
-
const bb =
|
|
46581
|
+
const bb = featureBboxPrimary(data.worldCoarse, r.iso);
|
|
45971
46582
|
if (bb) regionBoxes.push(bb);
|
|
45972
46583
|
}
|
|
45973
46584
|
}
|
|
@@ -45977,23 +46588,56 @@ function resolveMap(parsed, data) {
|
|
|
45977
46588
|
[-180, -85],
|
|
45978
46589
|
[180, 85]
|
|
45979
46590
|
];
|
|
45980
|
-
|
|
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
|
+
}
|
|
45981
46628
|
const lonSpan = extent2[1][0] - extent2[0][0];
|
|
45982
46629
|
const latSpan = extent2[1][1] - extent2[0][1];
|
|
45983
46630
|
const span = Math.max(lonSpan, latSpan);
|
|
45984
|
-
const
|
|
46631
|
+
const maxAbsLat = Math.max(Math.abs(extent2[0][1]), Math.abs(extent2[1][1]));
|
|
45985
46632
|
let projection;
|
|
45986
|
-
|
|
45987
|
-
|
|
45988
|
-
|
|
45989
|
-
} else if (usDominant) {
|
|
46633
|
+
if (isPoiOnly && usOriented && lonSpan < US_NATIONAL_LON_SPAN) {
|
|
46634
|
+
projection = "mercator";
|
|
46635
|
+
} else if (usOriented) {
|
|
45990
46636
|
projection = "albers-usa";
|
|
45991
|
-
} else if (span > WORLD_SPAN) {
|
|
46637
|
+
} else if (span > WORLD_SPAN || maxAbsLat > MERCATOR_MAX_LAT) {
|
|
45992
46638
|
projection = "equirectangular";
|
|
45993
|
-
} else if (span < MERCATOR_MAX_SPAN) {
|
|
45994
|
-
projection = "mercator";
|
|
45995
46639
|
} else {
|
|
45996
|
-
projection = "
|
|
46640
|
+
projection = "mercator";
|
|
45997
46641
|
}
|
|
45998
46642
|
if (lonSpan >= 180) {
|
|
45999
46643
|
extent2 = [
|
|
@@ -46006,11 +46650,20 @@ function resolveMap(parsed, data) {
|
|
|
46006
46650
|
result.edges = edges;
|
|
46007
46651
|
result.routes = routes;
|
|
46008
46652
|
result.basemaps = {
|
|
46009
|
-
|
|
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",
|
|
46010
46662
|
subdivisions
|
|
46011
46663
|
};
|
|
46012
46664
|
result.extent = extent2;
|
|
46013
46665
|
result.projection = projection;
|
|
46666
|
+
result.poiFrameContainers = containerRegionIds;
|
|
46014
46667
|
result.error = parsed.error ?? firstError(diagnostics);
|
|
46015
46668
|
return result;
|
|
46016
46669
|
}
|
|
@@ -46047,17 +46700,20 @@ function firstError(diags) {
|
|
|
46047
46700
|
const e = diags.find((d) => d.severity === "error");
|
|
46048
46701
|
return e ? formatDgmoError(e) : null;
|
|
46049
46702
|
}
|
|
46050
|
-
var WORLD_SPAN,
|
|
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;
|
|
46051
46704
|
var init_resolver2 = __esm({
|
|
46052
46705
|
"src/map/resolver.ts"() {
|
|
46053
46706
|
"use strict";
|
|
46054
46707
|
init_diagnostics();
|
|
46055
46708
|
init_geo();
|
|
46056
46709
|
WORLD_SPAN = 90;
|
|
46057
|
-
|
|
46710
|
+
MERCATOR_MAX_LAT = 80;
|
|
46058
46711
|
PAD_FRACTION = 0.05;
|
|
46712
|
+
REGION_PAD_FRACTION = 0.12;
|
|
46059
46713
|
WORLD_LAT_SOUTH = -58;
|
|
46060
46714
|
WORLD_LAT_NORTH = 78;
|
|
46715
|
+
POI_ZOOM_FLOOR_DEG = 7;
|
|
46716
|
+
US_NATIONAL_LON_SPAN = 48;
|
|
46061
46717
|
REGION_ALIASES = {
|
|
46062
46718
|
// Common everyday names → the Natural-Earth display name actually shipped.
|
|
46063
46719
|
"united states": "united states of america",
|
|
@@ -46135,111 +46791,269 @@ var init_resolver2 = __esm({
|
|
|
46135
46791
|
}
|
|
46136
46792
|
});
|
|
46137
46793
|
|
|
46138
|
-
// src/map/
|
|
46139
|
-
|
|
46140
|
-
|
|
46141
|
-
|
|
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
|
+
}
|
|
46142
46816
|
});
|
|
46143
|
-
|
|
46144
|
-
|
|
46145
|
-
|
|
46146
|
-
|
|
46147
|
-
|
|
46148
|
-
|
|
46149
|
-
return
|
|
46150
|
-
}
|
|
46151
|
-
|
|
46152
|
-
|
|
46153
|
-
|
|
46154
|
-
|
|
46155
|
-
|
|
46156
|
-
|
|
46157
|
-
|
|
46158
|
-
|
|
46159
|
-
|
|
46160
|
-
|
|
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]);
|
|
46161
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 };
|
|
46162
46877
|
}
|
|
46163
|
-
|
|
46164
|
-
`map data assets not found near ${baseDir} (looked in ${CANDIDATE_DIRS.join(", ")}). Run \`pnpm build:map-data\` and \`pnpm build\`.`
|
|
46165
|
-
);
|
|
46878
|
+
return best?.lines ?? [text];
|
|
46166
46879
|
}
|
|
46167
|
-
function
|
|
46168
|
-
const
|
|
46169
|
-
|
|
46170
|
-
|
|
46171
|
-
}
|
|
46172
|
-
return data;
|
|
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 };
|
|
46173
46884
|
}
|
|
46174
|
-
function
|
|
46175
|
-
|
|
46176
|
-
const url = import.meta.url;
|
|
46177
|
-
if (url) return nb.dirname(nb.fileURLToPath(url));
|
|
46178
|
-
} catch {
|
|
46179
|
-
}
|
|
46180
|
-
if (typeof __dirname !== "undefined") return __dirname;
|
|
46181
|
-
return process.cwd();
|
|
46885
|
+
function rectFits(r, width, height) {
|
|
46886
|
+
return r.x >= 0 && r.y >= 0 && r.x + r.w <= width && r.y + r.h <= height;
|
|
46182
46887
|
}
|
|
46183
|
-
function
|
|
46184
|
-
|
|
46185
|
-
|
|
46186
|
-
|
|
46187
|
-
|
|
46188
|
-
|
|
46189
|
-
|
|
46190
|
-
|
|
46191
|
-
|
|
46192
|
-
|
|
46193
|
-
|
|
46194
|
-
|
|
46195
|
-
|
|
46196
|
-
|
|
46197
|
-
|
|
46198
|
-
|
|
46199
|
-
|
|
46200
|
-
|
|
46201
|
-
|
|
46202
|
-
|
|
46203
|
-
|
|
46204
|
-
|
|
46205
|
-
|
|
46206
|
-
|
|
46207
|
-
|
|
46208
|
-
|
|
46209
|
-
|
|
46210
|
-
|
|
46211
|
-
|
|
46212
|
-
|
|
46213
|
-
|
|
46214
|
-
|
|
46215
|
-
|
|
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]
|
|
46216
46962
|
});
|
|
46217
|
-
}
|
|
46218
|
-
|
|
46219
|
-
|
|
46220
|
-
|
|
46221
|
-
|
|
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;
|
|
46222
47033
|
}
|
|
46223
|
-
var
|
|
46224
|
-
var
|
|
46225
|
-
"src/map/
|
|
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"() {
|
|
46226
47037
|
"use strict";
|
|
46227
|
-
|
|
46228
|
-
|
|
46229
|
-
|
|
46230
|
-
|
|
46231
|
-
|
|
46232
|
-
|
|
46233
|
-
|
|
46234
|
-
|
|
46235
|
-
|
|
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
|
|
46236
47056
|
};
|
|
46237
|
-
CANDIDATE_DIRS = [
|
|
46238
|
-
"./data",
|
|
46239
|
-
"./map-data",
|
|
46240
|
-
"../map-data",
|
|
46241
|
-
"../src/map/data"
|
|
46242
|
-
];
|
|
46243
47057
|
}
|
|
46244
47058
|
});
|
|
46245
47059
|
|
|
@@ -46247,6 +47061,7 @@ var init_load_data = __esm({
|
|
|
46247
47061
|
import {
|
|
46248
47062
|
geoPath,
|
|
46249
47063
|
geoNaturalEarth1,
|
|
47064
|
+
geoEqualEarth,
|
|
46250
47065
|
geoEquirectangular,
|
|
46251
47066
|
geoConicEqualArea,
|
|
46252
47067
|
geoMercator,
|
|
@@ -46258,12 +47073,34 @@ function geomObject2(topo) {
|
|
|
46258
47073
|
const key = Object.keys(topo.objects)[0];
|
|
46259
47074
|
return topo.objects[key];
|
|
46260
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
|
+
}
|
|
46261
47092
|
function decodeLayer(topo) {
|
|
47093
|
+
const cached = decodeCache.get(topo);
|
|
47094
|
+
if (cached) return cached;
|
|
46262
47095
|
const out = /* @__PURE__ */ new Map();
|
|
46263
47096
|
for (const g of geomObject2(topo).geometries) {
|
|
46264
47097
|
const f = feature2(topo, g);
|
|
46265
|
-
|
|
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);
|
|
46266
47102
|
}
|
|
47103
|
+
decodeCache.set(topo, out);
|
|
46267
47104
|
return out;
|
|
46268
47105
|
}
|
|
46269
47106
|
function projectionFor(family) {
|
|
@@ -46272,38 +47109,35 @@ function projectionFor(family) {
|
|
|
46272
47109
|
return usConusProjection();
|
|
46273
47110
|
case "mercator":
|
|
46274
47111
|
return geoMercator();
|
|
47112
|
+
case "equal-earth":
|
|
47113
|
+
return geoEqualEarth();
|
|
47114
|
+
case "equirectangular":
|
|
47115
|
+
return geoEquirectangular();
|
|
46275
47116
|
case "natural-earth":
|
|
46276
47117
|
return geoNaturalEarth1();
|
|
46277
|
-
case "equirectangular":
|
|
46278
47118
|
default:
|
|
46279
47119
|
return geoEquirectangular();
|
|
46280
47120
|
}
|
|
46281
47121
|
}
|
|
46282
|
-
function mapBackgroundColor(palette, isDark = false,
|
|
46283
|
-
|
|
46284
|
-
|
|
46285
|
-
|
|
46286
|
-
|
|
46287
|
-
|
|
46288
|
-
);
|
|
46289
|
-
return mix(palette.colors.blue, palette.bg, WATER_TINT);
|
|
47122
|
+
function mapBackgroundColor(palette, isDark = false, _dataActive = false) {
|
|
47123
|
+
return mix(
|
|
47124
|
+
palette.colors.blue,
|
|
47125
|
+
palette.bg,
|
|
47126
|
+
isDark ? WATER_TINT_DARK : WATER_TINT_LIGHT
|
|
47127
|
+
);
|
|
46290
47128
|
}
|
|
46291
|
-
function mapNeutralLandColor(palette, isDark,
|
|
46292
|
-
if (dataActive)
|
|
46293
|
-
return isDark ? mix(palette.colors.gray, palette.bg, MUTED_LAND_DARK) : palette.bg;
|
|
47129
|
+
function mapNeutralLandColor(palette, isDark, _dataActive = false) {
|
|
46294
47130
|
return mix(
|
|
46295
47131
|
palette.colors.green,
|
|
46296
47132
|
palette.bg,
|
|
46297
47133
|
isDark ? LAND_TINT_DARK : LAND_TINT_LIGHT
|
|
46298
47134
|
);
|
|
46299
47135
|
}
|
|
46300
|
-
function
|
|
46301
|
-
const { palette, isDark } = opts;
|
|
46302
|
-
const { width, height } = size;
|
|
47136
|
+
function buildMapProjection(resolved, data) {
|
|
46303
47137
|
const wantsUsStates = resolved.basemaps.subdivisions.includes("us-states");
|
|
46304
|
-
const usCrisp = resolved.projection === "albers-usa" && wantsUsStates && !!data.naLand;
|
|
47138
|
+
const usCrisp = (resolved.projection === "albers-usa" || resolved.projection === "mercator") && wantsUsStates && !!data.naLand;
|
|
46305
47139
|
const worldTopo = usCrisp ? data.worldDetail : resolved.basemaps.world === "detail" ? data.worldDetail : data.worldCoarse;
|
|
46306
|
-
const worldLayer = decodeLayer(worldTopo);
|
|
47140
|
+
const worldLayer = new Map(decodeLayer(worldTopo));
|
|
46307
47141
|
if (usCrisp && data.naLand) {
|
|
46308
47142
|
const [nbW, nbS, nbE, nbN] = [-140, 10, -52, 66];
|
|
46309
47143
|
const crisp = decodeLayer(data.naLand);
|
|
@@ -46312,17 +47146,110 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46312
47146
|
if (!base) continue;
|
|
46313
47147
|
const [[bw, bs], [be, bn]] = geoBounds2(base);
|
|
46314
47148
|
if (bw >= nbW && be <= nbE && bs >= nbS && bn <= nbN)
|
|
46315
|
-
worldLayer.set(iso, cf);
|
|
47149
|
+
worldLayer.set(iso, { ...cf, properties: base.properties });
|
|
46316
47150
|
}
|
|
46317
47151
|
}
|
|
46318
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);
|
|
46319
47246
|
const usContext = usLayer !== null;
|
|
46320
47247
|
const regionStroke = isDark ? mix(palette.bg, palette.text, 78) : mix(palette.text, palette.bg, 78);
|
|
46321
47248
|
const values = resolved.regions.filter((r) => r.value !== void 0).map((r) => r.value);
|
|
46322
|
-
const
|
|
46323
|
-
const rampMin =
|
|
46324
|
-
const rampMax =
|
|
46325
|
-
const rampHue = palette.colors.red;
|
|
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);
|
|
47252
|
+
const rampHue = resolveColor(resolved.directives.regionMetricColor ?? "", palette) ?? palette.colors.red;
|
|
46326
47253
|
const hasRamp = values.length > 0;
|
|
46327
47254
|
const VALUE_NAME = hasRamp ? resolved.directives.regionMetric?.trim() || "Value" : null;
|
|
46328
47255
|
const matchColorGroup = (v) => {
|
|
@@ -46342,14 +47269,48 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46342
47269
|
activeGroup = VALUE_NAME ?? (resolved.tagGroups.length > 0 ? resolved.tagGroups[0].name : null);
|
|
46343
47270
|
}
|
|
46344
47271
|
const activeIsScore = VALUE_NAME !== null && activeGroup === VALUE_NAME;
|
|
46345
|
-
const mutedBasemap =
|
|
47272
|
+
const mutedBasemap = activeGroup !== null;
|
|
46346
47273
|
const neutralFill = mapNeutralLandColor(palette, isDark, mutedBasemap);
|
|
46347
47274
|
const water = mapBackgroundColor(palette, isDark, mutedBasemap);
|
|
47275
|
+
const lakeStroke = mix(regionStroke, water, 45);
|
|
46348
47276
|
const foreignFill = mix(
|
|
46349
47277
|
palette.colors.gray,
|
|
46350
47278
|
palette.bg,
|
|
46351
47279
|
mutedBasemap ? isDark ? MUTED_FOREIGN_DARK : MUTED_FOREIGN_LIGHT : isDark ? FOREIGN_TINT_DARK : FOREIGN_TINT_LIGHT
|
|
46352
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);
|
|
46353
47314
|
const rampBase = isDark ? mix(palette.surface, palette.text, 28) : palette.bg;
|
|
46354
47315
|
const fillForValue = (s) => {
|
|
46355
47316
|
const t = rampMax > rampMin ? (s - rampMin) / (rampMax - rampMin) : 1;
|
|
@@ -46374,47 +47335,26 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46374
47335
|
isDark ? TAG_TINT_DARK : TAG_TINT_LIGHT
|
|
46375
47336
|
);
|
|
46376
47337
|
};
|
|
47338
|
+
const directFill = (name) => {
|
|
47339
|
+
const hex = name ? resolveColor(name, palette) : null;
|
|
47340
|
+
if (!hex) return null;
|
|
47341
|
+
return mix(hex, palette.bg, isDark ? TAG_TINT_DARK : TAG_TINT_LIGHT);
|
|
47342
|
+
};
|
|
46377
47343
|
const regionFill = (r) => {
|
|
47344
|
+
const direct = directFill(r.color);
|
|
47345
|
+
if (direct) return direct;
|
|
46378
47346
|
if (activeIsScore) {
|
|
46379
47347
|
return r.value !== void 0 ? fillForValue(r.value) : neutralFill;
|
|
46380
47348
|
}
|
|
47349
|
+
if (colorizeActive) return (r.iso && colorByIso.get(r.iso)) ?? neutralFill;
|
|
46381
47350
|
return tagFill(r.tags, activeGroup) ?? neutralFill;
|
|
46382
47351
|
};
|
|
46383
47352
|
const regionById = new Map(resolved.regions.map((r) => [r.iso, r]));
|
|
46384
|
-
const
|
|
46385
|
-
const [[w, s], [e, n]] = resolved.extent;
|
|
46386
|
-
const N = 16;
|
|
46387
|
-
const coords = [];
|
|
46388
|
-
for (let i = 0; i <= N; i++) {
|
|
46389
|
-
const t = i / N;
|
|
46390
|
-
const lon = w + (e - w) * t;
|
|
46391
|
-
const lat = s + (n - s) * t;
|
|
46392
|
-
coords.push([lon, s], [lon, n], [w, lat], [e, lat]);
|
|
46393
|
-
}
|
|
46394
|
-
return {
|
|
46395
|
-
type: "Feature",
|
|
46396
|
-
properties: {},
|
|
46397
|
-
geometry: { type: "MultiPoint", coordinates: coords }
|
|
46398
|
-
};
|
|
46399
|
-
};
|
|
46400
|
-
let fitFeatures;
|
|
46401
|
-
if (resolved.projection === "albers-usa" && usLayer) {
|
|
46402
|
-
fitFeatures = [...usLayer.entries()].filter(([iso]) => !US_NON_CONUS.has(iso)).map(([, f]) => f);
|
|
46403
|
-
} else {
|
|
46404
|
-
fitFeatures = [extentOutline()];
|
|
46405
|
-
}
|
|
46406
|
-
const fitTarget = { type: "FeatureCollection", features: fitFeatures };
|
|
46407
|
-
const projection = projectionFor(resolved.projection);
|
|
46408
|
-
if (resolved.projection !== "albers-usa") {
|
|
46409
|
-
let centerLon = (resolved.extent[0][0] + resolved.extent[1][0]) / 2;
|
|
46410
|
-
if (centerLon > 180) centerLon -= 360;
|
|
46411
|
-
projection.rotate([-centerLon, 0]);
|
|
46412
|
-
}
|
|
46413
|
-
const TITLE_GAP = 16;
|
|
47353
|
+
const TITLE_GAP2 = 16;
|
|
46414
47354
|
let topPad = FIT_PAD;
|
|
46415
47355
|
if (resolved.title && resolved.pois.length > 0) {
|
|
46416
47356
|
const bannerBottom = (resolved.subtitle ? TITLE_Y + TITLE_FONT_SIZE : TITLE_Y) + TITLE_FONT_SIZE / 2;
|
|
46417
|
-
topPad = Math.max(FIT_PAD, bannerBottom +
|
|
47357
|
+
topPad = Math.max(FIT_PAD, bannerBottom + TITLE_GAP2);
|
|
46418
47358
|
}
|
|
46419
47359
|
const fitBox = [
|
|
46420
47360
|
[FIT_PAD, topPad],
|
|
@@ -46424,11 +47364,10 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46424
47364
|
]
|
|
46425
47365
|
];
|
|
46426
47366
|
projection.fitExtent(fitBox, fitTarget);
|
|
46427
|
-
const fitGB = geoBounds2(fitTarget);
|
|
46428
|
-
const fitIsGlobal = fitGB[1][0] - fitGB[0][0] >= 270 || fitGB[1][1] - fitGB[0][1] >= 130;
|
|
46429
47367
|
let path;
|
|
46430
47368
|
let project;
|
|
46431
|
-
|
|
47369
|
+
let stretchParams = null;
|
|
47370
|
+
if (fitIsGlobal && !opts.preferContain) {
|
|
46432
47371
|
const cb = geoPath(projection).bounds(fitTarget);
|
|
46433
47372
|
const bx0 = cb[0][0];
|
|
46434
47373
|
const by0 = cb[0][1];
|
|
@@ -46438,6 +47377,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46438
47377
|
const oy = fitBox[0][1];
|
|
46439
47378
|
const sx = cw > 0 ? (fitBox[1][0] - ox) / cw : 1;
|
|
46440
47379
|
const sy = ch > 0 ? (fitBox[1][1] - oy) / ch : 1;
|
|
47380
|
+
stretchParams = { sx, sy, ox, oy, bx0, by0 };
|
|
46441
47381
|
const stretch = (x, y) => [
|
|
46442
47382
|
ox + (x - bx0) * sx,
|
|
46443
47383
|
oy + (y - by0) * sy
|
|
@@ -46469,7 +47409,9 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46469
47409
|
const insets = [];
|
|
46470
47410
|
const insetRegions = [];
|
|
46471
47411
|
const insetLabelSeeds = [];
|
|
46472
|
-
|
|
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)) {
|
|
46473
47415
|
const PAD = 8;
|
|
46474
47416
|
const GAP = 12;
|
|
46475
47417
|
const yB = height - FIT_PAD;
|
|
@@ -46500,38 +47442,14 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46500
47442
|
}
|
|
46501
47443
|
return y;
|
|
46502
47444
|
};
|
|
46503
|
-
const
|
|
47445
|
+
const coastFloor = (x0, xr) => {
|
|
46504
47446
|
const n = 24;
|
|
46505
|
-
const pts = [];
|
|
46506
47447
|
let maxY = -Infinity;
|
|
46507
47448
|
for (let i = 0; i <= n; i++) {
|
|
46508
|
-
const
|
|
46509
|
-
|
|
46510
|
-
|
|
46511
|
-
|
|
46512
|
-
if (y > maxY) maxY = y;
|
|
46513
|
-
}
|
|
46514
|
-
}
|
|
46515
|
-
if (pts.length === 0) return () => yB - height * 0.42;
|
|
46516
|
-
let m = 0;
|
|
46517
|
-
if (pts.length >= 2) {
|
|
46518
|
-
let sx = 0, sy = 0, sxx = 0, sxy = 0;
|
|
46519
|
-
for (const [x, y] of pts) {
|
|
46520
|
-
sx += x;
|
|
46521
|
-
sy += y;
|
|
46522
|
-
sxx += x * x;
|
|
46523
|
-
sxy += x * y;
|
|
46524
|
-
}
|
|
46525
|
-
const den = pts.length * sxx - sx * sx;
|
|
46526
|
-
if (den !== 0) m = (pts.length * sxy - sx * sy) / den;
|
|
46527
|
-
}
|
|
46528
|
-
m = Math.max(-0.35, Math.min(0.35, m));
|
|
46529
|
-
let c = -Infinity;
|
|
46530
|
-
for (const [x, y] of pts) {
|
|
46531
|
-
const need = y - m * x + GAP;
|
|
46532
|
-
if (need > c) c = need;
|
|
46533
|
-
}
|
|
46534
|
-
return (x) => m * x + c;
|
|
47449
|
+
const y = at(x0 + (xr - x0) * i / n);
|
|
47450
|
+
if (y > maxY) maxY = y;
|
|
47451
|
+
}
|
|
47452
|
+
return maxY;
|
|
46535
47453
|
};
|
|
46536
47454
|
const placeInset = (iso, proj, boxX, iwReq) => {
|
|
46537
47455
|
const f = usLayer.get(iso);
|
|
@@ -46540,19 +47458,15 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46540
47458
|
const iw = Math.min(iwReq, width - FIT_PAD - x0 - 2 * PAD);
|
|
46541
47459
|
if (iw < 24) return boxX;
|
|
46542
47460
|
const xr = x0 + iw + 2 * PAD;
|
|
46543
|
-
const
|
|
46544
|
-
const
|
|
46545
|
-
const yR = top(xr);
|
|
47461
|
+
const floor = coastFloor(x0, xr);
|
|
47462
|
+
const topGuess = floor > -Infinity ? floor + GAP : yB - height * 0.42;
|
|
46546
47463
|
proj.fitWidth(iw, f);
|
|
46547
47464
|
const bb = geoPath(proj).bounds(f);
|
|
46548
47465
|
const sh = Number.isFinite(bb[0][0]) ? bb[1][1] - bb[0][1] : iw;
|
|
46549
47466
|
const needH = sh + 2 * PAD;
|
|
46550
|
-
let topFit =
|
|
47467
|
+
let topFit = topGuess;
|
|
46551
47468
|
const bottom = Math.min(topFit + needH, yB);
|
|
46552
47469
|
if (bottom - topFit < needH) topFit = bottom - needH;
|
|
46553
|
-
const lift = topFit - Math.max(yL, yR);
|
|
46554
|
-
const topL = yL + lift;
|
|
46555
|
-
const topR = yR + lift;
|
|
46556
47470
|
proj.fitExtent(
|
|
46557
47471
|
[
|
|
46558
47472
|
[x0 + PAD, topFit + PAD],
|
|
@@ -46562,8 +47476,18 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46562
47476
|
);
|
|
46563
47477
|
const d = geoPath(proj)(f) ?? "";
|
|
46564
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
|
+
}
|
|
46565
47489
|
const r = regionById.get(iso);
|
|
46566
|
-
let fill2 = neutralFill;
|
|
47490
|
+
let fill2 = colorizeActive ? colorByIso.get(iso) ?? neutralFill : neutralFill;
|
|
46567
47491
|
let lineNumber = -1;
|
|
46568
47492
|
if (r?.layer === "us-state") {
|
|
46569
47493
|
fill2 = regionFill(r);
|
|
@@ -46571,21 +47495,25 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46571
47495
|
}
|
|
46572
47496
|
insets.push({
|
|
46573
47497
|
x: x0,
|
|
46574
|
-
y:
|
|
47498
|
+
y: topFit,
|
|
46575
47499
|
w: xr - x0,
|
|
46576
|
-
h: bottom -
|
|
47500
|
+
h: bottom - topFit,
|
|
46577
47501
|
points: [
|
|
46578
|
-
[x0,
|
|
46579
|
-
[xr,
|
|
47502
|
+
[x0, topFit],
|
|
47503
|
+
[xr, topFit],
|
|
46580
47504
|
[xr, bottom],
|
|
46581
47505
|
[x0, bottom]
|
|
46582
|
-
]
|
|
47506
|
+
],
|
|
47507
|
+
// The FITTED inset projection (just fit to this box) — captured so the
|
|
47508
|
+
// geo-query can invert pixels inside the frame back to AK/HI coords.
|
|
47509
|
+
projection: proj,
|
|
47510
|
+
...contextLand && { contextLand }
|
|
46583
47511
|
});
|
|
46584
47512
|
insetRegions.push({
|
|
46585
47513
|
id: iso,
|
|
46586
47514
|
d,
|
|
46587
47515
|
fill: fill2,
|
|
46588
|
-
stroke: regionStroke,
|
|
47516
|
+
stroke: colorizeActive ? colorizeStroke(fill2) : regionStroke,
|
|
46589
47517
|
lineNumber,
|
|
46590
47518
|
layer: "us-state",
|
|
46591
47519
|
...r?.value !== void 0 && { value: r.value },
|
|
@@ -46598,13 +47526,16 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46598
47526
|
}
|
|
46599
47527
|
return xr;
|
|
46600
47528
|
};
|
|
46601
|
-
|
|
46602
|
-
|
|
46603
|
-
alaskaProjection(),
|
|
46604
|
-
|
|
46605
|
-
|
|
46606
|
-
|
|
46607
|
-
|
|
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
|
+
);
|
|
46608
47539
|
}
|
|
46609
47540
|
const conusFit = resolved.projection === "albers-usa" && !!usLayer;
|
|
46610
47541
|
const classifyExtent = conusFit ? geoBounds2(fitTarget) : resolved.extent;
|
|
@@ -46620,15 +47551,24 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46620
47551
|
};
|
|
46621
47552
|
const ringOverlapsView = (ring) => {
|
|
46622
47553
|
let loMin = Infinity, loMax = -Infinity, rawMin = Infinity, rawMax = -Infinity;
|
|
47554
|
+
const lons = [];
|
|
46623
47555
|
for (const [rawLon] of ring) {
|
|
46624
47556
|
const lon = normLon(rawLon);
|
|
47557
|
+
lons.push(lon);
|
|
46625
47558
|
if (lon < loMin) loMin = lon;
|
|
46626
47559
|
if (lon > loMax) loMax = lon;
|
|
46627
47560
|
if (rawLon < rawMin) rawMin = rawLon;
|
|
46628
47561
|
if (rawLon > rawMax) rawMax = rawLon;
|
|
46629
47562
|
}
|
|
46630
|
-
|
|
46631
|
-
|
|
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;
|
|
46632
47572
|
let px0 = Infinity, py0 = Infinity, px1 = -Infinity, py1 = -Infinity, anyFinite = false;
|
|
46633
47573
|
for (const [lon, lat] of ring) {
|
|
46634
47574
|
const p = project(lon, lat);
|
|
@@ -46701,7 +47641,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46701
47641
|
const regions = [];
|
|
46702
47642
|
const pushRegionLayer = (layerFeatures, layerKind, shouldCull) => {
|
|
46703
47643
|
for (const [iso, f] of layerFeatures) {
|
|
46704
|
-
if (layerKind === "us-state" && usContext && INSET_STATES.has(iso))
|
|
47644
|
+
if (layerKind === "us-state" && usContext && resolved.projection === "albers-usa" && INSET_STATES.has(iso))
|
|
46705
47645
|
continue;
|
|
46706
47646
|
if (layerKind === "country" && usContext && iso === "US") continue;
|
|
46707
47647
|
if (layerKind === "country" && iso === "AQ" && !regionById.has("AQ"))
|
|
@@ -46713,7 +47653,8 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46713
47653
|
if (!d) continue;
|
|
46714
47654
|
const isThisLayer = r?.layer === layerKind;
|
|
46715
47655
|
const isForeign = layerKind === "country" && usContext && iso !== "US";
|
|
46716
|
-
|
|
47656
|
+
const baseFill = isForeign ? foreignFill : neutralFill;
|
|
47657
|
+
let fill2 = colorizeActive ? colorByIso.get(iso) ?? baseFill : baseFill;
|
|
46717
47658
|
let label;
|
|
46718
47659
|
let lineNumber = -1;
|
|
46719
47660
|
let layer = "base";
|
|
@@ -46722,12 +47663,14 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46722
47663
|
lineNumber = r.lineNumber;
|
|
46723
47664
|
layer = layerKind;
|
|
46724
47665
|
label = r.name;
|
|
47666
|
+
} else {
|
|
47667
|
+
label = f.properties?.name;
|
|
46725
47668
|
}
|
|
46726
47669
|
regions.push({
|
|
46727
47670
|
id: iso,
|
|
46728
47671
|
d,
|
|
46729
47672
|
fill: fill2,
|
|
46730
|
-
stroke: regionStroke,
|
|
47673
|
+
stroke: colorizeActive ? colorizeStroke(fill2) : regionStroke,
|
|
46731
47674
|
lineNumber,
|
|
46732
47675
|
layer,
|
|
46733
47676
|
...label !== void 0 && { label },
|
|
@@ -46749,13 +47692,88 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46749
47692
|
id: "lake",
|
|
46750
47693
|
d,
|
|
46751
47694
|
fill: water,
|
|
46752
|
-
stroke:
|
|
47695
|
+
stroke: lakeStroke,
|
|
46753
47696
|
lineNumber: -1,
|
|
46754
47697
|
layer: "base"
|
|
46755
47698
|
});
|
|
46756
47699
|
}
|
|
46757
47700
|
}
|
|
46758
|
-
const
|
|
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;
|
|
47733
|
+
const relief = [];
|
|
47734
|
+
let reliefHatch = null;
|
|
47735
|
+
if (reliefAllowed && data.mountainRanges) {
|
|
47736
|
+
for (const [, f] of decodeLayer(data.mountainRanges)) {
|
|
47737
|
+
const viewF = isGlobalView ? dropFrameFillers(f) : cullFeatureToView(f);
|
|
47738
|
+
if (!viewF) continue;
|
|
47739
|
+
const area2 = path.area(viewF);
|
|
47740
|
+
if (!Number.isFinite(area2) || area2 < RELIEF_MIN_AREA) continue;
|
|
47741
|
+
const box = path.bounds(viewF);
|
|
47742
|
+
if (box[1][0] - box[0][0] < RELIEF_MIN_DIM || box[1][1] - box[0][1] < RELIEF_MIN_DIM)
|
|
47743
|
+
continue;
|
|
47744
|
+
const d = path(viewF) ?? "";
|
|
47745
|
+
if (!d) continue;
|
|
47746
|
+
relief.push({ d });
|
|
47747
|
+
}
|
|
47748
|
+
if (relief.length) {
|
|
47749
|
+
const darkTone = isDark ? palette.bg : palette.text;
|
|
47750
|
+
const lightTone = isDark ? palette.text : palette.bg;
|
|
47751
|
+
const reliefLandRef = colorizeActive ? isDark ? palette.surface : palette.bg : neutralFill;
|
|
47752
|
+
const landLum = relativeLuminance(reliefLandRef);
|
|
47753
|
+
const tone = Math.abs(landLum - relativeLuminance(darkTone)) > 0.04 ? darkTone : lightTone;
|
|
47754
|
+
reliefHatch = {
|
|
47755
|
+
color: mix(tone, reliefLandRef, RELIEF_HATCH_STRENGTH),
|
|
47756
|
+
spacing: RELIEF_HATCH_SPACING,
|
|
47757
|
+
width: RELIEF_HATCH_WIDTH
|
|
47758
|
+
};
|
|
47759
|
+
}
|
|
47760
|
+
}
|
|
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);
|
|
46759
47777
|
const rivers = [];
|
|
46760
47778
|
if (data.rivers) {
|
|
46761
47779
|
for (const [, f] of decodeLayer(data.rivers)) {
|
|
@@ -46776,6 +47794,9 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46776
47794
|
return R_MIN + Math.max(0, Math.min(1, t)) * (R_MAX - R_MIN);
|
|
46777
47795
|
};
|
|
46778
47796
|
const poiFill = (p) => {
|
|
47797
|
+
const directHex = p.color ? resolveColor(p.color, palette) : null;
|
|
47798
|
+
if (directHex)
|
|
47799
|
+
return { fill: directHex, stroke: mix(directHex, palette.text, 18) };
|
|
46779
47800
|
for (const group of resolved.tagGroups) {
|
|
46780
47801
|
const val = p.tags[group.name.toLowerCase()];
|
|
46781
47802
|
if (!val) continue;
|
|
@@ -46808,38 +47829,108 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46808
47829
|
const xy = project(p.lon, p.lat);
|
|
46809
47830
|
if (xy) projected.push({ p, xy });
|
|
46810
47831
|
}
|
|
46811
|
-
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);
|
|
46812
47861
|
for (const e of projected) {
|
|
46813
|
-
|
|
46814
|
-
|
|
46815
|
-
|
|
46816
|
-
|
|
46817
|
-
|
|
46818
|
-
|
|
46819
|
-
|
|
46820
|
-
|
|
46821
|
-
|
|
46822
|
-
|
|
46823
|
-
|
|
46824
|
-
|
|
46825
|
-
|
|
46826
|
-
|
|
46827
|
-
|
|
46828
|
-
|
|
46829
|
-
|
|
46830
|
-
|
|
46831
|
-
|
|
46832
|
-
|
|
46833
|
-
|
|
46834
|
-
|
|
46835
|
-
|
|
46836
|
-
|
|
46837
|
-
|
|
46838
|
-
|
|
46839
|
-
|
|
46840
|
-
|
|
46841
|
-
|
|
46842
|
-
|
|
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
|
|
46843
47934
|
});
|
|
46844
47935
|
}
|
|
46845
47936
|
const legs = [];
|
|
@@ -46889,16 +47980,26 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46889
47980
|
if (!a || !b) continue;
|
|
46890
47981
|
const mx = (a.cx + b.cx) / 2;
|
|
46891
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;
|
|
46892
47990
|
legs.push({
|
|
46893
|
-
d: legPath(a, b,
|
|
47991
|
+
d: legPath(a, b, bow.curved, bow.offset),
|
|
46894
47992
|
width: routeWidthFor(Number(leg.value)),
|
|
46895
47993
|
color: mix(palette.text, palette.bg, 72),
|
|
46896
47994
|
arrow: true,
|
|
46897
47995
|
lineNumber: leg.lineNumber,
|
|
46898
47996
|
...leg.label !== void 0 && {
|
|
46899
47997
|
label: leg.label,
|
|
46900
|
-
labelX:
|
|
46901
|
-
labelY:
|
|
47998
|
+
labelX: bow.labelX,
|
|
47999
|
+
labelY: bow.labelY,
|
|
48000
|
+
labelColor: routeLabelStyle.color,
|
|
48001
|
+
labelHalo: routeLabelStyle.halo,
|
|
48002
|
+
labelHaloColor: routeLabelStyle.haloColor
|
|
46902
48003
|
}
|
|
46903
48004
|
});
|
|
46904
48005
|
}
|
|
@@ -46926,20 +48027,29 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46926
48027
|
const a = poiScreen.get(e.fromId);
|
|
46927
48028
|
const b = poiScreen.get(e.toId);
|
|
46928
48029
|
if (!a || !b) return;
|
|
46929
|
-
const
|
|
46930
|
-
const offset = n > 1 ? (i - (n - 1) / 2) * FAN_STEP : 0;
|
|
48030
|
+
const fanOffset = n > 1 ? (i - (n - 1) / 2) * FAN_STEP : 0;
|
|
46931
48031
|
const mx = (a.cx + b.cx) / 2;
|
|
46932
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;
|
|
46933
48040
|
legs.push({
|
|
46934
|
-
d: legPath(a, b, curved, offset),
|
|
48041
|
+
d: legPath(a, b, bow.curved, bow.offset),
|
|
46935
48042
|
width: widthFor(e),
|
|
46936
48043
|
color: mix(palette.text, palette.bg, 66),
|
|
46937
48044
|
arrow: e.directed,
|
|
46938
48045
|
lineNumber: e.lineNumber,
|
|
46939
48046
|
...e.label !== void 0 && {
|
|
46940
48047
|
label: e.label,
|
|
46941
|
-
labelX:
|
|
46942
|
-
labelY:
|
|
48048
|
+
labelX: bow.labelX,
|
|
48049
|
+
labelY: bow.labelY,
|
|
48050
|
+
labelColor: edgeLabelStyle.color,
|
|
48051
|
+
labelHalo: edgeLabelStyle.halo,
|
|
48052
|
+
labelHaloColor: edgeLabelStyle.haloColor
|
|
46943
48053
|
}
|
|
46944
48054
|
});
|
|
46945
48055
|
});
|
|
@@ -46981,25 +48091,25 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46981
48091
|
}
|
|
46982
48092
|
}
|
|
46983
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));
|
|
46984
|
-
const
|
|
48094
|
+
const showRegionLabels = resolved.directives.noRegionLabels !== true;
|
|
48095
|
+
const isCompact = width < COMPACT_WIDTH_PX;
|
|
46985
48096
|
const LABEL_PADX = 6;
|
|
46986
48097
|
const LABEL_PADY = 3;
|
|
46987
|
-
const labelW = (text) => measureLegendText(text,
|
|
46988
|
-
const labelH =
|
|
48098
|
+
const labelW = (text) => measureLegendText(text, FONT2) + 2 * LABEL_PADX;
|
|
48099
|
+
const labelH = FONT2 + 2 * LABEL_PADY;
|
|
46989
48100
|
const pushRegionLabel = (x, y, text, fill2, lineNumber) => {
|
|
46990
|
-
const color =
|
|
46991
|
-
|
|
46992
|
-
|
|
46993
|
-
|
|
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
|
|
46994
48105
|
);
|
|
46995
|
-
const haloColor = color === palette.textOnFillLight ? palette.textOnFillDark : palette.textOnFillLight;
|
|
46996
48106
|
labels.push({
|
|
46997
48107
|
x,
|
|
46998
48108
|
y,
|
|
46999
48109
|
text,
|
|
47000
48110
|
anchor: "middle",
|
|
47001
48111
|
color,
|
|
47002
|
-
halo:
|
|
48112
|
+
halo: overflows,
|
|
47003
48113
|
haloColor,
|
|
47004
48114
|
lineNumber
|
|
47005
48115
|
});
|
|
@@ -47008,21 +48118,50 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47008
48118
|
US: [-98.5, 39.5]
|
|
47009
48119
|
// CONUS geographic centre (near Lebanon, Kansas)
|
|
47010
48120
|
};
|
|
47011
|
-
|
|
47012
|
-
|
|
47013
|
-
|
|
47014
|
-
|
|
47015
|
-
|
|
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;
|
|
47016
48135
|
const [[x0, y0], [x1, y1]] = path.bounds(f);
|
|
47017
|
-
const
|
|
47018
|
-
|
|
47019
|
-
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;
|
|
47020
48141
|
const c = anchor ? project(anchor[0], anchor[1]) : path.centroid(f);
|
|
47021
|
-
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));
|
|
47022
48161
|
pushRegionLabel(c[0], c[1], text, r.fill, r.lineNumber);
|
|
47023
48162
|
}
|
|
47024
48163
|
for (const seed of insetLabelSeeds) {
|
|
47025
|
-
const text =
|
|
48164
|
+
const text = isCompact ? seed.iso.replace(/^US-/, "") : seed.name;
|
|
47026
48165
|
const src = regionById.get(seed.iso);
|
|
47027
48166
|
pushRegionLabel(
|
|
47028
48167
|
seed.x,
|
|
@@ -47033,22 +48172,26 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47033
48172
|
);
|
|
47034
48173
|
}
|
|
47035
48174
|
}
|
|
47036
|
-
|
|
47037
|
-
|
|
47038
|
-
const ordered = [...pois].sort(
|
|
47039
|
-
(a, b) => a.lineNumber - b.lineNumber || (a.id < b.id ? -1 : 1)
|
|
47040
|
-
);
|
|
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));
|
|
47041
48177
|
const poiById = new Map(resolved.pois.map((q) => [q.id, q]));
|
|
47042
48178
|
const labelText = (p) => {
|
|
47043
48179
|
const src = poiById.get(p.id);
|
|
47044
48180
|
return src?.label ?? src?.name ?? p.id;
|
|
47045
48181
|
};
|
|
47046
|
-
const poiLabH =
|
|
48182
|
+
const poiLabH = FONT2 * 1.25;
|
|
47047
48183
|
const labelInfo = (p) => {
|
|
47048
48184
|
const text = labelText(p);
|
|
47049
|
-
return { text, w: measureLegendText(text,
|
|
48185
|
+
return { text, w: measureLegendText(text, FONT2) };
|
|
47050
48186
|
};
|
|
47051
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
|
+
}
|
|
47052
48195
|
const inlineRect = (p, w, side) => {
|
|
47053
48196
|
switch (side) {
|
|
47054
48197
|
case "right":
|
|
@@ -47078,11 +48221,11 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47078
48221
|
const x = side === "right" ? rect.x : side === "left" ? rect.x + w : p.cx;
|
|
47079
48222
|
labels.push({
|
|
47080
48223
|
x,
|
|
47081
|
-
y: rect.y + poiLabH / 2 +
|
|
48224
|
+
y: rect.y + poiLabH / 2 + FONT2 / 3,
|
|
47082
48225
|
text,
|
|
47083
48226
|
anchor,
|
|
47084
48227
|
color: palette.text,
|
|
47085
|
-
halo:
|
|
48228
|
+
halo: false,
|
|
47086
48229
|
haloColor: palette.bg,
|
|
47087
48230
|
poiId: p.id,
|
|
47088
48231
|
lineNumber: p.lineNumber
|
|
@@ -47093,43 +48236,60 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47093
48236
|
return rect.x >= 0 && rect.x + rect.w <= width && rect.y >= 0 && rect.y + rect.h <= height && !collides(rect);
|
|
47094
48237
|
};
|
|
47095
48238
|
const GROUP_R = 30;
|
|
47096
|
-
const
|
|
48239
|
+
const groups2 = [];
|
|
47097
48240
|
for (const p of ordered) {
|
|
47098
|
-
const near =
|
|
48241
|
+
const near = groups2.find(
|
|
47099
48242
|
(g) => g.some((q) => Math.hypot(q.cx - p.cx, q.cy - p.cy) < GROUP_R)
|
|
47100
48243
|
);
|
|
47101
48244
|
if (near) near.push(p);
|
|
47102
|
-
else
|
|
48245
|
+
else groups2.push([p]);
|
|
47103
48246
|
}
|
|
47104
48247
|
const ROW_GAP2 = 3;
|
|
47105
48248
|
const step = poiLabH + ROW_GAP2;
|
|
47106
48249
|
const COL_GAP = 16;
|
|
47107
|
-
const
|
|
47108
|
-
|
|
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) => {
|
|
47109
48252
|
const left = Math.min(...items.map((o) => o.p.cx - o.p.r));
|
|
47110
48253
|
const right = Math.max(...items.map((o) => o.p.cx + o.p.r));
|
|
47111
|
-
const cyMid = (Math.min(...items.map((o) => o.p.cy)) + Math.max(...items.map((o) => o.p.cy))) / 2;
|
|
47112
48254
|
const maxW = Math.max(...items.map((o) => o.w));
|
|
47113
|
-
const
|
|
47114
|
-
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);
|
|
47115
48257
|
const totalH = items.length * step;
|
|
47116
48258
|
let startY = cyMid - totalH / 2;
|
|
47117
48259
|
startY = Math.max(2, Math.min(startY, height - totalH - 2));
|
|
47118
|
-
items.
|
|
48260
|
+
return items.map((o, i) => {
|
|
47119
48261
|
const rowCy = startY + i * step + step / 2;
|
|
47120
|
-
|
|
47121
|
-
|
|
47122
|
-
|
|
47123
|
-
|
|
47124
|
-
|
|
47125
|
-
|
|
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);
|
|
47126
48286
|
labels.push({
|
|
47127
48287
|
x: colX,
|
|
47128
|
-
y: rowCy +
|
|
48288
|
+
y: rowCy + FONT2 / 3,
|
|
47129
48289
|
text: o.text,
|
|
47130
48290
|
anchor: side === "right" ? "start" : "end",
|
|
47131
48291
|
color: palette.text,
|
|
47132
|
-
halo:
|
|
48292
|
+
halo: false,
|
|
47133
48293
|
haloColor: palette.bg,
|
|
47134
48294
|
leader: {
|
|
47135
48295
|
x1: o.p.cx,
|
|
@@ -47139,24 +48299,141 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47139
48299
|
},
|
|
47140
48300
|
leaderColor: o.p.fill,
|
|
47141
48301
|
poiId: o.p.id,
|
|
47142
|
-
lineNumber: o.p.lineNumber
|
|
48302
|
+
lineNumber: o.p.lineNumber,
|
|
48303
|
+
...clusterId !== void 0 && { clusterMember: clusterId }
|
|
47143
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
|
|
47144
48327
|
});
|
|
47145
48328
|
};
|
|
47146
|
-
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);
|
|
47147
48339
|
if (g.length === 1) {
|
|
47148
|
-
const p =
|
|
47149
|
-
const { text, w } = labelInfo(p);
|
|
48340
|
+
const { p, text, w } = items[0];
|
|
47150
48341
|
const side = ["right", "left", "above", "below"].find(
|
|
47151
48342
|
(s) => inlineFits(p, w, s)
|
|
47152
48343
|
);
|
|
47153
|
-
if (side)
|
|
47154
|
-
|
|
47155
|
-
|
|
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;
|
|
47156
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
|
+
});
|
|
47157
48418
|
}
|
|
47158
|
-
placeColumn(g);
|
|
47159
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);
|
|
47160
48437
|
}
|
|
47161
48438
|
let legend = null;
|
|
47162
48439
|
if (!resolved.directives.noLegend) {
|
|
@@ -47191,22 +48468,33 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47191
48468
|
...resolved.caption !== void 0 && { caption: resolved.caption },
|
|
47192
48469
|
regions,
|
|
47193
48470
|
rivers,
|
|
48471
|
+
relief,
|
|
48472
|
+
reliefHatch,
|
|
48473
|
+
coastlineStyle,
|
|
47194
48474
|
legs,
|
|
47195
48475
|
pois,
|
|
48476
|
+
clusters,
|
|
47196
48477
|
labels,
|
|
47197
48478
|
legend,
|
|
47198
48479
|
insets,
|
|
47199
|
-
insetRegions
|
|
48480
|
+
insetRegions,
|
|
48481
|
+
projection,
|
|
48482
|
+
stretch: stretchParams,
|
|
48483
|
+
diagnostics: []
|
|
47200
48484
|
};
|
|
47201
48485
|
}
|
|
47202
|
-
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;
|
|
47203
48487
|
var init_layout15 = __esm({
|
|
47204
48488
|
"src/map/layout.ts"() {
|
|
47205
48489
|
"use strict";
|
|
47206
48490
|
init_color_utils();
|
|
48491
|
+
init_geo();
|
|
48492
|
+
init_colorize();
|
|
48493
|
+
init_colors();
|
|
47207
48494
|
init_label_layout();
|
|
47208
48495
|
init_legend_constants();
|
|
47209
48496
|
init_title_constants();
|
|
48497
|
+
init_context_labels();
|
|
47210
48498
|
FIT_PAD = 24;
|
|
47211
48499
|
RAMP_FLOOR = 15;
|
|
47212
48500
|
R_DEFAULT = 6;
|
|
@@ -47214,29 +48502,66 @@ var init_layout15 = __esm({
|
|
|
47214
48502
|
R_MAX = 22;
|
|
47215
48503
|
W_MIN = 1.25;
|
|
47216
48504
|
W_MAX = 8;
|
|
47217
|
-
|
|
47218
|
-
|
|
47219
|
-
|
|
47220
|
-
|
|
48505
|
+
FONT2 = 11;
|
|
48506
|
+
MAX_CLUSTER_EXTENT_FACTOR = 0.18;
|
|
48507
|
+
MAX_COLUMN_ROWS = 7;
|
|
48508
|
+
REGION_LABEL_HALO_RATIO = 4.5;
|
|
48509
|
+
LAND_TINT_LIGHT = 12;
|
|
48510
|
+
LAND_TINT_DARK = 24;
|
|
47221
48511
|
TAG_TINT_LIGHT = 60;
|
|
47222
48512
|
TAG_TINT_DARK = 68;
|
|
47223
|
-
|
|
48513
|
+
WATER_TINT_LIGHT = 24;
|
|
48514
|
+
WATER_TINT_DARK = 24;
|
|
47224
48515
|
RIVER_WIDTH = 1.3;
|
|
48516
|
+
COMPACT_WIDTH_PX = 480;
|
|
48517
|
+
RELIEF_MIN_AREA = 12;
|
|
48518
|
+
RELIEF_MIN_DIM = 2;
|
|
48519
|
+
RELIEF_HATCH_SPACING = 2;
|
|
48520
|
+
RELIEF_HATCH_WIDTH = 0.15;
|
|
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;
|
|
47225
48531
|
FOREIGN_TINT_LIGHT = 30;
|
|
47226
48532
|
FOREIGN_TINT_DARK = 62;
|
|
47227
|
-
MUTED_WATER_LIGHT = 14;
|
|
47228
|
-
MUTED_WATER_DARK = 10;
|
|
47229
48533
|
MUTED_FOREIGN_LIGHT = 28;
|
|
47230
48534
|
MUTED_FOREIGN_DARK = 16;
|
|
47231
|
-
MUTED_LAND_DARK = 24;
|
|
47232
48535
|
COLO_R = 9;
|
|
47233
48536
|
GOLDEN_ANGLE = 2.399963229728653;
|
|
48537
|
+
STACK_OVERLAP = 1;
|
|
48538
|
+
STACK_RING_MAX = 8;
|
|
48539
|
+
STACK_RING_GAP = 4;
|
|
47234
48540
|
FAN_STEP = 16;
|
|
47235
48541
|
ARC_CURVE_FRAC = 0.18;
|
|
48542
|
+
decodeCache = /* @__PURE__ */ new WeakMap();
|
|
47236
48543
|
usConusProjection = () => geoConicEqualArea().parallels([29.5, 45.5]).rotate([96, 0]);
|
|
47237
48544
|
alaskaProjection = () => geoConicEqualArea().rotate([154, 0]).center([-2, 58.5]).parallels([55, 65]);
|
|
47238
48545
|
hawaiiProjection = () => geoMercator();
|
|
47239
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
|
+
};
|
|
47240
48565
|
US_NON_CONUS = /* @__PURE__ */ new Set([
|
|
47241
48566
|
"US-AK",
|
|
47242
48567
|
"US-HI",
|
|
@@ -47256,6 +48581,58 @@ __export(renderer_exports16, {
|
|
|
47256
48581
|
renderMapForExport: () => renderMapForExport
|
|
47257
48582
|
});
|
|
47258
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
|
+
}
|
|
47259
48636
|
function renderMap(container, resolved, data, palette, isDark, onClickItem, exportDims, activeGroupOverride) {
|
|
47260
48637
|
d3Selection18.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
47261
48638
|
const width = exportDims?.width ?? container.clientWidth;
|
|
@@ -47268,6 +48645,11 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47268
48645
|
{
|
|
47269
48646
|
palette,
|
|
47270
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,
|
|
47271
48653
|
...activeGroupOverride !== void 0 && {
|
|
47272
48654
|
activeGroup: activeGroupOverride
|
|
47273
48655
|
}
|
|
@@ -47281,6 +48663,7 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47281
48663
|
const gRegions = svg.append("g").attr("class", "dgmo-map-regions");
|
|
47282
48664
|
const drawRegion = (g, r, strokeWidth) => {
|
|
47283
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);
|
|
47284
48667
|
if (r.layer !== "base") {
|
|
47285
48668
|
p.classed("dgmo-map-region", true).attr("data-region", r.id);
|
|
47286
48669
|
if (r.value !== void 0) p.attr("data-value", r.value);
|
|
@@ -47301,6 +48684,52 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47301
48684
|
}
|
|
47302
48685
|
};
|
|
47303
48686
|
for (const r of layout.regions) drawRegion(gRegions, r, 0.5);
|
|
48687
|
+
if (layout.relief.length && layout.reliefHatch) {
|
|
48688
|
+
const h = layout.reliefHatch;
|
|
48689
|
+
const rangeClipId = "dgmo-relief-clip";
|
|
48690
|
+
const landClipId = "dgmo-relief-land";
|
|
48691
|
+
const rangeClip = defs.append("clipPath").attr("id", rangeClipId);
|
|
48692
|
+
for (const s of layout.relief) rangeClip.append("path").attr("d", s.d);
|
|
48693
|
+
const landClip = defs.append("clipPath").attr("id", landClipId);
|
|
48694
|
+
for (const r of layout.regions)
|
|
48695
|
+
if (r.id !== "lake") landClip.append("path").attr("d", r.d);
|
|
48696
|
+
const gRelief = svg.append("g").attr("clip-path", `url(#${landClipId})`).append("g").attr("class", "dgmo-map-relief").attr("clip-path", `url(#${rangeClipId})`).attr("stroke", h.color).attr("stroke-width", h.width).attr("vector-effect", "non-scaling-stroke");
|
|
48697
|
+
for (let y = h.spacing; y < height; y += h.spacing) {
|
|
48698
|
+
gRelief.append("line").attr("x1", 0).attr("y1", y).attr("x2", width).attr("y2", y);
|
|
48699
|
+
}
|
|
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
|
+
}
|
|
47304
48733
|
if (layout.rivers.length) {
|
|
47305
48734
|
const gRivers = svg.append("g").attr("class", "dgmo-map-rivers").attr("fill", "none");
|
|
47306
48735
|
for (const r of layout.rivers) {
|
|
@@ -47309,15 +48738,61 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47309
48738
|
}
|
|
47310
48739
|
if (layout.insets.length) {
|
|
47311
48740
|
const insetG = svg.append("g").attr("class", "dgmo-map-insets");
|
|
47312
|
-
|
|
48741
|
+
layout.insets.forEach((box, bi) => {
|
|
47313
48742
|
const d = box.points.map((p, i) => `${i ? "L" : "M"}${p[0]},${p[1]}`).join("") + "Z";
|
|
47314
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");
|
|
47315
|
-
|
|
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
|
+
});
|
|
47316
48750
|
for (const r of layout.insetRegions) drawRegion(insetG, r, 0.5);
|
|
47317
|
-
|
|
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
|
+
};
|
|
47318
48792
|
const gLegs = svg.append("g").attr("class", "dgmo-map-legs").attr("fill", "none");
|
|
47319
48793
|
layout.legs.forEach((leg, i) => {
|
|
47320
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);
|
|
47321
48796
|
if (leg.arrow) {
|
|
47322
48797
|
const id = `dgmo-map-arrow-${i}`;
|
|
47323
48798
|
const s = arrowSize(leg.width);
|
|
@@ -47325,25 +48800,38 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47325
48800
|
p.attr("marker-end", `url(#${id})`);
|
|
47326
48801
|
}
|
|
47327
48802
|
if (leg.label !== void 0 && leg.labelX !== void 0) {
|
|
47328
|
-
emitText(
|
|
48803
|
+
const lt = emitText(
|
|
47329
48804
|
gLegs,
|
|
47330
48805
|
leg.labelX,
|
|
47331
48806
|
leg.labelY ?? 0,
|
|
47332
48807
|
leg.label,
|
|
47333
48808
|
"middle",
|
|
47334
|
-
palette.textMuted,
|
|
47335
|
-
haloColor,
|
|
47336
|
-
true,
|
|
48809
|
+
leg.labelColor ?? palette.textMuted,
|
|
48810
|
+
leg.labelHaloColor ?? haloColor,
|
|
48811
|
+
leg.labelHalo ?? true,
|
|
47337
48812
|
LABEL_FONT - 1
|
|
47338
48813
|
);
|
|
48814
|
+
wireSync(lt, leg.lineNumber);
|
|
47339
48815
|
}
|
|
47340
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
|
+
}
|
|
47341
48827
|
const gPois = svg.append("g").attr("class", "dgmo-map-pois");
|
|
47342
48828
|
for (const poi of layout.pois) {
|
|
47343
48829
|
if (poi.isOrigin) {
|
|
47344
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);
|
|
47345
48831
|
}
|
|
47346
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);
|
|
47347
48835
|
if (poi.tags) {
|
|
47348
48836
|
for (const [group, value] of Object.entries(poi.tags)) {
|
|
47349
48837
|
c.attr(`data-tag-${group.toLowerCase()}`, value.toLowerCase());
|
|
@@ -47371,12 +48859,32 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47371
48859
|
}
|
|
47372
48860
|
const gLabels = svg.append("g").attr("class", "dgmo-map-labels");
|
|
47373
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
|
+
}
|
|
47374
48879
|
if (lab.leader) {
|
|
47375
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(
|
|
47376
48881
|
"stroke",
|
|
47377
48882
|
lab.leaderColor ?? mix(palette.textMuted, palette.bg, 60)
|
|
47378
48883
|
).attr("stroke-width", lab.leaderColor ? 1 : 0.75);
|
|
47379
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);
|
|
47380
48888
|
}
|
|
47381
48889
|
const t = emitText(
|
|
47382
48890
|
gLabels,
|
|
@@ -47387,11 +48895,38 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47387
48895
|
lab.color,
|
|
47388
48896
|
lab.haloColor,
|
|
47389
48897
|
lab.halo,
|
|
47390
|
-
LABEL_FONT
|
|
48898
|
+
LABEL_FONT,
|
|
48899
|
+
lab.italic,
|
|
48900
|
+
lab.letterSpacing,
|
|
48901
|
+
lab.lines
|
|
47391
48902
|
);
|
|
47392
48903
|
if (lab.poiId !== void 0) {
|
|
47393
48904
|
t.attr("data-poi", lab.poiId).style("cursor", "default");
|
|
47394
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
|
+
}
|
|
47395
48930
|
}
|
|
47396
48931
|
if (layout.legend) {
|
|
47397
48932
|
const legendY = (layout.title ? TITLE_Y + TITLE_FONT_SIZE : 0) + (layout.subtitle ? TITLE_FONT_SIZE : 0) + 8;
|
|
@@ -47425,10 +48960,10 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47425
48960
|
}
|
|
47426
48961
|
}
|
|
47427
48962
|
if (layout.title) {
|
|
47428
|
-
svg.append("text").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);
|
|
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);
|
|
47429
48964
|
}
|
|
47430
48965
|
if (layout.subtitle) {
|
|
47431
|
-
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);
|
|
47432
48967
|
}
|
|
47433
48968
|
if (layout.caption) {
|
|
47434
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);
|
|
@@ -47437,10 +48972,21 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47437
48972
|
function renderMapForExport(container, resolved, data, palette, isDark, exportDims) {
|
|
47438
48973
|
renderMap(container, resolved, data, palette, isDark, void 0, exportDims);
|
|
47439
48974
|
}
|
|
47440
|
-
function emitText(g, x, y, text, anchor, color, halo, withHalo, fontSize) {
|
|
47441
|
-
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);
|
|
47442
48988
|
if (withHalo) {
|
|
47443
|
-
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);
|
|
47444
48990
|
}
|
|
47445
48991
|
return t;
|
|
47446
48992
|
}
|
|
@@ -47457,6 +49003,178 @@ var init_renderer16 = __esm({
|
|
|
47457
49003
|
}
|
|
47458
49004
|
});
|
|
47459
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
|
+
|
|
49056
|
+
// src/map/load-data.ts
|
|
49057
|
+
var load_data_exports = {};
|
|
49058
|
+
__export(load_data_exports, {
|
|
49059
|
+
loadMapData: () => loadMapData
|
|
49060
|
+
});
|
|
49061
|
+
async function loadNodeBuiltins() {
|
|
49062
|
+
const [{ readFile }, { fileURLToPath }, { dirname, resolve }] = await Promise.all([
|
|
49063
|
+
import("fs/promises"),
|
|
49064
|
+
import("url"),
|
|
49065
|
+
import("path")
|
|
49066
|
+
]);
|
|
49067
|
+
return { readFile, fileURLToPath, dirname, resolve };
|
|
49068
|
+
}
|
|
49069
|
+
async function readJson(nb, dir, name) {
|
|
49070
|
+
return JSON.parse(await nb.readFile(nb.resolve(dir, name), "utf8"));
|
|
49071
|
+
}
|
|
49072
|
+
async function firstExistingDir(nb, baseDir) {
|
|
49073
|
+
for (const rel of CANDIDATE_DIRS) {
|
|
49074
|
+
const dir = nb.resolve(baseDir, rel);
|
|
49075
|
+
try {
|
|
49076
|
+
await nb.readFile(nb.resolve(dir, FILES.gazetteer), "utf8");
|
|
49077
|
+
return dir;
|
|
49078
|
+
} catch {
|
|
49079
|
+
}
|
|
49080
|
+
}
|
|
49081
|
+
throw new Error(
|
|
49082
|
+
`map data assets not found near ${baseDir} (looked in ${CANDIDATE_DIRS.join(", ")}). Run \`pnpm build:map-data\` and \`pnpm build\`.`
|
|
49083
|
+
);
|
|
49084
|
+
}
|
|
49085
|
+
function validate(data) {
|
|
49086
|
+
const topoOk = (t) => !!t && t.type === "Topology" && !!t.objects;
|
|
49087
|
+
if (!topoOk(data.worldCoarse) || !topoOk(data.worldDetail) || !topoOk(data.usStates) || !data.gazetteer || !Array.isArray(data.gazetteer.cities) || !data.gazetteer.byName) {
|
|
49088
|
+
throw new Error("map data assets are malformed (failed shape validation)");
|
|
49089
|
+
}
|
|
49090
|
+
return data;
|
|
49091
|
+
}
|
|
49092
|
+
function moduleBaseDir(nb) {
|
|
49093
|
+
try {
|
|
49094
|
+
const url = import.meta.url;
|
|
49095
|
+
if (url) return nb.dirname(nb.fileURLToPath(url));
|
|
49096
|
+
} catch {
|
|
49097
|
+
}
|
|
49098
|
+
if (typeof __dirname !== "undefined") return __dirname;
|
|
49099
|
+
return process.cwd();
|
|
49100
|
+
}
|
|
49101
|
+
function loadMapData() {
|
|
49102
|
+
cache ??= (async () => {
|
|
49103
|
+
const nb = await loadNodeBuiltins();
|
|
49104
|
+
const dir = await firstExistingDir(nb, moduleBaseDir(nb));
|
|
49105
|
+
const [
|
|
49106
|
+
worldCoarse,
|
|
49107
|
+
worldDetail,
|
|
49108
|
+
usStates,
|
|
49109
|
+
lakes,
|
|
49110
|
+
rivers,
|
|
49111
|
+
mountainRanges,
|
|
49112
|
+
naLand,
|
|
49113
|
+
naLakes,
|
|
49114
|
+
waterBodies,
|
|
49115
|
+
gazetteer
|
|
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.
|
|
49121
|
+
readJson(nb, dir, FILES.worldCoarse),
|
|
49122
|
+
readJson(nb, dir, FILES.worldDetail),
|
|
49123
|
+
readJson(nb, dir, FILES.usStates),
|
|
49124
|
+
// Lakes/rivers/mountain/NA/water assets are optional — older bundles may predate them.
|
|
49125
|
+
readJson(nb, dir, FILES.lakes).catch(() => void 0),
|
|
49126
|
+
readJson(nb, dir, FILES.rivers).catch(() => void 0),
|
|
49127
|
+
readJson(nb, dir, FILES.mountainRanges).catch(
|
|
49128
|
+
() => void 0
|
|
49129
|
+
),
|
|
49130
|
+
readJson(nb, dir, FILES.naLand).catch(() => void 0),
|
|
49131
|
+
readJson(nb, dir, FILES.naLakes).catch(() => void 0),
|
|
49132
|
+
readJson(nb, dir, FILES.waterBodies).catch(() => void 0),
|
|
49133
|
+
readJson(nb, dir, FILES.gazetteer)
|
|
49134
|
+
]);
|
|
49135
|
+
return validate({
|
|
49136
|
+
worldCoarse,
|
|
49137
|
+
worldDetail,
|
|
49138
|
+
usStates,
|
|
49139
|
+
gazetteer,
|
|
49140
|
+
...lakes && { lakes },
|
|
49141
|
+
...rivers && { rivers },
|
|
49142
|
+
...mountainRanges && { mountainRanges },
|
|
49143
|
+
...naLand && { naLand },
|
|
49144
|
+
...naLakes && { naLakes },
|
|
49145
|
+
...waterBodies && { waterBodies }
|
|
49146
|
+
});
|
|
49147
|
+
})().catch((e) => {
|
|
49148
|
+
cache = void 0;
|
|
49149
|
+
throw e;
|
|
49150
|
+
});
|
|
49151
|
+
return cache;
|
|
49152
|
+
}
|
|
49153
|
+
var FILES, CANDIDATE_DIRS, cache;
|
|
49154
|
+
var init_load_data = __esm({
|
|
49155
|
+
"src/map/load-data.ts"() {
|
|
49156
|
+
"use strict";
|
|
49157
|
+
FILES = {
|
|
49158
|
+
worldCoarse: "world-coarse.json",
|
|
49159
|
+
worldDetail: "world-detail.json",
|
|
49160
|
+
usStates: "us-states.json",
|
|
49161
|
+
lakes: "lakes.json",
|
|
49162
|
+
rivers: "rivers.json",
|
|
49163
|
+
mountainRanges: "mountain-ranges.json",
|
|
49164
|
+
naLand: "na-land.json",
|
|
49165
|
+
naLakes: "na-lakes.json",
|
|
49166
|
+
waterBodies: "water-bodies.json",
|
|
49167
|
+
gazetteer: "gazetteer.json"
|
|
49168
|
+
};
|
|
49169
|
+
CANDIDATE_DIRS = [
|
|
49170
|
+
"./data",
|
|
49171
|
+
"./map-data",
|
|
49172
|
+
"../map-data",
|
|
49173
|
+
"../src/map/data"
|
|
49174
|
+
];
|
|
49175
|
+
}
|
|
49176
|
+
});
|
|
49177
|
+
|
|
47460
49178
|
// src/pyramid/renderer.ts
|
|
47461
49179
|
var renderer_exports17 = {};
|
|
47462
49180
|
__export(renderer_exports17, {
|
|
@@ -49459,8 +51177,8 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
|
|
|
49459
51177
|
const lines = splitParticipantLabel(p.label, LABEL_MAX_CHARS);
|
|
49460
51178
|
if (lines.length === 0) continue;
|
|
49461
51179
|
const widest = Math.max(...lines.map((l) => l.length));
|
|
49462
|
-
const
|
|
49463
|
-
uniformBoxWidth = Math.max(uniformBoxWidth,
|
|
51180
|
+
const labelWidth2 = widest * LABEL_CHAR_WIDTH + 10;
|
|
51181
|
+
uniformBoxWidth = Math.max(uniformBoxWidth, labelWidth2);
|
|
49464
51182
|
}
|
|
49465
51183
|
uniformBoxWidth = Math.min(MAX_BOX_WIDTH, uniformBoxWidth);
|
|
49466
51184
|
const effectiveGap = Math.max(PARTICIPANT_GAP, uniformBoxWidth + 30);
|
|
@@ -52159,15 +53877,15 @@ function renderArcDiagram(container, parsed, palette, _isDark, onClickItem, expo
|
|
|
52159
53877
|
textColor,
|
|
52160
53878
|
onClickItem
|
|
52161
53879
|
);
|
|
52162
|
-
const
|
|
52163
|
-
for (const node of nodes)
|
|
53880
|
+
const neighbors2 = /* @__PURE__ */ new Map();
|
|
53881
|
+
for (const node of nodes) neighbors2.set(node, /* @__PURE__ */ new Set());
|
|
52164
53882
|
for (const link of links) {
|
|
52165
|
-
|
|
52166
|
-
|
|
53883
|
+
neighbors2.get(link.source).add(link.target);
|
|
53884
|
+
neighbors2.get(link.target).add(link.source);
|
|
52167
53885
|
}
|
|
52168
53886
|
const FADE_OPACITY3 = 0.1;
|
|
52169
53887
|
function handleMouseEnter(hovered) {
|
|
52170
|
-
const connected =
|
|
53888
|
+
const connected = neighbors2.get(hovered);
|
|
52171
53889
|
g.selectAll(".arc-link").each(function() {
|
|
52172
53890
|
const el = d3Selection23.select(this);
|
|
52173
53891
|
const src = el.attr("data-source");
|
|
@@ -54102,7 +55820,7 @@ function renderVenn(container, parsed, palette, _isDark, onClickItem, exportDims
|
|
|
54102
55820
|
8,
|
|
54103
55821
|
Math.floor(OVERLAP_WRAP_TARGET_W / OVERLAP_CH_W)
|
|
54104
55822
|
);
|
|
54105
|
-
function
|
|
55823
|
+
function wrapLabel3(text, maxChars) {
|
|
54106
55824
|
const words = text.split(/\s+/).filter(Boolean);
|
|
54107
55825
|
const lines = [];
|
|
54108
55826
|
let cur = "";
|
|
@@ -54148,7 +55866,7 @@ function renderVenn(container, parsed, palette, _isDark, onClickItem, exportDims
|
|
|
54148
55866
|
if (!ov.label) continue;
|
|
54149
55867
|
const idxs = ov.sets.map((s) => vennSets.findIndex((vs) => vs.name === s));
|
|
54150
55868
|
if (idxs.some((idx) => idx < 0)) continue;
|
|
54151
|
-
const lines =
|
|
55869
|
+
const lines = wrapLabel3(ov.label, MAX_WRAP_CHARS);
|
|
54152
55870
|
wrappedOverlapLabels.set(ov, lines);
|
|
54153
55871
|
const dir = predictOverlapDirRaw(idxs);
|
|
54154
55872
|
const longest = lines.reduce((m, l) => Math.max(m, l.length), 0);
|
|
@@ -55585,25 +57303,29 @@ async function renderForExport(content, theme, palette, viewState, options) {
|
|
|
55585
57303
|
if (detectedType === "map") {
|
|
55586
57304
|
const { parseMap: parseMap2 } = await Promise.resolve().then(() => (init_parser12(), parser_exports11));
|
|
55587
57305
|
const { resolveMap: resolveMap2 } = await Promise.resolve().then(() => (init_resolver2(), resolver_exports));
|
|
55588
|
-
const { loadMapData: loadMapData2 } = await Promise.resolve().then(() => (init_load_data(), load_data_exports));
|
|
55589
57306
|
const { renderMapForExport: renderMapForExport2 } = await Promise.resolve().then(() => (init_renderer16(), renderer_exports16));
|
|
57307
|
+
const { mapExportDimensions: mapExportDimensions2 } = await Promise.resolve().then(() => (init_dimensions(), dimensions_exports));
|
|
55590
57308
|
const effectivePalette2 = await resolveExportPalette(theme, palette);
|
|
55591
57309
|
const mapParsed = parseMap2(content);
|
|
55592
|
-
let mapData;
|
|
55593
|
-
|
|
55594
|
-
|
|
55595
|
-
|
|
55596
|
-
|
|
57310
|
+
let mapData = options?.mapData;
|
|
57311
|
+
if (!mapData) {
|
|
57312
|
+
const { loadMapData: loadMapData2 } = await Promise.resolve().then(() => (init_load_data(), load_data_exports));
|
|
57313
|
+
try {
|
|
57314
|
+
mapData = await loadMapData2();
|
|
57315
|
+
} catch {
|
|
57316
|
+
return "";
|
|
57317
|
+
}
|
|
55597
57318
|
}
|
|
55598
57319
|
const mapResolved = resolveMap2(mapParsed, mapData);
|
|
55599
|
-
const
|
|
57320
|
+
const dims2 = mapExportDimensions2(mapResolved, mapData, EXPORT_WIDTH);
|
|
57321
|
+
const container2 = createExportContainer(dims2.width, dims2.height);
|
|
55600
57322
|
renderMapForExport2(
|
|
55601
57323
|
container2,
|
|
55602
57324
|
mapResolved,
|
|
55603
57325
|
mapData,
|
|
55604
57326
|
effectivePalette2,
|
|
55605
57327
|
theme === "dark",
|
|
55606
|
-
|
|
57328
|
+
dims2
|
|
55607
57329
|
);
|
|
55608
57330
|
return finalizeSvgExport(container2, theme, effectivePalette2);
|
|
55609
57331
|
}
|
|
@@ -56445,7 +58167,8 @@ async function render(content, options) {
|
|
|
56445
58167
|
...options?.c4Container !== void 0 && {
|
|
56446
58168
|
c4Container: options.c4Container
|
|
56447
58169
|
},
|
|
56448
|
-
...options?.tagGroup !== void 0 && { tagGroup: options.tagGroup }
|
|
58170
|
+
...options?.tagGroup !== void 0 && { tagGroup: options.tagGroup },
|
|
58171
|
+
...options?.mapData !== void 0 && { mapData: options.mapData }
|
|
56449
58172
|
});
|
|
56450
58173
|
if (chartType === "map") {
|
|
56451
58174
|
try {
|
|
@@ -56456,7 +58179,7 @@ async function render(content, options) {
|
|
|
56456
58179
|
Promise.resolve().then(() => (init_load_data(), load_data_exports))
|
|
56457
58180
|
]
|
|
56458
58181
|
);
|
|
56459
|
-
const data = await loadMapData2();
|
|
58182
|
+
const data = options?.mapData ?? await loadMapData2();
|
|
56460
58183
|
diagnostics = [...resolveMap2(parseMap2(content), data).diagnostics];
|
|
56461
58184
|
} catch {
|
|
56462
58185
|
}
|
|
@@ -56624,21 +58347,20 @@ var DIRECTIVE_KEYWORDS = /* @__PURE__ */ new Set([
|
|
|
56624
58347
|
// Sequence
|
|
56625
58348
|
"activations",
|
|
56626
58349
|
"no-activations",
|
|
56627
|
-
// Map (§24B) directives
|
|
56628
|
-
"region",
|
|
56629
|
-
"projection",
|
|
58350
|
+
// Map (§24B) directives — cosmetics on by default, bare `no-*` opt-outs
|
|
56630
58351
|
"region-metric",
|
|
56631
58352
|
"poi-metric",
|
|
56632
58353
|
"flow-metric",
|
|
56633
|
-
"
|
|
56634
|
-
"
|
|
56635
|
-
"default-country",
|
|
56636
|
-
"default-state",
|
|
56637
|
-
"no-legend",
|
|
56638
|
-
"muted",
|
|
56639
|
-
"natural",
|
|
56640
|
-
"subtitle",
|
|
58354
|
+
"locale",
|
|
58355
|
+
"active-tag",
|
|
56641
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",
|
|
56642
58364
|
"poi",
|
|
56643
58365
|
"route",
|
|
56644
58366
|
// Data charts
|
|
@@ -56931,7 +58653,11 @@ var ATTRIBUTE_KEYS = /* @__PURE__ */ new Set([
|
|
|
56931
58653
|
"collapsed",
|
|
56932
58654
|
"tech",
|
|
56933
58655
|
"span",
|
|
56934
|
-
"split"
|
|
58656
|
+
"split",
|
|
58657
|
+
// Map (§24B) reserved keys
|
|
58658
|
+
"value",
|
|
58659
|
+
"label",
|
|
58660
|
+
"style"
|
|
56935
58661
|
]);
|
|
56936
58662
|
function applyAttributeKeys(tokens) {
|
|
56937
58663
|
for (let i = 0; i < tokens.length - 1; i++) {
|
|
@@ -57304,7 +59030,7 @@ pre.dgmo, code.language-dgmo, pre > code.language-dgmo,
|
|
|
57304
59030
|
|
|
57305
59031
|
// src/auto/index.ts
|
|
57306
59032
|
init_safe_href();
|
|
57307
|
-
var VERSION = "0.
|
|
59033
|
+
var VERSION = "0.22.0";
|
|
57308
59034
|
var DEFAULTS = {
|
|
57309
59035
|
theme: "auto",
|
|
57310
59036
|
palette: "nord",
|