@diagrammo/dgmo 0.21.1 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -6
- package/dist/advanced.cjs +2003 -466
- package/dist/advanced.d.cts +5714 -0
- package/dist/advanced.d.ts +5714 -0
- package/dist/advanced.js +1999 -466
- package/dist/auto.cjs +2048 -449
- package/dist/auto.d.cts +39 -0
- package/dist/auto.d.ts +39 -0
- package/dist/auto.js +121 -121
- package/dist/auto.mjs +2050 -450
- package/dist/cli.cjs +170 -170
- package/dist/editor.cjs +13 -16
- package/dist/editor.js +13 -16
- package/dist/highlight.cjs +15 -13
- package/dist/highlight.js +15 -13
- package/dist/index.cjs +2032 -435
- package/dist/index.d.cts +339 -0
- package/dist/index.d.ts +339 -0
- package/dist/index.js +2034 -436
- package/dist/internal.cjs +2003 -466
- package/dist/internal.d.cts +5714 -0
- package/dist/internal.d.ts +5714 -0
- package/dist/internal.js +1999 -466
- package/dist/map-data/water-bodies.json +1 -0
- package/docs/language-reference.md +20 -9
- package/gallery/fixtures/map-categorical-world.dgmo +16 -0
- package/gallery/fixtures/map-categorical.dgmo +0 -1
- package/gallery/fixtures/map-choropleth.dgmo +0 -1
- package/gallery/fixtures/map-coastline.dgmo +7 -0
- package/gallery/fixtures/map-colorize.dgmo +11 -0
- package/gallery/fixtures/map-direct-color.dgmo +0 -1
- package/gallery/fixtures/map-reference-world.dgmo +11 -0
- package/gallery/fixtures/map-region-scope.dgmo +0 -3
- package/gallery/fixtures/map-route.dgmo +0 -1
- package/package.json +1 -1
- package/src/advanced.ts +12 -1
- package/src/boxes-and-lines/renderer.ts +39 -12
- package/src/cli.ts +1 -1
- package/src/completion.ts +32 -25
- package/src/cycle/renderer.ts +14 -1
- package/src/d3.ts +8 -2
- package/src/editor/highlight-api.ts +4 -0
- package/src/editor/keywords.ts +13 -16
- package/src/infra/renderer.ts +35 -7
- package/src/map/colorize.ts +54 -0
- package/src/map/context-labels.ts +429 -0
- package/src/map/data/types.ts +34 -0
- package/src/map/data/water-bodies.json +1 -0
- package/src/map/dimensions.ts +117 -0
- package/src/map/geo-query.ts +21 -3
- package/src/map/geo.ts +47 -1
- package/src/map/layout.ts +1300 -251
- package/src/map/load-data.ts +10 -2
- package/src/map/parser.ts +42 -116
- package/src/map/renderer.ts +512 -13
- package/src/map/resolved-types.ts +16 -2
- package/src/map/resolver.ts +208 -59
- package/src/map/types.ts +30 -32
- package/src/mindmap/renderer.ts +10 -1
- package/src/palettes/atlas.ts +77 -0
- package/src/palettes/blueprint.ts +73 -0
- package/src/palettes/color-utils.ts +58 -1
- package/src/palettes/index.ts +12 -3
- package/src/palettes/slate.ts +73 -0
- package/src/palettes/tidewater.ts +73 -0
- package/src/render.ts +8 -1
- package/src/tech-radar/renderer.ts +3 -0
- package/src/tech-radar/types.ts +3 -0
- package/src/utils/d3-types.ts +5 -0
- package/src/utils/legend-layout.ts +21 -4
- package/src/utils/legend-types.ts +7 -0
- package/src/utils/reserved-key-registry.ts +3 -0
- package/src/palettes/bold.ts +0 -67
package/dist/auto.cjs
CHANGED
|
@@ -93,18 +93,18 @@ function computeQuadrantPointLabels(points, chartBounds, obstacles, pointRadius,
|
|
|
93
93
|
const results = [];
|
|
94
94
|
for (let i = 0; i < points.length; i++) {
|
|
95
95
|
const pt = points[i];
|
|
96
|
-
const
|
|
96
|
+
const labelWidth2 = pt.label.length * fontSize * CHAR_WIDTH_RATIO + 8;
|
|
97
97
|
let best = null;
|
|
98
98
|
const directions = [
|
|
99
99
|
{
|
|
100
100
|
// Above
|
|
101
101
|
gen: (offset) => {
|
|
102
|
-
const lx = pt.cx -
|
|
102
|
+
const lx = pt.cx - labelWidth2 / 2;
|
|
103
103
|
const ly = pt.cy - offset - labelHeight;
|
|
104
|
-
if (ly < chartBounds.top || lx < chartBounds.left || lx +
|
|
104
|
+
if (ly < chartBounds.top || lx < chartBounds.left || lx + labelWidth2 > chartBounds.right)
|
|
105
105
|
return null;
|
|
106
106
|
return {
|
|
107
|
-
rect: { x: lx, y: ly, w:
|
|
107
|
+
rect: { x: lx, y: ly, w: labelWidth2, h: labelHeight },
|
|
108
108
|
textX: pt.cx,
|
|
109
109
|
textY: ly + labelHeight / 2,
|
|
110
110
|
anchor: "middle"
|
|
@@ -114,12 +114,12 @@ function computeQuadrantPointLabels(points, chartBounds, obstacles, pointRadius,
|
|
|
114
114
|
{
|
|
115
115
|
// Below
|
|
116
116
|
gen: (offset) => {
|
|
117
|
-
const lx = pt.cx -
|
|
117
|
+
const lx = pt.cx - labelWidth2 / 2;
|
|
118
118
|
const ly = pt.cy + offset;
|
|
119
|
-
if (ly + labelHeight > chartBounds.bottom || lx < chartBounds.left || lx +
|
|
119
|
+
if (ly + labelHeight > chartBounds.bottom || lx < chartBounds.left || lx + labelWidth2 > chartBounds.right)
|
|
120
120
|
return null;
|
|
121
121
|
return {
|
|
122
|
-
rect: { x: lx, y: ly, w:
|
|
122
|
+
rect: { x: lx, y: ly, w: labelWidth2, h: labelHeight },
|
|
123
123
|
textX: pt.cx,
|
|
124
124
|
textY: ly + labelHeight / 2,
|
|
125
125
|
anchor: "middle"
|
|
@@ -131,10 +131,10 @@ function computeQuadrantPointLabels(points, chartBounds, obstacles, pointRadius,
|
|
|
131
131
|
gen: (offset) => {
|
|
132
132
|
const lx = pt.cx + offset;
|
|
133
133
|
const ly = pt.cy - labelHeight / 2;
|
|
134
|
-
if (lx +
|
|
134
|
+
if (lx + labelWidth2 > chartBounds.right || ly < chartBounds.top || ly + labelHeight > chartBounds.bottom)
|
|
135
135
|
return null;
|
|
136
136
|
return {
|
|
137
|
-
rect: { x: lx, y: ly, w:
|
|
137
|
+
rect: { x: lx, y: ly, w: labelWidth2, h: labelHeight },
|
|
138
138
|
textX: lx,
|
|
139
139
|
textY: pt.cy,
|
|
140
140
|
anchor: "start"
|
|
@@ -144,13 +144,13 @@ function computeQuadrantPointLabels(points, chartBounds, obstacles, pointRadius,
|
|
|
144
144
|
{
|
|
145
145
|
// Left
|
|
146
146
|
gen: (offset) => {
|
|
147
|
-
const lx = pt.cx - offset -
|
|
147
|
+
const lx = pt.cx - offset - labelWidth2;
|
|
148
148
|
const ly = pt.cy - labelHeight / 2;
|
|
149
149
|
if (lx < chartBounds.left || ly < chartBounds.top || ly + labelHeight > chartBounds.bottom)
|
|
150
150
|
return null;
|
|
151
151
|
return {
|
|
152
|
-
rect: { x: lx, y: ly, w:
|
|
153
|
-
textX: lx +
|
|
152
|
+
rect: { x: lx, y: ly, w: labelWidth2, h: labelHeight },
|
|
153
|
+
textX: lx + labelWidth2,
|
|
154
154
|
textY: pt.cy,
|
|
155
155
|
anchor: "end"
|
|
156
156
|
};
|
|
@@ -200,10 +200,10 @@ function computeQuadrantPointLabels(points, chartBounds, obstacles, pointRadius,
|
|
|
200
200
|
}
|
|
201
201
|
}
|
|
202
202
|
if (!best) {
|
|
203
|
-
const lx = pt.cx -
|
|
203
|
+
const lx = pt.cx - labelWidth2 / 2;
|
|
204
204
|
const ly = pt.cy - minGap - labelHeight;
|
|
205
205
|
best = {
|
|
206
|
-
rect: { x: lx, y: ly, w:
|
|
206
|
+
rect: { x: lx, y: ly, w: labelWidth2, h: labelHeight },
|
|
207
207
|
textX: pt.cx,
|
|
208
208
|
textY: ly + labelHeight / 2,
|
|
209
209
|
anchor: "middle",
|
|
@@ -763,6 +763,9 @@ var init_reserved_key_registry = __esm({
|
|
|
763
763
|
"value",
|
|
764
764
|
"label",
|
|
765
765
|
"style"
|
|
766
|
+
// `surface:` was removed in the 2026-06-02 defaults-on review — it is no longer
|
|
767
|
+
// a recognized metadata key (the route/edge surface feature was cut; §24B.7).
|
|
768
|
+
// A stray `surface: water` is no longer captured as a reserved key.
|
|
766
769
|
]);
|
|
767
770
|
ORG_REGISTRY = staticRegistry([
|
|
768
771
|
"color",
|
|
@@ -1825,77 +1828,266 @@ function getSegmentColors(palette, count) {
|
|
|
1825
1828
|
(_, i) => hslToHex(Math.round((startHue + i * step) % 360), avgS, avgL)
|
|
1826
1829
|
);
|
|
1827
1830
|
}
|
|
1831
|
+
function politicalTints(palette, count, isDark) {
|
|
1832
|
+
if (count <= 0) return [];
|
|
1833
|
+
const base = isDark ? palette.surface : palette.bg;
|
|
1834
|
+
const c = palette.colors;
|
|
1835
|
+
const swatches = [
|
|
1836
|
+
.../* @__PURE__ */ new Set([
|
|
1837
|
+
c.green,
|
|
1838
|
+
c.yellow,
|
|
1839
|
+
c.orange,
|
|
1840
|
+
c.purple,
|
|
1841
|
+
c.red,
|
|
1842
|
+
c.teal,
|
|
1843
|
+
c.cyan,
|
|
1844
|
+
c.blue
|
|
1845
|
+
])
|
|
1846
|
+
];
|
|
1847
|
+
const bands = isDark ? POLITICAL_TINT_BANDS.dark : POLITICAL_TINT_BANDS.light;
|
|
1848
|
+
const out = [];
|
|
1849
|
+
for (const pct of bands) {
|
|
1850
|
+
if (out.length >= count) break;
|
|
1851
|
+
for (const s of swatches) out.push(mix(s, base, pct));
|
|
1852
|
+
}
|
|
1853
|
+
return out.slice(0, count);
|
|
1854
|
+
}
|
|
1855
|
+
var POLITICAL_TINT_BANDS;
|
|
1828
1856
|
var init_color_utils = __esm({
|
|
1829
1857
|
"src/palettes/color-utils.ts"() {
|
|
1830
1858
|
"use strict";
|
|
1859
|
+
POLITICAL_TINT_BANDS = {
|
|
1860
|
+
light: [32, 48, 64, 80],
|
|
1861
|
+
dark: [44, 58, 72, 86]
|
|
1862
|
+
};
|
|
1831
1863
|
}
|
|
1832
1864
|
});
|
|
1833
1865
|
|
|
1834
|
-
// src/palettes/
|
|
1835
|
-
var
|
|
1836
|
-
var
|
|
1837
|
-
"src/palettes/
|
|
1866
|
+
// src/palettes/atlas.ts
|
|
1867
|
+
var atlasPalette;
|
|
1868
|
+
var init_atlas = __esm({
|
|
1869
|
+
"src/palettes/atlas.ts"() {
|
|
1838
1870
|
"use strict";
|
|
1839
1871
|
init_registry();
|
|
1840
|
-
|
|
1841
|
-
id: "
|
|
1842
|
-
name: "
|
|
1872
|
+
atlasPalette = {
|
|
1873
|
+
id: "atlas",
|
|
1874
|
+
name: "Atlas",
|
|
1843
1875
|
light: {
|
|
1844
|
-
bg: "#
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1876
|
+
bg: "#f3ead3",
|
|
1877
|
+
// warm manila / parchment
|
|
1878
|
+
surface: "#ece0c0",
|
|
1879
|
+
// deeper paper (cards, panels)
|
|
1880
|
+
overlay: "#e8dab8",
|
|
1881
|
+
// popovers, dropdowns
|
|
1882
|
+
border: "#bcaa86",
|
|
1883
|
+
// muted sepia rule line
|
|
1884
|
+
text: "#463a26",
|
|
1885
|
+
// aged sepia-brown ink
|
|
1886
|
+
textMuted: "#7a6a4f",
|
|
1887
|
+
// faded annotation ink
|
|
1888
|
+
textOnFillLight: "#f7f1de",
|
|
1889
|
+
// parchment (light text on dark fills)
|
|
1890
|
+
textOnFillDark: "#3a2e1c",
|
|
1891
|
+
// deep ink (dark text on light fills)
|
|
1892
|
+
primary: "#5b7a99",
|
|
1893
|
+
// pull-down map ocean (steel-blue)
|
|
1894
|
+
secondary: "#7e9a6f",
|
|
1895
|
+
// lowland sage / celadon
|
|
1896
|
+
accent: "#b07f7c",
|
|
1897
|
+
// dusty rose
|
|
1898
|
+
destructive: "#b25a45",
|
|
1899
|
+
// brick / terracotta
|
|
1856
1900
|
colors: {
|
|
1857
|
-
red: "#
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1901
|
+
red: "#bf6a52",
|
|
1902
|
+
// terracotta brick
|
|
1903
|
+
orange: "#cf9a5c",
|
|
1904
|
+
// map tan / ochre
|
|
1905
|
+
yellow: "#cdb35e",
|
|
1906
|
+
// straw / muted lemon
|
|
1907
|
+
green: "#7e9a6f",
|
|
1908
|
+
// sage / celadon lowland
|
|
1909
|
+
blue: "#5b7a99",
|
|
1910
|
+
// steel-blue ocean
|
|
1911
|
+
purple: "#9a7fa6",
|
|
1912
|
+
// dusty lilac / mauve
|
|
1913
|
+
teal: "#6fa094",
|
|
1914
|
+
// muted seafoam
|
|
1915
|
+
cyan: "#79a7b5",
|
|
1916
|
+
// shallow-water blue
|
|
1917
|
+
gray: "#8a7d68",
|
|
1918
|
+
// warm taupe
|
|
1919
|
+
black: "#463a26",
|
|
1920
|
+
// ink
|
|
1921
|
+
white: "#ece0c0"
|
|
1922
|
+
// paper
|
|
1868
1923
|
}
|
|
1869
1924
|
},
|
|
1870
1925
|
dark: {
|
|
1871
|
-
bg: "#
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1926
|
+
bg: "#1e2a33",
|
|
1927
|
+
// deep map ocean (night globe)
|
|
1928
|
+
surface: "#27353f",
|
|
1929
|
+
// raised ocean
|
|
1930
|
+
overlay: "#2e3d48",
|
|
1931
|
+
// popovers, dropdowns
|
|
1932
|
+
border: "#3d4f5c",
|
|
1933
|
+
// depth-contour line
|
|
1934
|
+
text: "#e8dcc0",
|
|
1935
|
+
// parchment ink, inverted
|
|
1936
|
+
textMuted: "#a89a7d",
|
|
1937
|
+
// faded label
|
|
1938
|
+
textOnFillLight: "#f7f1de",
|
|
1939
|
+
// parchment
|
|
1940
|
+
textOnFillDark: "#1a242c",
|
|
1941
|
+
// deep ocean ink
|
|
1942
|
+
primary: "#7ba0bf",
|
|
1943
|
+
// brighter ocean
|
|
1944
|
+
secondary: "#9bb588",
|
|
1945
|
+
// sage, lifted
|
|
1946
|
+
accent: "#cf9a96",
|
|
1947
|
+
// dusty rose, lifted
|
|
1948
|
+
destructive: "#c9745c",
|
|
1949
|
+
// brick, lifted
|
|
1883
1950
|
colors: {
|
|
1884
|
-
red: "#
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1951
|
+
red: "#cf7a60",
|
|
1952
|
+
// terracotta
|
|
1953
|
+
orange: "#d9a96a",
|
|
1954
|
+
// tan / ochre
|
|
1955
|
+
yellow: "#d8c074",
|
|
1956
|
+
// straw
|
|
1957
|
+
green: "#9bb588",
|
|
1958
|
+
// sage lowland
|
|
1959
|
+
blue: "#7ba0bf",
|
|
1960
|
+
// ocean
|
|
1961
|
+
purple: "#b59ac0",
|
|
1962
|
+
// lilac / mauve
|
|
1963
|
+
teal: "#85b3a6",
|
|
1964
|
+
// seafoam
|
|
1965
|
+
cyan: "#92bccb",
|
|
1966
|
+
// shallow-water blue
|
|
1967
|
+
gray: "#9a8d76",
|
|
1968
|
+
// warm taupe
|
|
1969
|
+
black: "#27353f",
|
|
1970
|
+
// raised ocean
|
|
1971
|
+
white: "#e8dcc0"
|
|
1972
|
+
// parchment
|
|
1895
1973
|
}
|
|
1896
1974
|
}
|
|
1897
1975
|
};
|
|
1898
|
-
registerPalette(
|
|
1976
|
+
registerPalette(atlasPalette);
|
|
1977
|
+
}
|
|
1978
|
+
});
|
|
1979
|
+
|
|
1980
|
+
// src/palettes/blueprint.ts
|
|
1981
|
+
var blueprintPalette;
|
|
1982
|
+
var init_blueprint = __esm({
|
|
1983
|
+
"src/palettes/blueprint.ts"() {
|
|
1984
|
+
"use strict";
|
|
1985
|
+
init_registry();
|
|
1986
|
+
blueprintPalette = {
|
|
1987
|
+
id: "blueprint",
|
|
1988
|
+
name: "Blueprint",
|
|
1989
|
+
light: {
|
|
1990
|
+
bg: "#f4f8fb",
|
|
1991
|
+
// pale drafting white (faint cyan)
|
|
1992
|
+
surface: "#e6eef4",
|
|
1993
|
+
// drafting panel
|
|
1994
|
+
overlay: "#dde9f1",
|
|
1995
|
+
// popovers, dropdowns
|
|
1996
|
+
border: "#aac3d6",
|
|
1997
|
+
// pale blue grid line
|
|
1998
|
+
text: "#123a5e",
|
|
1999
|
+
// blueprint navy ink
|
|
2000
|
+
textMuted: "#4f7390",
|
|
2001
|
+
// faint draft note
|
|
2002
|
+
textOnFillLight: "#f4f8fb",
|
|
2003
|
+
// drafting white
|
|
2004
|
+
textOnFillDark: "#0c2f4d",
|
|
2005
|
+
// deep blueprint navy
|
|
2006
|
+
primary: "#1f5e8c",
|
|
2007
|
+
// blueprint blue
|
|
2008
|
+
secondary: "#5b7d96",
|
|
2009
|
+
// steel
|
|
2010
|
+
accent: "#b08a3e",
|
|
2011
|
+
// draftsman's ochre highlight
|
|
2012
|
+
destructive: "#c0504d",
|
|
2013
|
+
// correction red
|
|
2014
|
+
colors: {
|
|
2015
|
+
red: "#c25a4e",
|
|
2016
|
+
// correction red
|
|
2017
|
+
orange: "#c2823e",
|
|
2018
|
+
// ochre
|
|
2019
|
+
yellow: "#c2a843",
|
|
2020
|
+
// pencil gold
|
|
2021
|
+
green: "#4f8a6b",
|
|
2022
|
+
// drafting green
|
|
2023
|
+
blue: "#1f5e8c",
|
|
2024
|
+
// blueprint blue
|
|
2025
|
+
purple: "#6f5e96",
|
|
2026
|
+
// indigo pencil
|
|
2027
|
+
teal: "#3a8a8a",
|
|
2028
|
+
// teal
|
|
2029
|
+
cyan: "#3f8fb5",
|
|
2030
|
+
// cyan
|
|
2031
|
+
gray: "#7e8e98",
|
|
2032
|
+
// graphite
|
|
2033
|
+
black: "#123a5e",
|
|
2034
|
+
// navy ink
|
|
2035
|
+
white: "#e6eef4"
|
|
2036
|
+
// panel
|
|
2037
|
+
}
|
|
2038
|
+
},
|
|
2039
|
+
dark: {
|
|
2040
|
+
bg: "#103a5e",
|
|
2041
|
+
// deep blueprint blue (cyanotype ground)
|
|
2042
|
+
surface: "#16466e",
|
|
2043
|
+
// raised sheet
|
|
2044
|
+
overlay: "#1c5180",
|
|
2045
|
+
// popovers, dropdowns
|
|
2046
|
+
border: "#3a6f96",
|
|
2047
|
+
// grid line
|
|
2048
|
+
text: "#eaf2f8",
|
|
2049
|
+
// chalk white
|
|
2050
|
+
textMuted: "#9fc0d6",
|
|
2051
|
+
// faint chalk note
|
|
2052
|
+
textOnFillLight: "#eaf2f8",
|
|
2053
|
+
// chalk white
|
|
2054
|
+
textOnFillDark: "#0c2f4d",
|
|
2055
|
+
// deep blueprint navy
|
|
2056
|
+
primary: "#7fb8d8",
|
|
2057
|
+
// chalk cyan
|
|
2058
|
+
secondary: "#9fb8c8",
|
|
2059
|
+
// pale steel
|
|
2060
|
+
accent: "#d8c27a",
|
|
2061
|
+
// chalk amber
|
|
2062
|
+
destructive: "#e08a7a",
|
|
2063
|
+
// chalk correction red
|
|
2064
|
+
colors: {
|
|
2065
|
+
red: "#e0907e",
|
|
2066
|
+
// chalk red
|
|
2067
|
+
orange: "#e0ab78",
|
|
2068
|
+
// chalk amber
|
|
2069
|
+
yellow: "#e3d089",
|
|
2070
|
+
// chalk gold
|
|
2071
|
+
green: "#93c79e",
|
|
2072
|
+
// chalk green
|
|
2073
|
+
blue: "#8ec3e0",
|
|
2074
|
+
// chalk cyan-blue
|
|
2075
|
+
purple: "#b6a6d8",
|
|
2076
|
+
// chalk indigo
|
|
2077
|
+
teal: "#84c7c2",
|
|
2078
|
+
// chalk teal
|
|
2079
|
+
cyan: "#9fd6e0",
|
|
2080
|
+
// chalk cyan
|
|
2081
|
+
gray: "#aebecb",
|
|
2082
|
+
// chalk graphite
|
|
2083
|
+
black: "#16466e",
|
|
2084
|
+
// raised sheet
|
|
2085
|
+
white: "#eaf2f8"
|
|
2086
|
+
// chalk white
|
|
2087
|
+
}
|
|
2088
|
+
}
|
|
2089
|
+
};
|
|
2090
|
+
registerPalette(blueprintPalette);
|
|
1899
2091
|
}
|
|
1900
2092
|
});
|
|
1901
2093
|
|
|
@@ -2392,6 +2584,120 @@ var init_rose_pine = __esm({
|
|
|
2392
2584
|
}
|
|
2393
2585
|
});
|
|
2394
2586
|
|
|
2587
|
+
// src/palettes/slate.ts
|
|
2588
|
+
var slatePalette;
|
|
2589
|
+
var init_slate = __esm({
|
|
2590
|
+
"src/palettes/slate.ts"() {
|
|
2591
|
+
"use strict";
|
|
2592
|
+
init_registry();
|
|
2593
|
+
slatePalette = {
|
|
2594
|
+
id: "slate",
|
|
2595
|
+
name: "Slate",
|
|
2596
|
+
light: {
|
|
2597
|
+
bg: "#ffffff",
|
|
2598
|
+
// clean slide white
|
|
2599
|
+
surface: "#f3f5f8",
|
|
2600
|
+
// light cool-gray panel
|
|
2601
|
+
overlay: "#eaeef3",
|
|
2602
|
+
// popovers, dropdowns
|
|
2603
|
+
border: "#d4dae1",
|
|
2604
|
+
// hairline rule
|
|
2605
|
+
text: "#1f2933",
|
|
2606
|
+
// near-black slate (softer than pure black)
|
|
2607
|
+
textMuted: "#5b6672",
|
|
2608
|
+
// secondary label
|
|
2609
|
+
textOnFillLight: "#ffffff",
|
|
2610
|
+
// light text on dark fills
|
|
2611
|
+
textOnFillDark: "#1f2933",
|
|
2612
|
+
// dark text on light fills
|
|
2613
|
+
primary: "#3b6ea5",
|
|
2614
|
+
// confident corporate blue
|
|
2615
|
+
secondary: "#5b6672",
|
|
2616
|
+
// slate gray
|
|
2617
|
+
accent: "#3a9188",
|
|
2618
|
+
// muted teal accent
|
|
2619
|
+
destructive: "#c0504d",
|
|
2620
|
+
// brick red
|
|
2621
|
+
colors: {
|
|
2622
|
+
red: "#c0504d",
|
|
2623
|
+
// brick
|
|
2624
|
+
orange: "#cc7a33",
|
|
2625
|
+
// muted amber
|
|
2626
|
+
yellow: "#c9a227",
|
|
2627
|
+
// gold (not neon)
|
|
2628
|
+
green: "#5b9357",
|
|
2629
|
+
// forest / sage
|
|
2630
|
+
blue: "#3b6ea5",
|
|
2631
|
+
// corporate blue
|
|
2632
|
+
purple: "#7d5ba6",
|
|
2633
|
+
// muted violet
|
|
2634
|
+
teal: "#3a9188",
|
|
2635
|
+
// teal
|
|
2636
|
+
cyan: "#4f96c4",
|
|
2637
|
+
// steel cyan
|
|
2638
|
+
gray: "#7e8a97",
|
|
2639
|
+
// cool gray
|
|
2640
|
+
black: "#1f2933",
|
|
2641
|
+
// slate ink
|
|
2642
|
+
white: "#f3f5f8"
|
|
2643
|
+
// panel
|
|
2644
|
+
}
|
|
2645
|
+
},
|
|
2646
|
+
dark: {
|
|
2647
|
+
bg: "#161b22",
|
|
2648
|
+
// deep slate (keynote dark)
|
|
2649
|
+
surface: "#202833",
|
|
2650
|
+
// raised panel
|
|
2651
|
+
overlay: "#29323e",
|
|
2652
|
+
// popovers, dropdowns
|
|
2653
|
+
border: "#38424f",
|
|
2654
|
+
// divider
|
|
2655
|
+
text: "#e6eaef",
|
|
2656
|
+
// off-white
|
|
2657
|
+
textMuted: "#9aa5b1",
|
|
2658
|
+
// secondary label
|
|
2659
|
+
textOnFillLight: "#ffffff",
|
|
2660
|
+
// light text on dark fills
|
|
2661
|
+
textOnFillDark: "#161b22",
|
|
2662
|
+
// dark text on light fills
|
|
2663
|
+
primary: "#5b9bd5",
|
|
2664
|
+
// lifted corporate blue
|
|
2665
|
+
secondary: "#8593a3",
|
|
2666
|
+
// slate gray, lifted
|
|
2667
|
+
accent: "#45b3a3",
|
|
2668
|
+
// teal, lifted
|
|
2669
|
+
destructive: "#e07b6e",
|
|
2670
|
+
// brick, lifted
|
|
2671
|
+
colors: {
|
|
2672
|
+
red: "#e07b6e",
|
|
2673
|
+
// brick
|
|
2674
|
+
orange: "#e0975a",
|
|
2675
|
+
// amber
|
|
2676
|
+
yellow: "#d9bd5a",
|
|
2677
|
+
// gold
|
|
2678
|
+
green: "#74b56e",
|
|
2679
|
+
// forest / sage
|
|
2680
|
+
blue: "#5b9bd5",
|
|
2681
|
+
// corporate blue
|
|
2682
|
+
purple: "#a585c9",
|
|
2683
|
+
// violet
|
|
2684
|
+
teal: "#45b3a3",
|
|
2685
|
+
// teal
|
|
2686
|
+
cyan: "#62b0d9",
|
|
2687
|
+
// steel cyan
|
|
2688
|
+
gray: "#95a1ae",
|
|
2689
|
+
// cool gray
|
|
2690
|
+
black: "#202833",
|
|
2691
|
+
// raised panel
|
|
2692
|
+
white: "#e6eaef"
|
|
2693
|
+
// off-white
|
|
2694
|
+
}
|
|
2695
|
+
}
|
|
2696
|
+
};
|
|
2697
|
+
registerPalette(slatePalette);
|
|
2698
|
+
}
|
|
2699
|
+
});
|
|
2700
|
+
|
|
2395
2701
|
// src/palettes/solarized.ts
|
|
2396
2702
|
var solarizedPalette;
|
|
2397
2703
|
var init_solarized = __esm({
|
|
@@ -2487,6 +2793,120 @@ var init_solarized = __esm({
|
|
|
2487
2793
|
}
|
|
2488
2794
|
});
|
|
2489
2795
|
|
|
2796
|
+
// src/palettes/tidewater.ts
|
|
2797
|
+
var tidewaterPalette;
|
|
2798
|
+
var init_tidewater = __esm({
|
|
2799
|
+
"src/palettes/tidewater.ts"() {
|
|
2800
|
+
"use strict";
|
|
2801
|
+
init_registry();
|
|
2802
|
+
tidewaterPalette = {
|
|
2803
|
+
id: "tidewater",
|
|
2804
|
+
name: "Tidewater",
|
|
2805
|
+
light: {
|
|
2806
|
+
bg: "#eceff0",
|
|
2807
|
+
// weathered sea-mist paper
|
|
2808
|
+
surface: "#e0e4e3",
|
|
2809
|
+
// worn deck panel
|
|
2810
|
+
overlay: "#dadfdf",
|
|
2811
|
+
// popovers, dropdowns
|
|
2812
|
+
border: "#a9b2b3",
|
|
2813
|
+
// muted slate rule
|
|
2814
|
+
text: "#18313f",
|
|
2815
|
+
// ship's-log navy ink
|
|
2816
|
+
textMuted: "#51636b",
|
|
2817
|
+
// faded log entry
|
|
2818
|
+
textOnFillLight: "#f3f5f3",
|
|
2819
|
+
// weathered white
|
|
2820
|
+
textOnFillDark: "#162c38",
|
|
2821
|
+
// deep navy
|
|
2822
|
+
primary: "#1f4e6b",
|
|
2823
|
+
// deep-sea navy
|
|
2824
|
+
secondary: "#b08a4f",
|
|
2825
|
+
// rope / manila tan
|
|
2826
|
+
accent: "#c69a3e",
|
|
2827
|
+
// brass
|
|
2828
|
+
destructive: "#c1433a",
|
|
2829
|
+
// signal-flag red
|
|
2830
|
+
colors: {
|
|
2831
|
+
red: "#c1433a",
|
|
2832
|
+
// signal-flag red
|
|
2833
|
+
orange: "#cc7a38",
|
|
2834
|
+
// weathered amber
|
|
2835
|
+
yellow: "#d6bf5a",
|
|
2836
|
+
// brass gold
|
|
2837
|
+
green: "#4f8a6b",
|
|
2838
|
+
// sea-glass green
|
|
2839
|
+
blue: "#1f4e6b",
|
|
2840
|
+
// deep-sea navy
|
|
2841
|
+
purple: "#6a5a8c",
|
|
2842
|
+
// twilight harbor
|
|
2843
|
+
teal: "#3d8c8c",
|
|
2844
|
+
// sea-glass teal
|
|
2845
|
+
cyan: "#4f9bb5",
|
|
2846
|
+
// shallow water
|
|
2847
|
+
gray: "#8a8d86",
|
|
2848
|
+
// driftwood gray
|
|
2849
|
+
black: "#18313f",
|
|
2850
|
+
// navy ink
|
|
2851
|
+
white: "#e0e4e3"
|
|
2852
|
+
// deck panel
|
|
2853
|
+
}
|
|
2854
|
+
},
|
|
2855
|
+
dark: {
|
|
2856
|
+
bg: "#0f2230",
|
|
2857
|
+
// night-harbor deep sea
|
|
2858
|
+
surface: "#16303f",
|
|
2859
|
+
// raised hull
|
|
2860
|
+
overlay: "#1d3a4a",
|
|
2861
|
+
// popovers, dropdowns
|
|
2862
|
+
border: "#2c4856",
|
|
2863
|
+
// rigging line
|
|
2864
|
+
text: "#e6ebe8",
|
|
2865
|
+
// weathered white
|
|
2866
|
+
textMuted: "#9aaab0",
|
|
2867
|
+
// faded label
|
|
2868
|
+
textOnFillLight: "#f3f5f3",
|
|
2869
|
+
// weathered white
|
|
2870
|
+
textOnFillDark: "#0f2230",
|
|
2871
|
+
// deep sea
|
|
2872
|
+
primary: "#4f9bc4",
|
|
2873
|
+
// lifted sea blue
|
|
2874
|
+
secondary: "#c9a46a",
|
|
2875
|
+
// rope tan, lifted
|
|
2876
|
+
accent: "#d9b25a",
|
|
2877
|
+
// brass, lifted
|
|
2878
|
+
destructive: "#e06a5e",
|
|
2879
|
+
// signal red, lifted
|
|
2880
|
+
colors: {
|
|
2881
|
+
red: "#e06a5e",
|
|
2882
|
+
// signal-flag red
|
|
2883
|
+
orange: "#df9a52",
|
|
2884
|
+
// amber
|
|
2885
|
+
yellow: "#e0c662",
|
|
2886
|
+
// brass gold
|
|
2887
|
+
green: "#6fb58c",
|
|
2888
|
+
// sea-glass green
|
|
2889
|
+
blue: "#4f9bc4",
|
|
2890
|
+
// sea blue
|
|
2891
|
+
purple: "#9486bf",
|
|
2892
|
+
// twilight harbor
|
|
2893
|
+
teal: "#5cb0ac",
|
|
2894
|
+
// sea-glass teal
|
|
2895
|
+
cyan: "#62b4cf",
|
|
2896
|
+
// shallow water
|
|
2897
|
+
gray: "#9aa39c",
|
|
2898
|
+
// driftwood gray
|
|
2899
|
+
black: "#16303f",
|
|
2900
|
+
// raised hull
|
|
2901
|
+
white: "#e6ebe8"
|
|
2902
|
+
// weathered white
|
|
2903
|
+
}
|
|
2904
|
+
}
|
|
2905
|
+
};
|
|
2906
|
+
registerPalette(tidewaterPalette);
|
|
2907
|
+
}
|
|
2908
|
+
});
|
|
2909
|
+
|
|
2490
2910
|
// src/palettes/tokyo-night.ts
|
|
2491
2911
|
var tokyoNightPalette;
|
|
2492
2912
|
var init_tokyo_night = __esm({
|
|
@@ -2762,7 +3182,8 @@ var init_monokai = __esm({
|
|
|
2762
3182
|
// src/palettes/index.ts
|
|
2763
3183
|
var palettes_exports = {};
|
|
2764
3184
|
__export(palettes_exports, {
|
|
2765
|
-
|
|
3185
|
+
atlasPalette: () => atlasPalette,
|
|
3186
|
+
blueprintPalette: () => blueprintPalette,
|
|
2766
3187
|
catppuccinPalette: () => catppuccinPalette,
|
|
2767
3188
|
contrastText: () => contrastText,
|
|
2768
3189
|
draculaPalette: () => draculaPalette,
|
|
@@ -2783,7 +3204,9 @@ __export(palettes_exports, {
|
|
|
2783
3204
|
rosePinePalette: () => rosePinePalette,
|
|
2784
3205
|
shade: () => shade,
|
|
2785
3206
|
shapeFill: () => shapeFill,
|
|
3207
|
+
slatePalette: () => slatePalette,
|
|
2786
3208
|
solarizedPalette: () => solarizedPalette,
|
|
3209
|
+
tidewaterPalette: () => tidewaterPalette,
|
|
2787
3210
|
tint: () => tint,
|
|
2788
3211
|
tokyoNightPalette: () => tokyoNightPalette
|
|
2789
3212
|
});
|
|
@@ -2793,17 +3216,21 @@ var init_palettes = __esm({
|
|
|
2793
3216
|
"use strict";
|
|
2794
3217
|
init_registry();
|
|
2795
3218
|
init_color_utils();
|
|
2796
|
-
|
|
3219
|
+
init_atlas();
|
|
3220
|
+
init_blueprint();
|
|
2797
3221
|
init_catppuccin();
|
|
2798
3222
|
init_gruvbox();
|
|
2799
3223
|
init_nord();
|
|
2800
3224
|
init_one_dark();
|
|
2801
3225
|
init_rose_pine();
|
|
3226
|
+
init_slate();
|
|
2802
3227
|
init_solarized();
|
|
3228
|
+
init_tidewater();
|
|
2803
3229
|
init_tokyo_night();
|
|
2804
3230
|
init_dracula();
|
|
2805
3231
|
init_monokai();
|
|
2806
|
-
|
|
3232
|
+
init_atlas();
|
|
3233
|
+
init_blueprint();
|
|
2807
3234
|
init_catppuccin();
|
|
2808
3235
|
init_dracula();
|
|
2809
3236
|
init_gruvbox();
|
|
@@ -2811,9 +3238,15 @@ var init_palettes = __esm({
|
|
|
2811
3238
|
init_nord();
|
|
2812
3239
|
init_one_dark();
|
|
2813
3240
|
init_rose_pine();
|
|
3241
|
+
init_slate();
|
|
2814
3242
|
init_solarized();
|
|
3243
|
+
init_tidewater();
|
|
2815
3244
|
init_tokyo_night();
|
|
2816
3245
|
palettes = {
|
|
3246
|
+
atlas: atlasPalette,
|
|
3247
|
+
blueprint: blueprintPalette,
|
|
3248
|
+
slate: slatePalette,
|
|
3249
|
+
tidewater: tidewaterPalette,
|
|
2817
3250
|
nord: nordPalette,
|
|
2818
3251
|
catppuccin: catppuccinPalette,
|
|
2819
3252
|
solarized: solarizedPalette,
|
|
@@ -2822,8 +3255,7 @@ var init_palettes = __esm({
|
|
|
2822
3255
|
oneDark: oneDarkPalette,
|
|
2823
3256
|
rosePine: rosePinePalette,
|
|
2824
3257
|
dracula: draculaPalette,
|
|
2825
|
-
monokai: monokaiPalette
|
|
2826
|
-
bold: boldPalette
|
|
3258
|
+
monokai: monokaiPalette
|
|
2827
3259
|
};
|
|
2828
3260
|
}
|
|
2829
3261
|
});
|
|
@@ -3333,6 +3765,9 @@ function controlsGroupCapsuleWidth(toggles) {
|
|
|
3333
3765
|
}
|
|
3334
3766
|
return w;
|
|
3335
3767
|
}
|
|
3768
|
+
function isAppHostedControls(config, isExport) {
|
|
3769
|
+
return !isExport && config.controlsHost === "app" && !!config.controlsGroup && config.controlsGroup.toggles.length > 0;
|
|
3770
|
+
}
|
|
3336
3771
|
function buildControlsGroupLayout(config, state) {
|
|
3337
3772
|
const cg = config.controlsGroup;
|
|
3338
3773
|
if (!cg || cg.toggles.length === 0) return void 0;
|
|
@@ -3386,6 +3821,7 @@ function buildControlsGroupLayout(config, state) {
|
|
|
3386
3821
|
function computeLegendLayout(config, state, containerWidth) {
|
|
3387
3822
|
const { groups, controls: configControls, mode } = config;
|
|
3388
3823
|
const isExport = mode === "export";
|
|
3824
|
+
const gated = isAppHostedControls(config, isExport);
|
|
3389
3825
|
const activeGroupName = state.activeGroup?.toLowerCase() ?? null;
|
|
3390
3826
|
if (isExport && !activeGroupName) {
|
|
3391
3827
|
return {
|
|
@@ -3396,7 +3832,7 @@ function computeLegendLayout(config, state, containerWidth) {
|
|
|
3396
3832
|
pills: []
|
|
3397
3833
|
};
|
|
3398
3834
|
}
|
|
3399
|
-
const controlsGroupLayout = isExport ? void 0 : buildControlsGroupLayout(config, state);
|
|
3835
|
+
const controlsGroupLayout = isExport || gated ? void 0 : buildControlsGroupLayout(config, state);
|
|
3400
3836
|
const visibleGroups = config.showEmptyGroups ? groups : groups.filter((g) => g.entries.length > 0 || !!g.gradient);
|
|
3401
3837
|
if (visibleGroups.length === 0 && (!configControls || configControls.length === 0) && !controlsGroupLayout) {
|
|
3402
3838
|
return {
|
|
@@ -8276,8 +8712,8 @@ function computeScatterLabelGraphics(points, chartBounds, fontSize, symbolSize,
|
|
|
8276
8712
|
const pt = points[i];
|
|
8277
8713
|
const ptSize = pt.size ?? symbolSize;
|
|
8278
8714
|
const minGap = ptSize / 2 + 4;
|
|
8279
|
-
const
|
|
8280
|
-
const labelX = pt.px -
|
|
8715
|
+
const labelWidth2 = pt.name.length * fontSize * 0.6 + 8;
|
|
8716
|
+
const labelX = pt.px - labelWidth2 / 2;
|
|
8281
8717
|
let bestLabelY = 0;
|
|
8282
8718
|
let bestOffset = Infinity;
|
|
8283
8719
|
let placed = false;
|
|
@@ -8289,7 +8725,7 @@ function computeScatterLabelGraphics(points, chartBounds, fontSize, symbolSize,
|
|
|
8289
8725
|
const candidate = {
|
|
8290
8726
|
x: labelX,
|
|
8291
8727
|
y: labelY,
|
|
8292
|
-
w:
|
|
8728
|
+
w: labelWidth2,
|
|
8293
8729
|
h: labelHeight
|
|
8294
8730
|
};
|
|
8295
8731
|
let collision = false;
|
|
@@ -8331,7 +8767,7 @@ function computeScatterLabelGraphics(points, chartBounds, fontSize, symbolSize,
|
|
|
8331
8767
|
const labelRect = {
|
|
8332
8768
|
x: labelX,
|
|
8333
8769
|
y: bestLabelY,
|
|
8334
|
-
w:
|
|
8770
|
+
w: labelWidth2,
|
|
8335
8771
|
h: labelHeight
|
|
8336
8772
|
};
|
|
8337
8773
|
placedLabels.push(labelRect);
|
|
@@ -8367,7 +8803,7 @@ function computeScatterLabelGraphics(points, chartBounds, fontSize, symbolSize,
|
|
|
8367
8803
|
shape: {
|
|
8368
8804
|
x: labelX - bgPad,
|
|
8369
8805
|
y: bestLabelY - bgPad,
|
|
8370
|
-
width:
|
|
8806
|
+
width: labelWidth2 + bgPad * 2,
|
|
8371
8807
|
height: labelHeight + bgPad * 2
|
|
8372
8808
|
},
|
|
8373
8809
|
style: { fill: bg },
|
|
@@ -15807,10 +16243,6 @@ function parseMap(content) {
|
|
|
15807
16243
|
handleTag(trimmed, lineNumber);
|
|
15808
16244
|
continue;
|
|
15809
16245
|
}
|
|
15810
|
-
if ((firstWord === "muted" || firstWord === "natural") && trimmed === firstWord) {
|
|
15811
|
-
handleDirective(firstWord, "", lineNumber);
|
|
15812
|
-
continue;
|
|
15813
|
-
}
|
|
15814
16246
|
if (DIRECTIVE_SET.has(firstWord) && !trimmed.slice(firstWord.length).trimStart().startsWith(":")) {
|
|
15815
16247
|
handleDirective(
|
|
15816
16248
|
firstWord,
|
|
@@ -15857,24 +16289,6 @@ function parseMap(content) {
|
|
|
15857
16289
|
pushWarning(line12, `Duplicate directive "${key}" \u2014 last value wins.`);
|
|
15858
16290
|
};
|
|
15859
16291
|
switch (key) {
|
|
15860
|
-
case "region":
|
|
15861
|
-
dup(d.region);
|
|
15862
|
-
d.region = value;
|
|
15863
|
-
break;
|
|
15864
|
-
case "projection":
|
|
15865
|
-
dup(d.projection);
|
|
15866
|
-
if (value && ![
|
|
15867
|
-
"equirectangular",
|
|
15868
|
-
"natural-earth",
|
|
15869
|
-
"albers-usa",
|
|
15870
|
-
"mercator"
|
|
15871
|
-
].includes(value))
|
|
15872
|
-
pushWarning(
|
|
15873
|
-
line12,
|
|
15874
|
-
`Unknown projection "${value}" (expected equirectangular | natural-earth | albers-usa | mercator).`
|
|
15875
|
-
);
|
|
15876
|
-
d.projection = value;
|
|
15877
|
-
break;
|
|
15878
16292
|
case "region-metric": {
|
|
15879
16293
|
dup(d.regionMetric);
|
|
15880
16294
|
const { label: rmLabel, colorName: rmColor } = peelTrailingColorName(value);
|
|
@@ -15890,91 +16304,43 @@ function parseMap(content) {
|
|
|
15890
16304
|
dup(d.flowMetric);
|
|
15891
16305
|
d.flowMetric = value;
|
|
15892
16306
|
break;
|
|
15893
|
-
case "
|
|
15894
|
-
dup(d.
|
|
15895
|
-
|
|
15896
|
-
const s = parseScale(value, line12);
|
|
15897
|
-
if (s) d.scale = s;
|
|
15898
|
-
}
|
|
15899
|
-
break;
|
|
15900
|
-
case "region-labels":
|
|
15901
|
-
dup(d.regionLabels);
|
|
15902
|
-
if (value && !["full", "abbrev", "off"].includes(value))
|
|
15903
|
-
pushWarning(
|
|
15904
|
-
line12,
|
|
15905
|
-
`Unknown region-labels "${value}" (expected full | abbrev | off).`
|
|
15906
|
-
);
|
|
15907
|
-
d.regionLabels = value;
|
|
15908
|
-
break;
|
|
15909
|
-
case "poi-labels":
|
|
15910
|
-
dup(d.poiLabels);
|
|
15911
|
-
if (value && !["off", "auto", "all"].includes(value))
|
|
15912
|
-
pushWarning(
|
|
15913
|
-
line12,
|
|
15914
|
-
`Unknown poi-labels "${value}" (expected off | auto | all).`
|
|
15915
|
-
);
|
|
15916
|
-
d.poiLabels = value;
|
|
15917
|
-
break;
|
|
15918
|
-
case "default-country":
|
|
15919
|
-
dup(d.defaultCountry);
|
|
15920
|
-
d.defaultCountry = value;
|
|
15921
|
-
break;
|
|
15922
|
-
case "default-state":
|
|
15923
|
-
dup(d.defaultState);
|
|
15924
|
-
d.defaultState = value;
|
|
16307
|
+
case "locale":
|
|
16308
|
+
dup(d.locale);
|
|
16309
|
+
d.locale = value;
|
|
15925
16310
|
break;
|
|
15926
16311
|
case "active-tag":
|
|
15927
16312
|
dup(d.activeTag);
|
|
15928
16313
|
d.activeTag = value;
|
|
15929
16314
|
break;
|
|
16315
|
+
case "caption":
|
|
16316
|
+
dup(d.caption);
|
|
16317
|
+
d.caption = value;
|
|
16318
|
+
break;
|
|
16319
|
+
// ── Cosmetic `no-*` opt-outs: bare flags, idempotent (mirror `no-legend`,
|
|
16320
|
+
// no dup warning); each defaults the feature ON when absent. ──
|
|
15930
16321
|
case "no-legend":
|
|
15931
16322
|
d.noLegend = true;
|
|
15932
16323
|
break;
|
|
15933
|
-
case "no-
|
|
15934
|
-
d.
|
|
16324
|
+
case "no-coastline":
|
|
16325
|
+
d.noCoastline = true;
|
|
15935
16326
|
break;
|
|
15936
|
-
case "relief":
|
|
15937
|
-
d.
|
|
16327
|
+
case "no-relief":
|
|
16328
|
+
d.noRelief = true;
|
|
15938
16329
|
break;
|
|
15939
|
-
case "
|
|
15940
|
-
|
|
15941
|
-
if (d.basemapStyle !== void 0 && d.basemapStyle !== key)
|
|
15942
|
-
pushWarning(
|
|
15943
|
-
line12,
|
|
15944
|
-
`Conflicting basemap dress \u2014 "${d.basemapStyle}" then "${key}"; last wins.`
|
|
15945
|
-
);
|
|
15946
|
-
d.basemapStyle = key;
|
|
16330
|
+
case "no-context-labels":
|
|
16331
|
+
d.noContextLabels = true;
|
|
15947
16332
|
break;
|
|
15948
|
-
case "
|
|
15949
|
-
|
|
15950
|
-
d.subtitle = value;
|
|
16333
|
+
case "no-region-labels":
|
|
16334
|
+
d.noRegionLabels = true;
|
|
15951
16335
|
break;
|
|
15952
|
-
case "
|
|
15953
|
-
|
|
15954
|
-
|
|
16336
|
+
case "no-poi-labels":
|
|
16337
|
+
d.noPoiLabels = true;
|
|
16338
|
+
break;
|
|
16339
|
+
case "no-colorize":
|
|
16340
|
+
d.noColorize = true;
|
|
15955
16341
|
break;
|
|
15956
16342
|
}
|
|
15957
16343
|
}
|
|
15958
|
-
function parseScale(value, line12) {
|
|
15959
|
-
const toks = value.split(/\s+/).filter(Boolean);
|
|
15960
|
-
const min = Number(toks[0]);
|
|
15961
|
-
const max = Number(toks[1]);
|
|
15962
|
-
if (!Number.isFinite(min) || !Number.isFinite(max)) {
|
|
15963
|
-
pushError(line12, `scale requires numeric <min> <max> (got "${value}").`);
|
|
15964
|
-
return null;
|
|
15965
|
-
}
|
|
15966
|
-
const scale = { min, max };
|
|
15967
|
-
if (toks[2] === "center") {
|
|
15968
|
-
const c = Number(toks[3]);
|
|
15969
|
-
if (Number.isFinite(c)) scale.center = c;
|
|
15970
|
-
else
|
|
15971
|
-
pushError(
|
|
15972
|
-
line12,
|
|
15973
|
-
`scale center requires a number (got "${toks[3] ?? ""}").`
|
|
15974
|
-
);
|
|
15975
|
-
}
|
|
15976
|
-
return scale;
|
|
15977
|
-
}
|
|
15978
16344
|
function handleTag(trimmed, line12) {
|
|
15979
16345
|
const m = matchTagBlockHeading(trimmed);
|
|
15980
16346
|
if (!m) {
|
|
@@ -16174,13 +16540,15 @@ function parseMap(content) {
|
|
|
16174
16540
|
pushError(line12, `Edge has an empty endpoint: "${trimmed}".`);
|
|
16175
16541
|
continue;
|
|
16176
16542
|
}
|
|
16177
|
-
const
|
|
16543
|
+
const isLast = k === links.length - 1;
|
|
16544
|
+
const meta = isLast ? lastSplit.meta : {};
|
|
16545
|
+
const style = links[k].style === "arc" ? "arc" : "straight";
|
|
16178
16546
|
edges.push({
|
|
16179
16547
|
from,
|
|
16180
16548
|
to,
|
|
16181
16549
|
...links[k].label !== void 0 && { label: links[k].label },
|
|
16182
16550
|
directed: links[k].directed,
|
|
16183
|
-
style
|
|
16551
|
+
style,
|
|
16184
16552
|
meta,
|
|
16185
16553
|
lineNumber: line12
|
|
16186
16554
|
});
|
|
@@ -16266,22 +16634,19 @@ var init_parser12 = __esm({
|
|
|
16266
16634
|
LEG_ARROW_RE = /^(-[^>]*?->|->|~[^>]*?~>|~>|--)\s+(.+)$/;
|
|
16267
16635
|
AT_RE = /(^|[\s,])at\s*:/i;
|
|
16268
16636
|
DIRECTIVE_SET = /* @__PURE__ */ new Set([
|
|
16269
|
-
"region",
|
|
16270
|
-
"projection",
|
|
16271
16637
|
"region-metric",
|
|
16272
16638
|
"poi-metric",
|
|
16273
16639
|
"flow-metric",
|
|
16274
|
-
"
|
|
16275
|
-
"region-labels",
|
|
16276
|
-
"poi-labels",
|
|
16277
|
-
"default-country",
|
|
16278
|
-
"default-state",
|
|
16640
|
+
"locale",
|
|
16279
16641
|
"active-tag",
|
|
16642
|
+
"caption",
|
|
16280
16643
|
"no-legend",
|
|
16281
|
-
"no-
|
|
16282
|
-
"relief",
|
|
16283
|
-
"
|
|
16284
|
-
"
|
|
16644
|
+
"no-coastline",
|
|
16645
|
+
"no-relief",
|
|
16646
|
+
"no-context-labels",
|
|
16647
|
+
"no-region-labels",
|
|
16648
|
+
"no-poi-labels",
|
|
16649
|
+
"no-colorize"
|
|
16285
16650
|
]);
|
|
16286
16651
|
}
|
|
16287
16652
|
});
|
|
@@ -24202,8 +24567,8 @@ function renderKanban(container, parsed, palette, isDark, options) {
|
|
|
24202
24567
|
let metaY = separatorY + sCardSeparatorGap + sCardMetaFontSize;
|
|
24203
24568
|
for (const meta of tagMeta) {
|
|
24204
24569
|
cg.append("text").attr("x", cx + sCardPaddingX).attr("y", metaY).attr("font-size", sCardMetaFontSize).attr("fill", onCardText).text(`${meta.label}: `);
|
|
24205
|
-
const
|
|
24206
|
-
cg.append("text").attr("x", cx + sCardPaddingX +
|
|
24570
|
+
const labelWidth2 = (meta.label.length + 2) * sCardMetaFontSize * 0.6;
|
|
24571
|
+
cg.append("text").attr("x", cx + sCardPaddingX + labelWidth2).attr("y", metaY).attr("font-size", sCardMetaFontSize).attr("fill", onCardText).text(meta.value);
|
|
24207
24572
|
metaY += sCardMetaLineHeight;
|
|
24208
24573
|
}
|
|
24209
24574
|
for (const detail of card.details) {
|
|
@@ -24547,8 +24912,8 @@ function renderSwimlaneCard(parent, cardLayout, tagGroups, activeTagGroup, palet
|
|
|
24547
24912
|
let metaY = separatorY + sCardSeparatorGap + sCardMetaFontSize;
|
|
24548
24913
|
for (const meta of tagMeta) {
|
|
24549
24914
|
cg.append("text").attr("x", cx + sCardPaddingX).attr("y", metaY).attr("font-size", sCardMetaFontSize).attr("fill", palette.textMuted).text(`${meta.label}: `);
|
|
24550
|
-
const
|
|
24551
|
-
cg.append("text").attr("x", cx + sCardPaddingX +
|
|
24915
|
+
const labelWidth2 = (meta.label.length + 2) * sCardMetaFontSize * 0.6;
|
|
24916
|
+
cg.append("text").attr("x", cx + sCardPaddingX + labelWidth2).attr("y", metaY).attr("font-size", sCardMetaFontSize).attr("fill", onCardText).text(meta.value);
|
|
24552
24917
|
metaY += sCardMetaLineHeight;
|
|
24553
24918
|
}
|
|
24554
24919
|
for (const detail of card.details) {
|
|
@@ -25383,8 +25748,8 @@ function classifyEREntities(tables, relationships) {
|
|
|
25383
25748
|
}
|
|
25384
25749
|
}
|
|
25385
25750
|
const mmParticipants = /* @__PURE__ */ new Set();
|
|
25386
|
-
for (const [id,
|
|
25387
|
-
if (
|
|
25751
|
+
for (const [id, neighbors2] of tableStarNeighbors) {
|
|
25752
|
+
if (neighbors2.size >= 2) mmParticipants.add(id);
|
|
25388
25753
|
}
|
|
25389
25754
|
const indegreeValues = Object.values(indegreeMap);
|
|
25390
25755
|
const mean = indegreeValues.reduce((a, b) => a + b, 0) / indegreeValues.length;
|
|
@@ -26055,7 +26420,8 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26055
26420
|
controlsExpanded,
|
|
26056
26421
|
onToggleDescriptions,
|
|
26057
26422
|
onToggleControlsExpand,
|
|
26058
|
-
exportMode = false
|
|
26423
|
+
exportMode = false,
|
|
26424
|
+
controlsHost
|
|
26059
26425
|
} = options ?? {};
|
|
26060
26426
|
d3Selection6.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
26061
26427
|
const width = exportDims?.width ?? container.clientWidth;
|
|
@@ -26073,7 +26439,11 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26073
26439
|
const sGroupLabelZone = sctx.structural(GROUP_LABEL_ZONE);
|
|
26074
26440
|
const sTitleFontSize = sctx.text(TITLE_FONT_SIZE);
|
|
26075
26441
|
const sTitleY = sctx.structural(TITLE_Y);
|
|
26076
|
-
const
|
|
26442
|
+
const reserveHasDescriptions = parsed.nodes.some(
|
|
26443
|
+
(n) => n.description && n.description.length > 0
|
|
26444
|
+
);
|
|
26445
|
+
const willRenderLegend = parsed.tagGroups.length > 0 || reserveHasDescriptions && controlsHost !== "app";
|
|
26446
|
+
const sLegendHeight = willRenderLegend ? sctx.structural(
|
|
26077
26447
|
getMaxLegendReservedHeight(
|
|
26078
26448
|
{
|
|
26079
26449
|
groups: parsed.tagGroups,
|
|
@@ -26082,7 +26452,7 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26082
26452
|
},
|
|
26083
26453
|
width
|
|
26084
26454
|
)
|
|
26085
|
-
);
|
|
26455
|
+
) : 0;
|
|
26086
26456
|
const activeGroup = resolveActiveTagGroup(
|
|
26087
26457
|
parsed.tagGroups,
|
|
26088
26458
|
parsed.options["active-tag"],
|
|
@@ -26397,10 +26767,10 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26397
26767
|
const hasDescriptions = parsed.nodes.some(
|
|
26398
26768
|
(n) => n.description && n.description.length > 0
|
|
26399
26769
|
);
|
|
26400
|
-
const hasLegend = parsed.tagGroups.length > 0 || hasDescriptions;
|
|
26770
|
+
const hasLegend = parsed.tagGroups.length > 0 || hasDescriptions && controlsHost !== "app";
|
|
26401
26771
|
if (hasLegend) {
|
|
26402
26772
|
let controlsGroup;
|
|
26403
|
-
if (hasDescriptions && onToggleDescriptions) {
|
|
26773
|
+
if (hasDescriptions && (onToggleDescriptions || controlsHost === "app")) {
|
|
26404
26774
|
controlsGroup = {
|
|
26405
26775
|
toggles: [
|
|
26406
26776
|
{
|
|
@@ -26418,7 +26788,14 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26418
26788
|
groups: parsed.tagGroups,
|
|
26419
26789
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
26420
26790
|
mode: exportMode ? "export" : "preview",
|
|
26421
|
-
|
|
26791
|
+
// Keep inactive sibling tag groups visible as collapsed pills so the user
|
|
26792
|
+
// can click one to flip the active colouring dimension (preview only —
|
|
26793
|
+
// export shows just the active group). Without this, declaring a second
|
|
26794
|
+
// tag group (e.g. Team) leaves it invisible whenever another group is
|
|
26795
|
+
// active. The app's BoxesAndLinesPreview already wires pill clicks.
|
|
26796
|
+
showInactivePills: true,
|
|
26797
|
+
...controlsGroup !== void 0 && { controlsGroup },
|
|
26798
|
+
...controlsHost !== void 0 && { controlsHost }
|
|
26422
26799
|
};
|
|
26423
26800
|
const legendState = {
|
|
26424
26801
|
activeGroup,
|
|
@@ -27666,8 +28043,9 @@ function renderMindmap(container, parsed, layout, palette, isDark, onClickItem,
|
|
|
27666
28043
|
const containerHeight = exportDims?.height ?? (container.getBoundingClientRect().height || 600);
|
|
27667
28044
|
d3Selection7.select(container).selectAll("*").remove();
|
|
27668
28045
|
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);
|
|
28046
|
+
const appHosted = options?.controlsHost === "app";
|
|
27669
28047
|
const hasControls = !!options?.onToggleColorByDepth || !!options?.onToggleDescriptions;
|
|
27670
|
-
const hasLegend = parsed.tagGroups.length > 0 || hasControls;
|
|
28048
|
+
const hasLegend = parsed.tagGroups.length > 0 || hasControls && !appHosted;
|
|
27671
28049
|
const fixedLegend = !isExport && hasLegend;
|
|
27672
28050
|
const legendReserve = fixedLegend ? getMaxLegendReservedHeight(
|
|
27673
28051
|
{
|
|
@@ -27761,7 +28139,10 @@ function renderMindmap(container, parsed, layout, palette, isDark, onClickItem,
|
|
|
27761
28139
|
}),
|
|
27762
28140
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
27763
28141
|
mode: options?.exportMode ? "export" : "preview",
|
|
27764
|
-
...controlsToggles !== void 0 && { controlsGroup: controlsToggles }
|
|
28142
|
+
...controlsToggles !== void 0 && { controlsGroup: controlsToggles },
|
|
28143
|
+
...options?.controlsHost !== void 0 && {
|
|
28144
|
+
controlsHost: options.controlsHost
|
|
28145
|
+
}
|
|
27765
28146
|
};
|
|
27766
28147
|
const legendState = {
|
|
27767
28148
|
activeGroup: options?.colorByDepth ? null : activeTagGroup !== void 0 ? activeTagGroup : parsed.options["active-tag"] ?? null,
|
|
@@ -28205,8 +28586,8 @@ function computeFieldAlignX(children) {
|
|
|
28205
28586
|
for (const child of children) {
|
|
28206
28587
|
if (child.metadata["_labelField"] === "true" && child.children.length >= 2) {
|
|
28207
28588
|
const labelEl = child.children[0];
|
|
28208
|
-
const
|
|
28209
|
-
maxLabelWidth = Math.max(maxLabelWidth,
|
|
28589
|
+
const labelWidth2 = labelEl.label.length * CHAR_WIDTH5;
|
|
28590
|
+
maxLabelWidth = Math.max(maxLabelWidth, labelWidth2);
|
|
28210
28591
|
labelFieldCount++;
|
|
28211
28592
|
}
|
|
28212
28593
|
}
|
|
@@ -33170,7 +33551,7 @@ function hasRoles(node) {
|
|
|
33170
33551
|
function computeNodeWidth2(node, expanded, options) {
|
|
33171
33552
|
const badgeVal = node.computedConcurrentInvocations === 0 && node.computedInstances > 1 ? node.computedInstances : 0;
|
|
33172
33553
|
const badgeLen = badgeVal > 0 ? `${badgeVal}x`.length + 2 : 0;
|
|
33173
|
-
const
|
|
33554
|
+
const labelWidth2 = (node.label.length + badgeLen) * CHAR_WIDTH7 + PADDING_X3;
|
|
33174
33555
|
const allKeys = [];
|
|
33175
33556
|
if (node.computedRps > 0) allKeys.push("RPS");
|
|
33176
33557
|
if (expanded) {
|
|
@@ -33214,7 +33595,7 @@ function computeNodeWidth2(node, expanded, options) {
|
|
|
33214
33595
|
allKeys.push("overflow");
|
|
33215
33596
|
}
|
|
33216
33597
|
}
|
|
33217
|
-
if (allKeys.length === 0) return Math.max(MIN_NODE_WIDTH2,
|
|
33598
|
+
if (allKeys.length === 0) return Math.max(MIN_NODE_WIDTH2, labelWidth2);
|
|
33218
33599
|
const maxKeyLen = Math.max(...allKeys.map((k) => k.length));
|
|
33219
33600
|
let maxRowWidth = 0;
|
|
33220
33601
|
if (node.computedRps > 0) {
|
|
@@ -33302,7 +33683,7 @@ function computeNodeWidth2(node, expanded, options) {
|
|
|
33302
33683
|
truncated.length * META_CHAR_WIDTH3 + PADDING_X3
|
|
33303
33684
|
);
|
|
33304
33685
|
}
|
|
33305
|
-
return Math.max(MIN_NODE_WIDTH2,
|
|
33686
|
+
return Math.max(MIN_NODE_WIDTH2, labelWidth2, maxRowWidth + 20, descWidth);
|
|
33306
33687
|
}
|
|
33307
33688
|
function computeNodeHeight2(node, expanded, options) {
|
|
33308
33689
|
const propCount = countDisplayProps(node, expanded, options);
|
|
@@ -34851,8 +35232,9 @@ function computeInfraLegendGroups(nodes, tagGroups, palette, edges) {
|
|
|
34851
35232
|
}
|
|
34852
35233
|
return groups;
|
|
34853
35234
|
}
|
|
34854
|
-
function renderLegend3(rootSvg, legendGroups, totalWidth, legendY, palette, isDark, activeGroup, playback, exportMode = false) {
|
|
35235
|
+
function renderLegend3(rootSvg, legendGroups, totalWidth, legendY, palette, isDark, activeGroup, playback, exportMode = false, controlsHost) {
|
|
34855
35236
|
if (legendGroups.length === 0 && !playback) return;
|
|
35237
|
+
const appHostedPlayback = controlsHost === "app" && !!playback;
|
|
34856
35238
|
const legendG = rootSvg.append("g").attr("transform", `translate(0, ${legendY})`);
|
|
34857
35239
|
if (activeGroup) {
|
|
34858
35240
|
legendG.attr("data-legend-active", activeGroup.toLowerCase());
|
|
@@ -34861,14 +35243,29 @@ function renderLegend3(rootSvg, legendGroups, totalWidth, legendY, palette, isDa
|
|
|
34861
35243
|
name: g.name,
|
|
34862
35244
|
entries: g.entries.map((e) => ({ value: e.value, color: e.color }))
|
|
34863
35245
|
}));
|
|
34864
|
-
if (playback) {
|
|
35246
|
+
if (playback && !appHostedPlayback) {
|
|
34865
35247
|
allGroups.push({ name: "Playback", entries: [] });
|
|
34866
35248
|
}
|
|
34867
35249
|
const legendConfig = {
|
|
34868
35250
|
groups: allGroups,
|
|
34869
35251
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
34870
35252
|
mode: exportMode ? "export" : "preview",
|
|
34871
|
-
showEmptyGroups: true
|
|
35253
|
+
showEmptyGroups: true,
|
|
35254
|
+
...appHostedPlayback && {
|
|
35255
|
+
controlsHost: "app",
|
|
35256
|
+
controlsGroup: {
|
|
35257
|
+
toggles: [
|
|
35258
|
+
{
|
|
35259
|
+
id: "playback",
|
|
35260
|
+
type: "toggle",
|
|
35261
|
+
label: "Playback",
|
|
35262
|
+
active: true,
|
|
35263
|
+
onToggle: () => {
|
|
35264
|
+
}
|
|
35265
|
+
}
|
|
35266
|
+
]
|
|
35267
|
+
}
|
|
35268
|
+
}
|
|
34872
35269
|
};
|
|
34873
35270
|
const legendState = { activeGroup };
|
|
34874
35271
|
renderLegendD3(
|
|
@@ -34919,8 +35316,9 @@ function renderLegend3(rootSvg, legendGroups, totalWidth, legendY, palette, isDa
|
|
|
34919
35316
|
}
|
|
34920
35317
|
}
|
|
34921
35318
|
}
|
|
34922
|
-
function renderInfra(container, layout, palette, isDark, title, titleLineNumber, tagGroups, activeGroup, animate, playback, expandedNodeIds, exportMode, collapsedNodes) {
|
|
35319
|
+
function renderInfra(container, layout, palette, isDark, title, titleLineNumber, tagGroups, activeGroup, animate, playback, expandedNodeIds, exportMode, collapsedNodes, controlsHost) {
|
|
34923
35320
|
d3Selection11.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
35321
|
+
const appHostedPlayback = controlsHost === "app" && !!playback;
|
|
34924
35322
|
const ctx = ScaleContext.identity();
|
|
34925
35323
|
const sc = buildScaledConstants(ctx);
|
|
34926
35324
|
const legendGroups = computeInfraLegendGroups(
|
|
@@ -34929,7 +35327,7 @@ function renderInfra(container, layout, palette, isDark, title, titleLineNumber,
|
|
|
34929
35327
|
palette,
|
|
34930
35328
|
layout.edges
|
|
34931
35329
|
);
|
|
34932
|
-
const hasLegend = legendGroups.length > 0 || !!playback;
|
|
35330
|
+
const hasLegend = legendGroups.length > 0 || !!playback && !appHostedPlayback;
|
|
34933
35331
|
const fixedLegend = !exportMode && hasLegend;
|
|
34934
35332
|
const legendDynamicH = hasLegend ? getMaxLegendReservedHeight(
|
|
34935
35333
|
{
|
|
@@ -35073,7 +35471,8 @@ function renderInfra(container, layout, palette, isDark, title, titleLineNumber,
|
|
|
35073
35471
|
isDark,
|
|
35074
35472
|
activeGroup ?? null,
|
|
35075
35473
|
playback ?? void 0,
|
|
35076
|
-
exportMode
|
|
35474
|
+
exportMode,
|
|
35475
|
+
controlsHost
|
|
35077
35476
|
);
|
|
35078
35477
|
legendSvg.selectAll(".infra-legend-group").style("pointer-events", "auto");
|
|
35079
35478
|
} else {
|
|
@@ -35086,7 +35485,8 @@ function renderInfra(container, layout, palette, isDark, title, titleLineNumber,
|
|
|
35086
35485
|
isDark,
|
|
35087
35486
|
activeGroup ?? null,
|
|
35088
35487
|
playback ?? void 0,
|
|
35089
|
-
exportMode
|
|
35488
|
+
exportMode,
|
|
35489
|
+
controlsHost
|
|
35090
35490
|
);
|
|
35091
35491
|
}
|
|
35092
35492
|
}
|
|
@@ -42721,6 +43121,9 @@ function renderTechRadar(container, parsed, palette, isDark, onClickItem, export
|
|
|
42721
43121
|
onToggle: (active) => options.onToggleListing(active)
|
|
42722
43122
|
}
|
|
42723
43123
|
]
|
|
43124
|
+
},
|
|
43125
|
+
...options.controlsHost !== void 0 && {
|
|
43126
|
+
controlsHost: options.controlsHost
|
|
42724
43127
|
}
|
|
42725
43128
|
};
|
|
42726
43129
|
const legendState = {
|
|
@@ -44544,7 +44947,7 @@ function computeCycleLayout(parsed, options) {
|
|
|
44544
44947
|
const circleNodes = parsed.options["circle-nodes"] === "true";
|
|
44545
44948
|
const nodeDims = parsed.nodes.map((node) => {
|
|
44546
44949
|
const hasDesc = !hideDescriptions && node.description.length > 0;
|
|
44547
|
-
const
|
|
44950
|
+
const labelWidth2 = Math.max(
|
|
44548
44951
|
MIN_NODE_WIDTH4,
|
|
44549
44952
|
node.label.length * LABEL_CHAR_W + NODE_PAD_X * 2
|
|
44550
44953
|
);
|
|
@@ -44553,12 +44956,12 @@ function computeCycleLayout(parsed, options) {
|
|
|
44553
44956
|
}
|
|
44554
44957
|
if (!hasDesc) {
|
|
44555
44958
|
return {
|
|
44556
|
-
width: Math.min(MAX_NODE_WIDTH3,
|
|
44959
|
+
width: Math.min(MAX_NODE_WIDTH3, labelWidth2),
|
|
44557
44960
|
height: PLAIN_NODE_HEIGHT,
|
|
44558
44961
|
wrappedDesc: []
|
|
44559
44962
|
};
|
|
44560
44963
|
}
|
|
44561
|
-
return chooseDescribedRectDims(node.description,
|
|
44964
|
+
return chooseDescribedRectDims(node.description, labelWidth2);
|
|
44562
44965
|
});
|
|
44563
44966
|
if (circleNodes) {
|
|
44564
44967
|
const maxDiam = Math.max(...nodeDims.map((d) => d.width));
|
|
@@ -44754,10 +45157,10 @@ function computeCycleLayout(parsed, options) {
|
|
|
44754
45157
|
scale
|
|
44755
45158
|
};
|
|
44756
45159
|
}
|
|
44757
|
-
function chooseDescribedRectDims(description,
|
|
45160
|
+
function chooseDescribedRectDims(description, labelWidth2) {
|
|
44758
45161
|
const minW = Math.min(
|
|
44759
45162
|
MAX_NODE_WIDTH3,
|
|
44760
|
-
Math.max(MIN_NODE_WIDTH4,
|
|
45163
|
+
Math.max(MIN_NODE_WIDTH4, labelWidth2, DESC_MIN_WIDTH)
|
|
44761
45164
|
);
|
|
44762
45165
|
let best = null;
|
|
44763
45166
|
let bestScore = Infinity;
|
|
@@ -45185,7 +45588,8 @@ function renderCycle(container, parsed, palette, isDark, onClickItem, exportDims
|
|
|
45185
45588
|
const hideDescriptions = (renderOptions?.hideDescriptions ?? false) || parsed.options["no-descriptions"] === "true" || viewState?.hd === true;
|
|
45186
45589
|
const showDescriptions = !hideDescriptions;
|
|
45187
45590
|
const hasDescriptions = parsed.nodes.some((n) => n.description.length > 0) || parsed.edges.some((e) => e.description.length > 0);
|
|
45188
|
-
const
|
|
45591
|
+
const appHostedControls = renderOptions?.controlsHost === "app";
|
|
45592
|
+
const hasLegend = !appHostedControls && hasDescriptions && !!renderOptions?.onToggleDescriptions;
|
|
45189
45593
|
const showTitle = !!parsed.title && parsed.options["no-title"] !== "on";
|
|
45190
45594
|
const legendOffset = hasLegend ? sLegendHeight : 0;
|
|
45191
45595
|
const layoutHeight = height - (showTitle ? sTitleAreaHeight : 0) - legendOffset;
|
|
@@ -45222,7 +45626,10 @@ function renderCycle(container, parsed, palette, isDark, onClickItem, exportDims
|
|
|
45222
45626
|
groups: [],
|
|
45223
45627
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
45224
45628
|
mode: renderOptions?.exportMode ? "export" : "preview",
|
|
45225
|
-
controlsGroup
|
|
45629
|
+
controlsGroup,
|
|
45630
|
+
...renderOptions?.controlsHost !== void 0 && {
|
|
45631
|
+
controlsHost: renderOptions.controlsHost
|
|
45632
|
+
}
|
|
45226
45633
|
};
|
|
45227
45634
|
const legendState = {
|
|
45228
45635
|
activeGroup: null,
|
|
@@ -45493,6 +45900,107 @@ function featureIndex(topo) {
|
|
|
45493
45900
|
}
|
|
45494
45901
|
return idx;
|
|
45495
45902
|
}
|
|
45903
|
+
function buildAdjacency(topo) {
|
|
45904
|
+
const cached = adjacencyCache.get(topo);
|
|
45905
|
+
if (cached) return cached;
|
|
45906
|
+
const geometries = geomObject(topo).geometries;
|
|
45907
|
+
const nb = (0, import_topojson_client.neighbors)(geometries);
|
|
45908
|
+
const sets = /* @__PURE__ */ new Map();
|
|
45909
|
+
geometries.forEach((g, i) => {
|
|
45910
|
+
if (!g.type || g.type === "null") return;
|
|
45911
|
+
let set = sets.get(g.id);
|
|
45912
|
+
if (!set) {
|
|
45913
|
+
set = /* @__PURE__ */ new Set();
|
|
45914
|
+
sets.set(g.id, set);
|
|
45915
|
+
}
|
|
45916
|
+
for (const j of nb[i] ?? []) {
|
|
45917
|
+
const nid = geometries[j]?.id;
|
|
45918
|
+
if (nid && nid !== g.id) set.add(nid);
|
|
45919
|
+
}
|
|
45920
|
+
});
|
|
45921
|
+
const out = /* @__PURE__ */ new Map();
|
|
45922
|
+
for (const [iso, set] of sets) out.set(iso, [...set].sort());
|
|
45923
|
+
adjacencyCache.set(topo, out);
|
|
45924
|
+
return out;
|
|
45925
|
+
}
|
|
45926
|
+
function decodeFeatures(topo) {
|
|
45927
|
+
return geomObject(topo).geometries.map((g) => {
|
|
45928
|
+
const f = (0, import_topojson_client.feature)(topo, g);
|
|
45929
|
+
return {
|
|
45930
|
+
type: "Feature",
|
|
45931
|
+
id: g.id,
|
|
45932
|
+
properties: g.properties,
|
|
45933
|
+
geometry: f.geometry
|
|
45934
|
+
};
|
|
45935
|
+
});
|
|
45936
|
+
}
|
|
45937
|
+
function pointInRing(lon, lat, ring) {
|
|
45938
|
+
let inside = false;
|
|
45939
|
+
for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
|
|
45940
|
+
const xi = ring[i][0];
|
|
45941
|
+
const yi = ring[i][1];
|
|
45942
|
+
const xj = ring[j][0];
|
|
45943
|
+
const yj = ring[j][1];
|
|
45944
|
+
const intersect = yi > lat !== yj > lat && lon < (xj - xi) * (lat - yi) / (yj - yi) + xi;
|
|
45945
|
+
if (intersect) inside = !inside;
|
|
45946
|
+
}
|
|
45947
|
+
return inside;
|
|
45948
|
+
}
|
|
45949
|
+
function pointOnRingEdge(lon, lat, ring) {
|
|
45950
|
+
for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
|
|
45951
|
+
const xi = ring[i][0];
|
|
45952
|
+
const yi = ring[i][1];
|
|
45953
|
+
const xj = ring[j][0];
|
|
45954
|
+
const yj = ring[j][1];
|
|
45955
|
+
if (lon < Math.min(xi, xj) - EDGE_EPS || lon > Math.max(xi, xj) + EDGE_EPS)
|
|
45956
|
+
continue;
|
|
45957
|
+
if (lat < Math.min(yi, yj) - EDGE_EPS || lat > Math.max(yi, yj) + EDGE_EPS)
|
|
45958
|
+
continue;
|
|
45959
|
+
const cross = (xj - xi) * (lat - yi) - (yj - yi) * (lon - xi);
|
|
45960
|
+
if (Math.abs(cross) <= EDGE_EPS) return true;
|
|
45961
|
+
}
|
|
45962
|
+
return false;
|
|
45963
|
+
}
|
|
45964
|
+
function pointInGeometry(geometry, lon, lat) {
|
|
45965
|
+
const g = geometry;
|
|
45966
|
+
if (!g) return false;
|
|
45967
|
+
const polys = g.type === "Polygon" ? [g.coordinates] : g.type === "MultiPolygon" ? g.coordinates : [];
|
|
45968
|
+
for (const rings of polys) {
|
|
45969
|
+
if (!rings.length) continue;
|
|
45970
|
+
if (pointOnRingEdge(lon, lat, rings[0])) return true;
|
|
45971
|
+
if (!pointInRing(lon, lat, rings[0])) continue;
|
|
45972
|
+
let inHole = false;
|
|
45973
|
+
for (let h = 1; h < rings.length; h++) {
|
|
45974
|
+
if (pointInRing(lon, lat, rings[h]) && !pointOnRingEdge(lon, lat, rings[h])) {
|
|
45975
|
+
inHole = true;
|
|
45976
|
+
break;
|
|
45977
|
+
}
|
|
45978
|
+
}
|
|
45979
|
+
if (!inHole) return true;
|
|
45980
|
+
}
|
|
45981
|
+
return false;
|
|
45982
|
+
}
|
|
45983
|
+
function regionAt(lonLat, countries, states) {
|
|
45984
|
+
const lon = lonLat[0];
|
|
45985
|
+
const lat = lonLat[1];
|
|
45986
|
+
let country = null;
|
|
45987
|
+
for (const f of countries) {
|
|
45988
|
+
if (pointInGeometry(f.geometry, lon, lat)) {
|
|
45989
|
+
country = { iso: f.id, name: f.properties.name };
|
|
45990
|
+
break;
|
|
45991
|
+
}
|
|
45992
|
+
}
|
|
45993
|
+
let state = null;
|
|
45994
|
+
if (country?.iso === "US" && states) {
|
|
45995
|
+
for (const f of states) {
|
|
45996
|
+
if (pointInGeometry(f.geometry, lon, lat)) {
|
|
45997
|
+
state = { iso: f.id, name: f.properties.name };
|
|
45998
|
+
break;
|
|
45999
|
+
}
|
|
46000
|
+
}
|
|
46001
|
+
}
|
|
46002
|
+
return { country, state };
|
|
46003
|
+
}
|
|
45496
46004
|
function featureBbox(topo, geomId) {
|
|
45497
46005
|
const geom = geomObject(topo).geometries.find((g) => g.id === geomId);
|
|
45498
46006
|
if (!geom) return null;
|
|
@@ -45610,13 +46118,15 @@ function unionLongitudes(lons) {
|
|
|
45610
46118
|
}
|
|
45611
46119
|
return { west: pts[gapIdx], east: pts[gapIdx - 1] + 360 };
|
|
45612
46120
|
}
|
|
45613
|
-
var import_topojson_client, import_d3_geo, fold, DETACH_GAP_DEG, DETACH_AREA_FRAC;
|
|
46121
|
+
var import_topojson_client, import_d3_geo, fold, adjacencyCache, EDGE_EPS, DETACH_GAP_DEG, DETACH_AREA_FRAC;
|
|
45614
46122
|
var init_geo = __esm({
|
|
45615
46123
|
"src/map/geo.ts"() {
|
|
45616
46124
|
"use strict";
|
|
45617
46125
|
import_topojson_client = require("topojson-client");
|
|
45618
46126
|
import_d3_geo = require("d3-geo");
|
|
45619
46127
|
fold = (s) => s.normalize("NFD").replace(/\p{Diacritic}/gu, "").toLowerCase().trim();
|
|
46128
|
+
adjacencyCache = /* @__PURE__ */ new WeakMap();
|
|
46129
|
+
EDGE_EPS = 1e-9;
|
|
45620
46130
|
DETACH_GAP_DEG = 10;
|
|
45621
46131
|
DETACH_AREA_FRAC = 0.25;
|
|
45622
46132
|
}
|
|
@@ -45636,6 +46146,12 @@ function looksUS(lat, lon) {
|
|
|
45636
46146
|
if (lat < 15 || lat > 72) return false;
|
|
45637
46147
|
return lon >= -180 && lon <= -64 || lon >= 172;
|
|
45638
46148
|
}
|
|
46149
|
+
function looksNorthAmericaNeighbor(lat, lon) {
|
|
46150
|
+
return lat >= 14 && lat <= 72 && lon >= -141 && lon <= -52;
|
|
46151
|
+
}
|
|
46152
|
+
function isWholeSphere(bb) {
|
|
46153
|
+
return bb[0][0] <= -179 && bb[1][0] >= 179 && bb[0][1] <= -89 && bb[1][1] >= 89;
|
|
46154
|
+
}
|
|
45639
46155
|
function resolveMap(parsed, data) {
|
|
45640
46156
|
const diagnostics = [...parsed.diagnostics];
|
|
45641
46157
|
const err = (line12, message, code) => {
|
|
@@ -45646,9 +46162,6 @@ function resolveMap(parsed, data) {
|
|
|
45646
46162
|
};
|
|
45647
46163
|
const result = {
|
|
45648
46164
|
title: parsed.title,
|
|
45649
|
-
...parsed.directives.subtitle !== void 0 && {
|
|
45650
|
-
subtitle: parsed.directives.subtitle
|
|
45651
|
-
},
|
|
45652
46165
|
...parsed.directives.caption !== void 0 && {
|
|
45653
46166
|
caption: parsed.directives.caption
|
|
45654
46167
|
},
|
|
@@ -45658,7 +46171,7 @@ function resolveMap(parsed, data) {
|
|
|
45658
46171
|
// renderer's job (step 4) — the resolver only carries `tags` + `tagGroups`
|
|
45659
46172
|
// through; it never resolves a tag value to a palette color (#10).
|
|
45660
46173
|
directives: { ...parsed.directives },
|
|
45661
|
-
basemaps: { world: "
|
|
46174
|
+
basemaps: { world: "detail", subdivisions: [] },
|
|
45662
46175
|
regions: [],
|
|
45663
46176
|
pois: [],
|
|
45664
46177
|
edges: [],
|
|
@@ -45667,7 +46180,8 @@ function resolveMap(parsed, data) {
|
|
|
45667
46180
|
[-180, -85],
|
|
45668
46181
|
[180, 85]
|
|
45669
46182
|
],
|
|
45670
|
-
projection: "
|
|
46183
|
+
projection: "equirectangular",
|
|
46184
|
+
poiFrameContainers: [],
|
|
45671
46185
|
diagnostics,
|
|
45672
46186
|
error: parsed.error
|
|
45673
46187
|
};
|
|
@@ -45677,7 +46191,10 @@ function resolveMap(parsed, data) {
|
|
|
45677
46191
|
...[...countryIndex.values()].map((v) => v.name),
|
|
45678
46192
|
...[...usStateIndex.values()].map((v) => v.name)
|
|
45679
46193
|
];
|
|
45680
|
-
const
|
|
46194
|
+
const localeRaw = parsed.directives.locale?.toUpperCase();
|
|
46195
|
+
const localeCountry = localeRaw ? localeRaw.split("-")[0] : void 0;
|
|
46196
|
+
const localeSubdivision = localeRaw && /^[A-Z]{2}-/.test(localeRaw) ? localeRaw : void 0;
|
|
46197
|
+
const usScoped = localeCountry === "US" || parsed.regions.some((r) => {
|
|
45681
46198
|
const f = fold(r.name);
|
|
45682
46199
|
return usStateIndex.has(f) && !countryIndex.has(f);
|
|
45683
46200
|
}) || parsed.regions.some(
|
|
@@ -45828,7 +46345,7 @@ function resolveMap(parsed, data) {
|
|
|
45828
46345
|
if (!scope)
|
|
45829
46346
|
warn2(
|
|
45830
46347
|
line12,
|
|
45831
|
-
`"${name}" is ambiguous \u2014 resolved to the most-populous match.`,
|
|
46348
|
+
`"${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.`,
|
|
45832
46349
|
"W_MAP_AMBIGUOUS_NAME"
|
|
45833
46350
|
);
|
|
45834
46351
|
}
|
|
@@ -45841,17 +46358,21 @@ function resolveMap(parsed, data) {
|
|
|
45841
46358
|
return fold(pos.name);
|
|
45842
46359
|
};
|
|
45843
46360
|
const poiCountries = [];
|
|
45844
|
-
let
|
|
46361
|
+
let anyUsPoi = false;
|
|
46362
|
+
let anyNonNaPoi = false;
|
|
45845
46363
|
const noteCountry = (iso) => {
|
|
45846
46364
|
if (iso) {
|
|
45847
46365
|
poiCountries.push(iso);
|
|
45848
|
-
if (iso
|
|
46366
|
+
if (iso === "US") anyUsPoi = true;
|
|
46367
|
+
if (iso !== "US" && iso !== "CA" && iso !== "MX") anyNonNaPoi = true;
|
|
45849
46368
|
}
|
|
45850
46369
|
};
|
|
45851
46370
|
const deferred = [];
|
|
45852
46371
|
for (const p of parsed.pois) {
|
|
45853
46372
|
if (p.pos.kind === "coords") {
|
|
45854
|
-
if (
|
|
46373
|
+
if (looksUS(p.pos.lat, p.pos.lon)) anyUsPoi = true;
|
|
46374
|
+
else if (!looksNorthAmericaNeighbor(p.pos.lat, p.pos.lon))
|
|
46375
|
+
anyNonNaPoi = true;
|
|
45855
46376
|
addResolvedPoi(p.pos.lat, p.pos.lon, p);
|
|
45856
46377
|
continue;
|
|
45857
46378
|
}
|
|
@@ -45869,14 +46390,15 @@ function resolveMap(parsed, data) {
|
|
|
45869
46390
|
deferred.push(p);
|
|
45870
46391
|
}
|
|
45871
46392
|
}
|
|
45872
|
-
const inferredCountry =
|
|
46393
|
+
const inferredCountry = localeCountry ?? mostCommonCountry(regions, poiCountries) ?? void 0;
|
|
46394
|
+
const inferredScope = localeSubdivision ?? inferredCountry;
|
|
45873
46395
|
for (const p of deferred) {
|
|
45874
46396
|
if (p.pos.kind !== "name") continue;
|
|
45875
46397
|
const got = lookupName(
|
|
45876
46398
|
p.pos.name,
|
|
45877
46399
|
p.pos.scope,
|
|
45878
46400
|
p.lineNumber,
|
|
45879
|
-
|
|
46401
|
+
inferredScope,
|
|
45880
46402
|
true
|
|
45881
46403
|
);
|
|
45882
46404
|
if (got.kind === "ok") {
|
|
@@ -45946,7 +46468,8 @@ function resolveMap(parsed, data) {
|
|
|
45946
46468
|
const meta = sizeValue !== void 0 ? { value: sizeValue } : {};
|
|
45947
46469
|
if (pos.kind === "coords") {
|
|
45948
46470
|
const id = alias ? fold(alias) : `@${pos.lat},${pos.lon}`;
|
|
45949
|
-
if (
|
|
46471
|
+
if (looksUS(pos.lat, pos.lon)) anyUsPoi = true;
|
|
46472
|
+
else if (!looksNorthAmericaNeighbor(pos.lat, pos.lon)) anyNonNaPoi = true;
|
|
45950
46473
|
if (!registry.has(id)) {
|
|
45951
46474
|
registerPoi(
|
|
45952
46475
|
id,
|
|
@@ -45969,7 +46492,7 @@ function resolveMap(parsed, data) {
|
|
|
45969
46492
|
if (registry.has(f)) return f;
|
|
45970
46493
|
const aliased = declaredByName.get(f);
|
|
45971
46494
|
if (aliased) return aliased;
|
|
45972
|
-
const got = lookupName(pos.name, pos.scope, line12,
|
|
46495
|
+
const got = lookupName(pos.name, pos.scope, line12, inferredScope, true);
|
|
45973
46496
|
if (got.kind !== "ok") return null;
|
|
45974
46497
|
noteCountry(got.iso);
|
|
45975
46498
|
registerPoi(
|
|
@@ -46026,9 +46549,12 @@ function resolveMap(parsed, data) {
|
|
|
46026
46549
|
}
|
|
46027
46550
|
routes.push({ stopIds, legs, lineNumber: rt.lineNumber });
|
|
46028
46551
|
}
|
|
46552
|
+
const hasUsContent = usSubdivisionReferenced || anyUsPoi || localeCountry === "US";
|
|
46553
|
+
const usOriented = !anyNonNaPoi && !regions.some(
|
|
46554
|
+
(r) => r.layer === "country" && !["US", "CA", "MX"].includes(r.iso)
|
|
46555
|
+
) && hasUsContent;
|
|
46029
46556
|
const subdivisions = [];
|
|
46030
|
-
if (usSubdivisionReferenced ||
|
|
46031
|
-
subdivisions.push("us-states");
|
|
46557
|
+
if (usSubdivisionReferenced || usOriented) subdivisions.push("us-states");
|
|
46032
46558
|
const regionBoxes = [];
|
|
46033
46559
|
for (const ref of referencedRegionIds) {
|
|
46034
46560
|
const bb = featureBbox(data.usStates, ref.id);
|
|
@@ -46046,17 +46572,51 @@ function resolveMap(parsed, data) {
|
|
|
46046
46572
|
[-180, -85],
|
|
46047
46573
|
[180, 85]
|
|
46048
46574
|
];
|
|
46049
|
-
|
|
46575
|
+
const basePad = regions.length > 0 ? REGION_PAD_FRACTION : PAD_FRACTION;
|
|
46576
|
+
let extent2 = unioned ? pad(unioned, basePad) : DEFAULT_EXTENT;
|
|
46577
|
+
const isPoiOnly = pois.length > 0 && regions.length === 0;
|
|
46578
|
+
const containerRegionIds = [];
|
|
46579
|
+
if (isPoiOnly) {
|
|
46580
|
+
const countries = decodeFeatures(data.worldDetail);
|
|
46581
|
+
const states = decodeFeatures(data.usStates);
|
|
46582
|
+
const seen = /* @__PURE__ */ new Set();
|
|
46583
|
+
const containerBoxes = [];
|
|
46584
|
+
for (const p of pois) {
|
|
46585
|
+
const { country, state } = regionAt([p.lon, p.lat], countries, states);
|
|
46586
|
+
const id = state?.iso ?? country?.iso;
|
|
46587
|
+
if (!id || seen.has(id)) continue;
|
|
46588
|
+
seen.add(id);
|
|
46589
|
+
containerRegionIds.push(id);
|
|
46590
|
+
const bb = state ? featureBbox(data.usStates, id) : featureBboxPrimary(data.worldCoarse, id);
|
|
46591
|
+
if (bb && !isWholeSphere(bb)) containerBoxes.push(bb);
|
|
46592
|
+
}
|
|
46593
|
+
const containerUnion = unionExtent(containerBoxes, points);
|
|
46594
|
+
if (containerUnion) extent2 = pad(containerUnion, PAD_FRACTION);
|
|
46595
|
+
}
|
|
46596
|
+
if (isPoiOnly) {
|
|
46597
|
+
const cx = (extent2[0][0] + extent2[1][0]) / 2;
|
|
46598
|
+
const cy = (extent2[0][1] + extent2[1][1]) / 2;
|
|
46599
|
+
const lon = extent2[1][0] - extent2[0][0];
|
|
46600
|
+
const lat = extent2[1][1] - extent2[0][1];
|
|
46601
|
+
const longer = Math.max(lon, lat);
|
|
46602
|
+
if (longer > 0 && longer < POI_ZOOM_FLOOR_DEG) {
|
|
46603
|
+
const k = POI_ZOOM_FLOOR_DEG / longer;
|
|
46604
|
+
const halfLon = lon * k / 2;
|
|
46605
|
+
const halfLat = lat * k / 2;
|
|
46606
|
+
extent2 = [
|
|
46607
|
+
[cx - halfLon, cy - halfLat],
|
|
46608
|
+
[cx + halfLon, cy + halfLat]
|
|
46609
|
+
];
|
|
46610
|
+
}
|
|
46611
|
+
}
|
|
46050
46612
|
const lonSpan = extent2[1][0] - extent2[0][0];
|
|
46051
46613
|
const latSpan = extent2[1][1] - extent2[0][1];
|
|
46052
46614
|
const span = Math.max(lonSpan, latSpan);
|
|
46053
46615
|
const maxAbsLat = Math.max(Math.abs(extent2[0][1]), Math.abs(extent2[1][1]));
|
|
46054
|
-
const usDominant = (subdivisions.includes("us-states") || regions.some((r) => r.layer === "us-state")) && !regions.some((r) => r.layer === "country" && r.iso !== "US") && !anyNonUsPoi;
|
|
46055
46616
|
let projection;
|
|
46056
|
-
|
|
46057
|
-
|
|
46058
|
-
|
|
46059
|
-
} else if (usDominant) {
|
|
46617
|
+
if (isPoiOnly && usOriented && lonSpan < US_NATIONAL_LON_SPAN) {
|
|
46618
|
+
projection = "mercator";
|
|
46619
|
+
} else if (usOriented) {
|
|
46060
46620
|
projection = "albers-usa";
|
|
46061
46621
|
} else if (span > WORLD_SPAN || maxAbsLat > MERCATOR_MAX_LAT) {
|
|
46062
46622
|
projection = "equirectangular";
|
|
@@ -46074,11 +46634,20 @@ function resolveMap(parsed, data) {
|
|
|
46074
46634
|
result.edges = edges;
|
|
46075
46635
|
result.routes = routes;
|
|
46076
46636
|
result.basemaps = {
|
|
46077
|
-
|
|
46637
|
+
// Tier is intentionally pinned to detail (50m) at ALL scales. Diagrammo maps
|
|
46638
|
+
// are presentational (palette tints, relief hachures, POI hubs), not
|
|
46639
|
+
// survey-grade — recognizability > generalization: 110m coarse drops the
|
|
46640
|
+
// Italian boot to a stump at world scale. `WORLD_SPAN` lives on only for the
|
|
46641
|
+
// projection decision (the `usOriented`/`span > WORLD_SPAN` chain above); it
|
|
46642
|
+
// no longer gates basemap resolution.
|
|
46643
|
+
// `worldCoarse` is still loaded — it's the authoritative name/bbox index
|
|
46644
|
+
// (featureIndex, featureBboxPrimary), not dead code.
|
|
46645
|
+
world: "detail",
|
|
46078
46646
|
subdivisions
|
|
46079
46647
|
};
|
|
46080
46648
|
result.extent = extent2;
|
|
46081
46649
|
result.projection = projection;
|
|
46650
|
+
result.poiFrameContainers = containerRegionIds;
|
|
46082
46651
|
result.error = parsed.error ?? firstError(diagnostics);
|
|
46083
46652
|
return result;
|
|
46084
46653
|
}
|
|
@@ -46115,7 +46684,7 @@ function firstError(diags) {
|
|
|
46115
46684
|
const e = diags.find((d) => d.severity === "error");
|
|
46116
46685
|
return e ? formatDgmoError(e) : null;
|
|
46117
46686
|
}
|
|
46118
|
-
var WORLD_SPAN, MERCATOR_MAX_LAT, PAD_FRACTION, WORLD_LAT_SOUTH, WORLD_LAT_NORTH, REGION_ALIASES, US_STATE_POSTAL;
|
|
46687
|
+
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;
|
|
46119
46688
|
var init_resolver2 = __esm({
|
|
46120
46689
|
"src/map/resolver.ts"() {
|
|
46121
46690
|
"use strict";
|
|
@@ -46124,8 +46693,11 @@ var init_resolver2 = __esm({
|
|
|
46124
46693
|
WORLD_SPAN = 90;
|
|
46125
46694
|
MERCATOR_MAX_LAT = 80;
|
|
46126
46695
|
PAD_FRACTION = 0.05;
|
|
46696
|
+
REGION_PAD_FRACTION = 0.12;
|
|
46127
46697
|
WORLD_LAT_SOUTH = -58;
|
|
46128
46698
|
WORLD_LAT_NORTH = 78;
|
|
46699
|
+
POI_ZOOM_FLOOR_DEG = 7;
|
|
46700
|
+
US_NATIONAL_LON_SPAN = 48;
|
|
46129
46701
|
REGION_ALIASES = {
|
|
46130
46702
|
// Common everyday names → the Natural-Earth display name actually shipped.
|
|
46131
46703
|
"united states": "united states of america",
|
|
@@ -46203,17 +46775,305 @@ var init_resolver2 = __esm({
|
|
|
46203
46775
|
}
|
|
46204
46776
|
});
|
|
46205
46777
|
|
|
46778
|
+
// src/map/colorize.ts
|
|
46779
|
+
function assignColors(isos, adjacency) {
|
|
46780
|
+
const sorted = [...isos].sort();
|
|
46781
|
+
const byIso = /* @__PURE__ */ new Map();
|
|
46782
|
+
let maxIndex = -1;
|
|
46783
|
+
for (const iso of sorted) {
|
|
46784
|
+
const taken = /* @__PURE__ */ new Set();
|
|
46785
|
+
for (const n of adjacency.get(iso) ?? []) {
|
|
46786
|
+
const c = byIso.get(n);
|
|
46787
|
+
if (c !== void 0) taken.add(c);
|
|
46788
|
+
}
|
|
46789
|
+
let h = 0;
|
|
46790
|
+
while (taken.has(h)) h++;
|
|
46791
|
+
byIso.set(iso, h);
|
|
46792
|
+
if (h > maxIndex) maxIndex = h;
|
|
46793
|
+
}
|
|
46794
|
+
return { byIso, huesNeeded: maxIndex + 1 };
|
|
46795
|
+
}
|
|
46796
|
+
var init_colorize = __esm({
|
|
46797
|
+
"src/map/colorize.ts"() {
|
|
46798
|
+
"use strict";
|
|
46799
|
+
}
|
|
46800
|
+
});
|
|
46801
|
+
|
|
46802
|
+
// src/map/context-labels.ts
|
|
46803
|
+
function tierBand(maxSpanDeg) {
|
|
46804
|
+
if (maxSpanDeg >= 90) return "world";
|
|
46805
|
+
if (maxSpanDeg >= 20) return "continental";
|
|
46806
|
+
if (maxSpanDeg >= 5) return "regional";
|
|
46807
|
+
return "local";
|
|
46808
|
+
}
|
|
46809
|
+
function labelBudget(width, height, band) {
|
|
46810
|
+
const bandCap = {
|
|
46811
|
+
world: 6,
|
|
46812
|
+
continental: 5,
|
|
46813
|
+
regional: 4,
|
|
46814
|
+
local: 3
|
|
46815
|
+
};
|
|
46816
|
+
const area2 = Math.floor(Math.sqrt(Math.max(0, width * height)) / 150);
|
|
46817
|
+
return Math.max(0, Math.min(area2, bandCap[band]));
|
|
46818
|
+
}
|
|
46819
|
+
function waterEligible(tier, kind, band) {
|
|
46820
|
+
switch (band) {
|
|
46821
|
+
case "world":
|
|
46822
|
+
return tier <= 1 && (kind === "ocean" || kind === "sea");
|
|
46823
|
+
case "continental":
|
|
46824
|
+
return tier <= 2;
|
|
46825
|
+
case "regional":
|
|
46826
|
+
return tier <= 3;
|
|
46827
|
+
case "local":
|
|
46828
|
+
return tier <= 4;
|
|
46829
|
+
}
|
|
46830
|
+
}
|
|
46831
|
+
function insideViewport(p, width, height) {
|
|
46832
|
+
return !!p && Number.isFinite(p[0]) && Number.isFinite(p[1]) && p[0] >= 0 && p[0] <= width && p[1] >= 0 && p[1] <= height;
|
|
46833
|
+
}
|
|
46834
|
+
function labelWidth(text, letterSpacing) {
|
|
46835
|
+
const spacing = letterSpacing > 0 ? Math.max(0, text.length - 1) * letterSpacing : 0;
|
|
46836
|
+
return measureLegendText(text, FONT) + spacing + 2 * PADX;
|
|
46837
|
+
}
|
|
46838
|
+
function wrapLabel2(text, letterSpacing) {
|
|
46839
|
+
const words = text.split(/\s+/).filter(Boolean);
|
|
46840
|
+
if (words.length <= 1) return [text];
|
|
46841
|
+
const maxLines = words.length >= 4 ? 3 : 2;
|
|
46842
|
+
const n = words.length;
|
|
46843
|
+
let best = null;
|
|
46844
|
+
for (let mask = 0; mask < 1 << n - 1; mask++) {
|
|
46845
|
+
const lines = [];
|
|
46846
|
+
let cur = [words[0]];
|
|
46847
|
+
for (let i = 1; i < n; i++) {
|
|
46848
|
+
if (mask & 1 << i - 1) {
|
|
46849
|
+
lines.push(cur.join(" "));
|
|
46850
|
+
cur = [words[i]];
|
|
46851
|
+
} else cur.push(words[i]);
|
|
46852
|
+
}
|
|
46853
|
+
lines.push(cur.join(" "));
|
|
46854
|
+
if (lines.length > maxLines) continue;
|
|
46855
|
+
const cost = Math.round(
|
|
46856
|
+
Math.max(...lines.map((l) => labelWidth(l, letterSpacing)))
|
|
46857
|
+
);
|
|
46858
|
+
const head = labelWidth(lines[0], letterSpacing);
|
|
46859
|
+
if (!best || cost < best.cost || cost === best.cost && lines.length < best.lines.length || cost === best.cost && lines.length === best.lines.length && head > best.head)
|
|
46860
|
+
best = { lines, cost, head };
|
|
46861
|
+
}
|
|
46862
|
+
return best?.lines ?? [text];
|
|
46863
|
+
}
|
|
46864
|
+
function rectAround(cx, cy, lines, letterSpacing) {
|
|
46865
|
+
const w = Math.max(...lines.map((l) => labelWidth(l, letterSpacing)));
|
|
46866
|
+
const h = (lines.length - 1) * LINE_HEIGHT + FONT + 2 * PADY;
|
|
46867
|
+
return { x: cx - w / 2, y: cy - h / 2, w, h };
|
|
46868
|
+
}
|
|
46869
|
+
function rectFits(r, width, height) {
|
|
46870
|
+
return r.x >= 0 && r.y >= 0 && r.x + r.w <= width && r.y + r.h <= height;
|
|
46871
|
+
}
|
|
46872
|
+
function overlapsPadded(a, b, pad2) {
|
|
46873
|
+
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;
|
|
46874
|
+
}
|
|
46875
|
+
function placeContextLabels(args) {
|
|
46876
|
+
const {
|
|
46877
|
+
projection,
|
|
46878
|
+
dLonSpan,
|
|
46879
|
+
dLatSpan,
|
|
46880
|
+
width,
|
|
46881
|
+
height,
|
|
46882
|
+
waterBodies,
|
|
46883
|
+
countries,
|
|
46884
|
+
palette,
|
|
46885
|
+
project,
|
|
46886
|
+
collides,
|
|
46887
|
+
overLand
|
|
46888
|
+
} = args;
|
|
46889
|
+
void projection;
|
|
46890
|
+
const band = tierBand(Math.max(dLonSpan, dLatSpan));
|
|
46891
|
+
const budget = labelBudget(width, height, band);
|
|
46892
|
+
if (budget <= 0) return [];
|
|
46893
|
+
const waterColor = mix(palette.colors.blue, palette.textMuted, 50);
|
|
46894
|
+
const countryColor = palette.textMuted;
|
|
46895
|
+
const haloColor = palette.bg;
|
|
46896
|
+
const candidates = [];
|
|
46897
|
+
const center = [width / 2, height / 2];
|
|
46898
|
+
for (const e of waterBodies?.entries ?? []) {
|
|
46899
|
+
const [lat, lon, name, tier, kind, alt] = e;
|
|
46900
|
+
if (!waterEligible(tier, kind, band)) continue;
|
|
46901
|
+
const wlines = wrapLabel2(name, WATER_LETTER_SPACING);
|
|
46902
|
+
const anchorsLngLat = [[lon, lat]];
|
|
46903
|
+
for (const a of alt ?? []) anchorsLngLat.push([a[1], a[0]]);
|
|
46904
|
+
let best = null;
|
|
46905
|
+
let bestD = Infinity;
|
|
46906
|
+
let nearestProj = null;
|
|
46907
|
+
let nearestProjD = Infinity;
|
|
46908
|
+
for (const [aLon, aLat] of anchorsLngLat) {
|
|
46909
|
+
const p = project(aLon, aLat);
|
|
46910
|
+
if (!p || !Number.isFinite(p[0]) || !Number.isFinite(p[1])) continue;
|
|
46911
|
+
const d = (p[0] - center[0]) ** 2 + (p[1] - center[1]) ** 2;
|
|
46912
|
+
if (d < nearestProjD) {
|
|
46913
|
+
nearestProjD = d;
|
|
46914
|
+
nearestProj = p;
|
|
46915
|
+
}
|
|
46916
|
+
if (!insideViewport(p, width, height)) continue;
|
|
46917
|
+
if (d < bestD) {
|
|
46918
|
+
bestD = d;
|
|
46919
|
+
best = p;
|
|
46920
|
+
}
|
|
46921
|
+
}
|
|
46922
|
+
if (!best && tier === 0 && nearestProj) {
|
|
46923
|
+
const overX = Math.max(0, -nearestProj[0], nearestProj[0] - width);
|
|
46924
|
+
const overY = Math.max(0, -nearestProj[1], nearestProj[1] - height);
|
|
46925
|
+
if (overX <= width * EDGE_CLAMP_OVERSHOOT && overY <= height * EDGE_CLAMP_OVERSHOOT) {
|
|
46926
|
+
const halfW = Math.max(...wlines.map((l) => labelWidth(l, WATER_LETTER_SPACING))) / 2;
|
|
46927
|
+
const halfH = ((wlines.length - 1) * LINE_HEIGHT + FONT + 2 * PADY) / 2;
|
|
46928
|
+
const m = EDGE_CLAMP_MARGIN;
|
|
46929
|
+
best = [
|
|
46930
|
+
Math.min(Math.max(nearestProj[0], halfW + m), width - halfW - m),
|
|
46931
|
+
Math.min(Math.max(nearestProj[1], halfH + m), height - halfH - m)
|
|
46932
|
+
];
|
|
46933
|
+
}
|
|
46934
|
+
}
|
|
46935
|
+
if (!best) continue;
|
|
46936
|
+
candidates.push({
|
|
46937
|
+
text: name,
|
|
46938
|
+
lines: wlines,
|
|
46939
|
+
cx: best[0],
|
|
46940
|
+
cy: best[1],
|
|
46941
|
+
italic: true,
|
|
46942
|
+
letterSpacing: WATER_LETTER_SPACING,
|
|
46943
|
+
color: waterColor,
|
|
46944
|
+
// Water before any country (×1000), then by tier, then kind, then name.
|
|
46945
|
+
sort: tier * 10 + KIND_ORDER[kind]
|
|
46946
|
+
});
|
|
46947
|
+
}
|
|
46948
|
+
const ranked = countries.map((c) => {
|
|
46949
|
+
const [x0, y0, x1, y1] = c.bbox;
|
|
46950
|
+
const w = x1 - x0;
|
|
46951
|
+
const h = y1 - y0;
|
|
46952
|
+
return { c, w, h, area: w * h };
|
|
46953
|
+
}).filter((r) => Number.isFinite(r.area) && r.area > 0).sort((a, b) => b.area - a.area);
|
|
46954
|
+
let ci = 0;
|
|
46955
|
+
for (const r of ranked) {
|
|
46956
|
+
const { c, w, h } = r;
|
|
46957
|
+
if (w > width * 0.66 || h > height * 0.66) continue;
|
|
46958
|
+
if (!insideViewport(c.anchor, width, height)) continue;
|
|
46959
|
+
const text = c.name;
|
|
46960
|
+
const tw = labelWidth(text, 0);
|
|
46961
|
+
if (tw > w || FONT + 2 * PADY > h) continue;
|
|
46962
|
+
candidates.push({
|
|
46963
|
+
text,
|
|
46964
|
+
lines: [text],
|
|
46965
|
+
cx: c.anchor[0],
|
|
46966
|
+
cy: c.anchor[1],
|
|
46967
|
+
italic: false,
|
|
46968
|
+
letterSpacing: 0,
|
|
46969
|
+
color: countryColor,
|
|
46970
|
+
// Always after every water body (+1e6); larger area = earlier.
|
|
46971
|
+
sort: 1e6 + ci++
|
|
46972
|
+
});
|
|
46973
|
+
}
|
|
46974
|
+
candidates.sort((a, b) => a.sort - b.sort);
|
|
46975
|
+
const placed = [];
|
|
46976
|
+
const placedRects = [];
|
|
46977
|
+
for (const cand of candidates) {
|
|
46978
|
+
if (placed.length >= budget) break;
|
|
46979
|
+
const rect = rectAround(cand.cx, cand.cy, cand.lines, cand.letterSpacing);
|
|
46980
|
+
if (!rectFits(rect, width, height)) continue;
|
|
46981
|
+
if (cand.italic && overLand) {
|
|
46982
|
+
const inset = 2;
|
|
46983
|
+
const top = cand.cy - (cand.lines.length - 1) / 2 * LINE_HEIGHT;
|
|
46984
|
+
const touchesLand = cand.lines.some((line12, li) => {
|
|
46985
|
+
const lw = labelWidth(line12, cand.letterSpacing);
|
|
46986
|
+
const x0 = cand.cx - lw / 2 + inset;
|
|
46987
|
+
const x1 = cand.cx + lw / 2 - inset;
|
|
46988
|
+
const xs = [x0, (x0 + cand.cx) / 2, cand.cx, (cand.cx + x1) / 2, x1];
|
|
46989
|
+
const base = top + li * LINE_HEIGHT;
|
|
46990
|
+
return [base, base - FONT * 0.4, base - FONT * 0.8].some(
|
|
46991
|
+
(y) => xs.some((x) => overLand(x, y))
|
|
46992
|
+
);
|
|
46993
|
+
});
|
|
46994
|
+
if (touchesLand) continue;
|
|
46995
|
+
}
|
|
46996
|
+
if (collides(rect)) continue;
|
|
46997
|
+
if (placedRects.some((r) => overlapsPadded(rect, r, CONTEXT_PAD))) continue;
|
|
46998
|
+
placedRects.push(rect);
|
|
46999
|
+
placed.push({
|
|
47000
|
+
x: cand.cx,
|
|
47001
|
+
y: cand.cy,
|
|
47002
|
+
text: cand.text,
|
|
47003
|
+
anchor: "middle",
|
|
47004
|
+
color: cand.color,
|
|
47005
|
+
// No halo: the bg-coloured outline reads as a ghost box behind the text
|
|
47006
|
+
// over the tinted water/land. Context labels are muted enough to sit
|
|
47007
|
+
// cleanly on the basemap without one.
|
|
47008
|
+
halo: false,
|
|
47009
|
+
haloColor,
|
|
47010
|
+
italic: cand.italic,
|
|
47011
|
+
letterSpacing: cand.letterSpacing,
|
|
47012
|
+
...cand.lines.length > 1 ? { lines: cand.lines } : {},
|
|
47013
|
+
lineNumber: 0
|
|
47014
|
+
});
|
|
47015
|
+
}
|
|
47016
|
+
return placed;
|
|
47017
|
+
}
|
|
47018
|
+
var FONT, LINE_HEIGHT, PADX, PADY, WATER_LETTER_SPACING, CONTEXT_PAD, EDGE_CLAMP_MARGIN, EDGE_CLAMP_OVERSHOOT, KIND_ORDER;
|
|
47019
|
+
var init_context_labels = __esm({
|
|
47020
|
+
"src/map/context-labels.ts"() {
|
|
47021
|
+
"use strict";
|
|
47022
|
+
init_color_utils();
|
|
47023
|
+
init_legend_constants();
|
|
47024
|
+
FONT = 11;
|
|
47025
|
+
LINE_HEIGHT = FONT + 2;
|
|
47026
|
+
PADX = 4;
|
|
47027
|
+
PADY = 3;
|
|
47028
|
+
WATER_LETTER_SPACING = 1.5;
|
|
47029
|
+
CONTEXT_PAD = 4;
|
|
47030
|
+
EDGE_CLAMP_MARGIN = 8;
|
|
47031
|
+
EDGE_CLAMP_OVERSHOOT = 0.35;
|
|
47032
|
+
KIND_ORDER = {
|
|
47033
|
+
ocean: 0,
|
|
47034
|
+
sea: 1,
|
|
47035
|
+
gulf: 2,
|
|
47036
|
+
bay: 3,
|
|
47037
|
+
strait: 4,
|
|
47038
|
+
channel: 5,
|
|
47039
|
+
sound: 6
|
|
47040
|
+
};
|
|
47041
|
+
}
|
|
47042
|
+
});
|
|
47043
|
+
|
|
46206
47044
|
// src/map/layout.ts
|
|
46207
47045
|
function geomObject2(topo) {
|
|
46208
47046
|
const key = Object.keys(topo.objects)[0];
|
|
46209
47047
|
return topo.objects[key];
|
|
46210
47048
|
}
|
|
47049
|
+
function mergeFeatures(a, b) {
|
|
47050
|
+
const polysOf = (f) => {
|
|
47051
|
+
const g = f.geometry;
|
|
47052
|
+
if (!g) return null;
|
|
47053
|
+
if (g.type === "Polygon") return [g.coordinates];
|
|
47054
|
+
if (g.type === "MultiPolygon") return g.coordinates;
|
|
47055
|
+
return null;
|
|
47056
|
+
};
|
|
47057
|
+
const pa = polysOf(a);
|
|
47058
|
+
const pb = polysOf(b);
|
|
47059
|
+
if (!pa || !pb) return a;
|
|
47060
|
+
return {
|
|
47061
|
+
...a,
|
|
47062
|
+
geometry: { type: "MultiPolygon", coordinates: [...pa, ...pb] }
|
|
47063
|
+
};
|
|
47064
|
+
}
|
|
46211
47065
|
function decodeLayer(topo) {
|
|
47066
|
+
const cached = decodeCache.get(topo);
|
|
47067
|
+
if (cached) return cached;
|
|
46212
47068
|
const out = /* @__PURE__ */ new Map();
|
|
46213
47069
|
for (const g of geomObject2(topo).geometries) {
|
|
46214
47070
|
const f = (0, import_topojson_client2.feature)(topo, g);
|
|
46215
|
-
|
|
47071
|
+
if (!f.geometry) continue;
|
|
47072
|
+
const tagged = { ...f, id: g.id };
|
|
47073
|
+
const existing = out.get(g.id);
|
|
47074
|
+
out.set(g.id, existing ? mergeFeatures(existing, tagged) : tagged);
|
|
46216
47075
|
}
|
|
47076
|
+
decodeCache.set(topo, out);
|
|
46217
47077
|
return out;
|
|
46218
47078
|
}
|
|
46219
47079
|
function projectionFor(family) {
|
|
@@ -46222,9 +47082,12 @@ function projectionFor(family) {
|
|
|
46222
47082
|
return usConusProjection();
|
|
46223
47083
|
case "mercator":
|
|
46224
47084
|
return (0, import_d3_geo2.geoMercator)();
|
|
47085
|
+
case "equal-earth":
|
|
47086
|
+
return (0, import_d3_geo2.geoEqualEarth)();
|
|
47087
|
+
case "equirectangular":
|
|
47088
|
+
return (0, import_d3_geo2.geoEquirectangular)();
|
|
46225
47089
|
case "natural-earth":
|
|
46226
47090
|
return (0, import_d3_geo2.geoNaturalEarth1)();
|
|
46227
|
-
case "equirectangular":
|
|
46228
47091
|
default:
|
|
46229
47092
|
return (0, import_d3_geo2.geoEquirectangular)();
|
|
46230
47093
|
}
|
|
@@ -46243,13 +47106,11 @@ function mapNeutralLandColor(palette, isDark, _dataActive = false) {
|
|
|
46243
47106
|
isDark ? LAND_TINT_DARK : LAND_TINT_LIGHT
|
|
46244
47107
|
);
|
|
46245
47108
|
}
|
|
46246
|
-
function
|
|
46247
|
-
const { palette, isDark } = opts;
|
|
46248
|
-
const { width, height } = size;
|
|
47109
|
+
function buildMapProjection(resolved, data) {
|
|
46249
47110
|
const wantsUsStates = resolved.basemaps.subdivisions.includes("us-states");
|
|
46250
|
-
const usCrisp = resolved.projection === "albers-usa" && wantsUsStates && !!data.naLand;
|
|
47111
|
+
const usCrisp = (resolved.projection === "albers-usa" || resolved.projection === "mercator") && wantsUsStates && !!data.naLand;
|
|
46251
47112
|
const worldTopo = usCrisp ? data.worldDetail : resolved.basemaps.world === "detail" ? data.worldDetail : data.worldCoarse;
|
|
46252
|
-
const worldLayer = decodeLayer(worldTopo);
|
|
47113
|
+
const worldLayer = new Map(decodeLayer(worldTopo));
|
|
46253
47114
|
if (usCrisp && data.naLand) {
|
|
46254
47115
|
const [nbW, nbS, nbE, nbN] = [-140, 10, -52, 66];
|
|
46255
47116
|
const crisp = decodeLayer(data.naLand);
|
|
@@ -46258,16 +47119,109 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46258
47119
|
if (!base) continue;
|
|
46259
47120
|
const [[bw, bs], [be, bn]] = (0, import_d3_geo2.geoBounds)(base);
|
|
46260
47121
|
if (bw >= nbW && be <= nbE && bs >= nbS && bn <= nbN)
|
|
46261
|
-
worldLayer.set(iso, cf);
|
|
47122
|
+
worldLayer.set(iso, { ...cf, properties: base.properties });
|
|
46262
47123
|
}
|
|
46263
47124
|
}
|
|
46264
47125
|
const usLayer = wantsUsStates ? decodeLayer(data.usStates) : null;
|
|
47126
|
+
const extentOutline = () => {
|
|
47127
|
+
const [[w, s], [e, n]] = resolved.extent;
|
|
47128
|
+
const N = 16;
|
|
47129
|
+
const coords = [];
|
|
47130
|
+
for (let i = 0; i <= N; i++) {
|
|
47131
|
+
const t = i / N;
|
|
47132
|
+
const lon = w + (e - w) * t;
|
|
47133
|
+
const lat = s + (n - s) * t;
|
|
47134
|
+
coords.push([lon, s], [lon, n], [w, lat], [e, lat]);
|
|
47135
|
+
}
|
|
47136
|
+
return {
|
|
47137
|
+
type: "Feature",
|
|
47138
|
+
properties: {},
|
|
47139
|
+
geometry: { type: "MultiPoint", coordinates: coords }
|
|
47140
|
+
};
|
|
47141
|
+
};
|
|
47142
|
+
let fitFeatures;
|
|
47143
|
+
if (resolved.projection === "albers-usa" && usLayer) {
|
|
47144
|
+
fitFeatures = [...usLayer.entries()].filter(([iso]) => !US_NON_CONUS.has(iso)).map(([, f]) => f);
|
|
47145
|
+
const neighborPoints = resolved.pois.filter((p) => !inAlaska(p.lon, p.lat) && !inHawaii(p.lon, p.lat)).map((p) => [p.lon, p.lat]);
|
|
47146
|
+
if (neighborPoints.length > 0) {
|
|
47147
|
+
fitFeatures.push({
|
|
47148
|
+
type: "Feature",
|
|
47149
|
+
properties: {},
|
|
47150
|
+
geometry: { type: "MultiPoint", coordinates: neighborPoints }
|
|
47151
|
+
});
|
|
47152
|
+
}
|
|
47153
|
+
for (const r of resolved.regions) {
|
|
47154
|
+
if (r.layer === "country" && (r.iso === "CA" || r.iso === "MX")) {
|
|
47155
|
+
const cf = worldLayer.get(r.iso);
|
|
47156
|
+
if (cf) fitFeatures.push(cf);
|
|
47157
|
+
}
|
|
47158
|
+
}
|
|
47159
|
+
} else {
|
|
47160
|
+
fitFeatures = [extentOutline()];
|
|
47161
|
+
}
|
|
47162
|
+
const fitTarget = { type: "FeatureCollection", features: fitFeatures };
|
|
47163
|
+
const projection = projectionFor(resolved.projection);
|
|
47164
|
+
if (resolved.projection !== "albers-usa") {
|
|
47165
|
+
let centerLon = (resolved.extent[0][0] + resolved.extent[1][0]) / 2;
|
|
47166
|
+
if (centerLon > 180) centerLon -= 360;
|
|
47167
|
+
projection.rotate([-centerLon, 0]);
|
|
47168
|
+
}
|
|
47169
|
+
const fitGB = (0, import_d3_geo2.geoBounds)(fitTarget);
|
|
47170
|
+
const fitIsGlobal = fitGB[1][0] - fitGB[0][0] >= 270 || fitGB[1][1] - fitGB[0][1] >= 130;
|
|
47171
|
+
return {
|
|
47172
|
+
projection,
|
|
47173
|
+
fitTarget,
|
|
47174
|
+
fitIsGlobal,
|
|
47175
|
+
worldLayer,
|
|
47176
|
+
usLayer,
|
|
47177
|
+
usCrisp,
|
|
47178
|
+
wantsUsStates,
|
|
47179
|
+
worldTopo
|
|
47180
|
+
};
|
|
47181
|
+
}
|
|
47182
|
+
function parsePathRings(d) {
|
|
47183
|
+
const rings = [];
|
|
47184
|
+
let cur = [];
|
|
47185
|
+
const re = /([MLZ])([^MLZ]*)/g;
|
|
47186
|
+
let m;
|
|
47187
|
+
while (m = re.exec(d)) {
|
|
47188
|
+
if (m[1] === "Z") {
|
|
47189
|
+
if (cur.length) rings.push(cur);
|
|
47190
|
+
cur = [];
|
|
47191
|
+
continue;
|
|
47192
|
+
}
|
|
47193
|
+
if (m[1] === "M" && cur.length) {
|
|
47194
|
+
rings.push(cur);
|
|
47195
|
+
cur = [];
|
|
47196
|
+
}
|
|
47197
|
+
const nums = m[2].split(/[ ,]+/).map(Number);
|
|
47198
|
+
for (let i = 0; i + 1 < nums.length; i += 2) {
|
|
47199
|
+
const x = nums[i];
|
|
47200
|
+
const y = nums[i + 1];
|
|
47201
|
+
if (Number.isFinite(x) && Number.isFinite(y)) cur.push([x, y]);
|
|
47202
|
+
}
|
|
47203
|
+
}
|
|
47204
|
+
if (cur.length) rings.push(cur);
|
|
47205
|
+
return rings;
|
|
47206
|
+
}
|
|
47207
|
+
function layoutMap(resolved, data, size, opts) {
|
|
47208
|
+
const { palette, isDark } = opts;
|
|
47209
|
+
const { width, height } = size;
|
|
47210
|
+
const {
|
|
47211
|
+
projection,
|
|
47212
|
+
fitTarget,
|
|
47213
|
+
fitIsGlobal,
|
|
47214
|
+
worldLayer,
|
|
47215
|
+
usLayer,
|
|
47216
|
+
usCrisp,
|
|
47217
|
+
worldTopo
|
|
47218
|
+
} = buildMapProjection(resolved, data);
|
|
46265
47219
|
const usContext = usLayer !== null;
|
|
46266
47220
|
const regionStroke = isDark ? mix(palette.bg, palette.text, 78) : mix(palette.text, palette.bg, 78);
|
|
46267
47221
|
const values = resolved.regions.filter((r) => r.value !== void 0).map((r) => r.value);
|
|
46268
|
-
const
|
|
46269
|
-
const rampMin =
|
|
46270
|
-
const rampMax =
|
|
47222
|
+
const allNonNegative = values.length > 0 && values.every((v) => v >= 0);
|
|
47223
|
+
const rampMin = allNonNegative ? 0 : Math.min(...values);
|
|
47224
|
+
const rampMax = Math.max(...values);
|
|
46271
47225
|
const rampHue = resolveColor(resolved.directives.regionMetricColor ?? "", palette) ?? palette.colors.red;
|
|
46272
47226
|
const hasRamp = values.length > 0;
|
|
46273
47227
|
const VALUE_NAME = hasRamp ? resolved.directives.regionMetric?.trim() || "Value" : null;
|
|
@@ -46288,7 +47242,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46288
47242
|
activeGroup = VALUE_NAME ?? (resolved.tagGroups.length > 0 ? resolved.tagGroups[0].name : null);
|
|
46289
47243
|
}
|
|
46290
47244
|
const activeIsScore = VALUE_NAME !== null && activeGroup === VALUE_NAME;
|
|
46291
|
-
const mutedBasemap =
|
|
47245
|
+
const mutedBasemap = activeGroup !== null;
|
|
46292
47246
|
const neutralFill = mapNeutralLandColor(palette, isDark, mutedBasemap);
|
|
46293
47247
|
const water = mapBackgroundColor(palette, isDark, mutedBasemap);
|
|
46294
47248
|
const lakeStroke = mix(regionStroke, water, 45);
|
|
@@ -46297,6 +47251,39 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46297
47251
|
palette.bg,
|
|
46298
47252
|
mutedBasemap ? isDark ? MUTED_FOREIGN_DARK : MUTED_FOREIGN_LIGHT : isDark ? FOREIGN_TINT_DARK : FOREIGN_TINT_LIGHT
|
|
46299
47253
|
);
|
|
47254
|
+
const colorizeActive = resolved.directives.noColorize !== true && !hasRamp && resolved.tagGroups.length === 0;
|
|
47255
|
+
const colorByIso = /* @__PURE__ */ new Map();
|
|
47256
|
+
if (colorizeActive) {
|
|
47257
|
+
const adjacency = /* @__PURE__ */ new Map();
|
|
47258
|
+
const addEdges = (src) => {
|
|
47259
|
+
for (const [iso, ns] of src) {
|
|
47260
|
+
const cur = adjacency.get(iso);
|
|
47261
|
+
if (cur) cur.push(...ns);
|
|
47262
|
+
else adjacency.set(iso, [...ns]);
|
|
47263
|
+
}
|
|
47264
|
+
};
|
|
47265
|
+
addEdges(buildAdjacency(worldTopo));
|
|
47266
|
+
if (usLayer) {
|
|
47267
|
+
addEdges(buildAdjacency(data.usStates));
|
|
47268
|
+
for (const [country, states] of Object.entries(FOREIGN_BORDER)) {
|
|
47269
|
+
const cn = adjacency.get(country);
|
|
47270
|
+
if (!cn) continue;
|
|
47271
|
+
for (const st of states) {
|
|
47272
|
+
const sn = adjacency.get(st);
|
|
47273
|
+
if (!sn) continue;
|
|
47274
|
+
cn.push(st);
|
|
47275
|
+
sn.push(country);
|
|
47276
|
+
}
|
|
47277
|
+
}
|
|
47278
|
+
}
|
|
47279
|
+
const { byIso, huesNeeded } = assignColors(
|
|
47280
|
+
[...adjacency.keys()],
|
|
47281
|
+
adjacency
|
|
47282
|
+
);
|
|
47283
|
+
const tints = politicalTints(palette, huesNeeded, isDark);
|
|
47284
|
+
for (const [iso, idx] of byIso) colorByIso.set(iso, tints[idx]);
|
|
47285
|
+
}
|
|
47286
|
+
const colorizeStroke = (fill2) => mix(fill2, palette.text, 35);
|
|
46300
47287
|
const rampBase = isDark ? mix(palette.surface, palette.text, 28) : palette.bg;
|
|
46301
47288
|
const fillForValue = (s) => {
|
|
46302
47289
|
const t = rampMax > rampMin ? (s - rampMin) / (rampMax - rampMin) : 1;
|
|
@@ -46332,43 +47319,15 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46332
47319
|
if (activeIsScore) {
|
|
46333
47320
|
return r.value !== void 0 ? fillForValue(r.value) : neutralFill;
|
|
46334
47321
|
}
|
|
47322
|
+
if (colorizeActive) return (r.iso && colorByIso.get(r.iso)) ?? neutralFill;
|
|
46335
47323
|
return tagFill(r.tags, activeGroup) ?? neutralFill;
|
|
46336
47324
|
};
|
|
46337
47325
|
const regionById = new Map(resolved.regions.map((r) => [r.iso, r]));
|
|
46338
|
-
const
|
|
46339
|
-
const [[w, s], [e, n]] = resolved.extent;
|
|
46340
|
-
const N = 16;
|
|
46341
|
-
const coords = [];
|
|
46342
|
-
for (let i = 0; i <= N; i++) {
|
|
46343
|
-
const t = i / N;
|
|
46344
|
-
const lon = w + (e - w) * t;
|
|
46345
|
-
const lat = s + (n - s) * t;
|
|
46346
|
-
coords.push([lon, s], [lon, n], [w, lat], [e, lat]);
|
|
46347
|
-
}
|
|
46348
|
-
return {
|
|
46349
|
-
type: "Feature",
|
|
46350
|
-
properties: {},
|
|
46351
|
-
geometry: { type: "MultiPoint", coordinates: coords }
|
|
46352
|
-
};
|
|
46353
|
-
};
|
|
46354
|
-
let fitFeatures;
|
|
46355
|
-
if (resolved.projection === "albers-usa" && usLayer) {
|
|
46356
|
-
fitFeatures = [...usLayer.entries()].filter(([iso]) => !US_NON_CONUS.has(iso)).map(([, f]) => f);
|
|
46357
|
-
} else {
|
|
46358
|
-
fitFeatures = [extentOutline()];
|
|
46359
|
-
}
|
|
46360
|
-
const fitTarget = { type: "FeatureCollection", features: fitFeatures };
|
|
46361
|
-
const projection = projectionFor(resolved.projection);
|
|
46362
|
-
if (resolved.projection !== "albers-usa") {
|
|
46363
|
-
let centerLon = (resolved.extent[0][0] + resolved.extent[1][0]) / 2;
|
|
46364
|
-
if (centerLon > 180) centerLon -= 360;
|
|
46365
|
-
projection.rotate([-centerLon, 0]);
|
|
46366
|
-
}
|
|
46367
|
-
const TITLE_GAP = 16;
|
|
47326
|
+
const TITLE_GAP2 = 16;
|
|
46368
47327
|
let topPad = FIT_PAD;
|
|
46369
47328
|
if (resolved.title && resolved.pois.length > 0) {
|
|
46370
47329
|
const bannerBottom = (resolved.subtitle ? TITLE_Y + TITLE_FONT_SIZE : TITLE_Y) + TITLE_FONT_SIZE / 2;
|
|
46371
|
-
topPad = Math.max(FIT_PAD, bannerBottom +
|
|
47330
|
+
topPad = Math.max(FIT_PAD, bannerBottom + TITLE_GAP2);
|
|
46372
47331
|
}
|
|
46373
47332
|
const fitBox = [
|
|
46374
47333
|
[FIT_PAD, topPad],
|
|
@@ -46378,12 +47337,10 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46378
47337
|
]
|
|
46379
47338
|
];
|
|
46380
47339
|
projection.fitExtent(fitBox, fitTarget);
|
|
46381
|
-
const fitGB = (0, import_d3_geo2.geoBounds)(fitTarget);
|
|
46382
|
-
const fitIsGlobal = fitGB[1][0] - fitGB[0][0] >= 270 || fitGB[1][1] - fitGB[0][1] >= 130;
|
|
46383
47340
|
let path;
|
|
46384
47341
|
let project;
|
|
46385
47342
|
let stretchParams = null;
|
|
46386
|
-
if (fitIsGlobal) {
|
|
47343
|
+
if (fitIsGlobal && !opts.preferContain) {
|
|
46387
47344
|
const cb = (0, import_d3_geo2.geoPath)(projection).bounds(fitTarget);
|
|
46388
47345
|
const bx0 = cb[0][0];
|
|
46389
47346
|
const by0 = cb[0][1];
|
|
@@ -46425,7 +47382,9 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46425
47382
|
const insets = [];
|
|
46426
47383
|
const insetRegions = [];
|
|
46427
47384
|
const insetLabelSeeds = [];
|
|
46428
|
-
|
|
47385
|
+
const akRef = resolved.regions.some((r) => r.iso === "US-AK") || resolved.pois.some((p) => inAlaska(p.lon, p.lat));
|
|
47386
|
+
const hiRef = resolved.regions.some((r) => r.iso === "US-HI") || resolved.pois.some((p) => inHawaii(p.lon, p.lat));
|
|
47387
|
+
if (resolved.projection === "albers-usa" && usLayer && (akRef || hiRef)) {
|
|
46429
47388
|
const PAD = 8;
|
|
46430
47389
|
const GAP = 12;
|
|
46431
47390
|
const yB = height - FIT_PAD;
|
|
@@ -46490,8 +47449,18 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46490
47449
|
);
|
|
46491
47450
|
const d = (0, import_d3_geo2.geoPath)(proj)(f) ?? "";
|
|
46492
47451
|
if (!d) return xr;
|
|
47452
|
+
let contextLand;
|
|
47453
|
+
if (iso === "US-AK") {
|
|
47454
|
+
const can = worldLayer.get("CA");
|
|
47455
|
+
const cd = can ? (0, import_d3_geo2.geoPath)(proj)(can) ?? "" : "";
|
|
47456
|
+
if (cd)
|
|
47457
|
+
contextLand = {
|
|
47458
|
+
d: cd,
|
|
47459
|
+
fill: colorizeActive ? colorByIso.get("CA") ?? foreignFill : foreignFill
|
|
47460
|
+
};
|
|
47461
|
+
}
|
|
46493
47462
|
const r = regionById.get(iso);
|
|
46494
|
-
let fill2 = neutralFill;
|
|
47463
|
+
let fill2 = colorizeActive ? colorByIso.get(iso) ?? neutralFill : neutralFill;
|
|
46495
47464
|
let lineNumber = -1;
|
|
46496
47465
|
if (r?.layer === "us-state") {
|
|
46497
47466
|
fill2 = regionFill(r);
|
|
@@ -46510,13 +47479,14 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46510
47479
|
],
|
|
46511
47480
|
// The FITTED inset projection (just fit to this box) — captured so the
|
|
46512
47481
|
// geo-query can invert pixels inside the frame back to AK/HI coords.
|
|
46513
|
-
projection: proj
|
|
47482
|
+
projection: proj,
|
|
47483
|
+
...contextLand && { contextLand }
|
|
46514
47484
|
});
|
|
46515
47485
|
insetRegions.push({
|
|
46516
47486
|
id: iso,
|
|
46517
47487
|
d,
|
|
46518
47488
|
fill: fill2,
|
|
46519
|
-
stroke: regionStroke,
|
|
47489
|
+
stroke: colorizeActive ? colorizeStroke(fill2) : regionStroke,
|
|
46520
47490
|
lineNumber,
|
|
46521
47491
|
layer: "us-state",
|
|
46522
47492
|
...r?.value !== void 0 && { value: r.value },
|
|
@@ -46529,13 +47499,16 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46529
47499
|
}
|
|
46530
47500
|
return xr;
|
|
46531
47501
|
};
|
|
46532
|
-
|
|
46533
|
-
|
|
46534
|
-
alaskaProjection(),
|
|
46535
|
-
|
|
46536
|
-
|
|
46537
|
-
|
|
46538
|
-
|
|
47502
|
+
let akRight = FIT_PAD;
|
|
47503
|
+
if (akRef)
|
|
47504
|
+
akRight = placeInset("US-AK", alaskaProjection(), FIT_PAD, width * 0.15);
|
|
47505
|
+
if (hiRef)
|
|
47506
|
+
placeInset(
|
|
47507
|
+
"US-HI",
|
|
47508
|
+
hawaiiProjection(),
|
|
47509
|
+
akRef ? akRight + 24 : FIT_PAD,
|
|
47510
|
+
width * 0.1
|
|
47511
|
+
);
|
|
46539
47512
|
}
|
|
46540
47513
|
const conusFit = resolved.projection === "albers-usa" && !!usLayer;
|
|
46541
47514
|
const classifyExtent = conusFit ? (0, import_d3_geo2.geoBounds)(fitTarget) : resolved.extent;
|
|
@@ -46551,15 +47524,24 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46551
47524
|
};
|
|
46552
47525
|
const ringOverlapsView = (ring) => {
|
|
46553
47526
|
let loMin = Infinity, loMax = -Infinity, rawMin = Infinity, rawMax = -Infinity;
|
|
47527
|
+
const lons = [];
|
|
46554
47528
|
for (const [rawLon] of ring) {
|
|
46555
47529
|
const lon = normLon(rawLon);
|
|
47530
|
+
lons.push(lon);
|
|
46556
47531
|
if (lon < loMin) loMin = lon;
|
|
46557
47532
|
if (lon > loMax) loMax = lon;
|
|
46558
47533
|
if (rawLon < rawMin) rawMin = rawLon;
|
|
46559
47534
|
if (rawLon > rawMax) rawMax = rawLon;
|
|
46560
47535
|
}
|
|
46561
|
-
|
|
46562
|
-
|
|
47536
|
+
lons.sort((a, b) => a - b);
|
|
47537
|
+
let maxGap = 0;
|
|
47538
|
+
for (let i = 1; i < lons.length; i++)
|
|
47539
|
+
maxGap = Math.max(maxGap, lons[i] - lons[i - 1]);
|
|
47540
|
+
if (lons.length > 1)
|
|
47541
|
+
maxGap = Math.max(maxGap, lons[0] + 360 - lons[lons.length - 1]);
|
|
47542
|
+
const occupiedArc = 360 - maxGap;
|
|
47543
|
+
if (occupiedArc > 270) return false;
|
|
47544
|
+
if (rawMax - rawMin > 180 && occupiedArc < 90) return false;
|
|
46563
47545
|
let px0 = Infinity, py0 = Infinity, px1 = -Infinity, py1 = -Infinity, anyFinite = false;
|
|
46564
47546
|
for (const [lon, lat] of ring) {
|
|
46565
47547
|
const p = project(lon, lat);
|
|
@@ -46632,7 +47614,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46632
47614
|
const regions = [];
|
|
46633
47615
|
const pushRegionLayer = (layerFeatures, layerKind, shouldCull) => {
|
|
46634
47616
|
for (const [iso, f] of layerFeatures) {
|
|
46635
|
-
if (layerKind === "us-state" && usContext && INSET_STATES.has(iso))
|
|
47617
|
+
if (layerKind === "us-state" && usContext && resolved.projection === "albers-usa" && INSET_STATES.has(iso))
|
|
46636
47618
|
continue;
|
|
46637
47619
|
if (layerKind === "country" && usContext && iso === "US") continue;
|
|
46638
47620
|
if (layerKind === "country" && iso === "AQ" && !regionById.has("AQ"))
|
|
@@ -46644,7 +47626,8 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46644
47626
|
if (!d) continue;
|
|
46645
47627
|
const isThisLayer = r?.layer === layerKind;
|
|
46646
47628
|
const isForeign = layerKind === "country" && usContext && iso !== "US";
|
|
46647
|
-
|
|
47629
|
+
const baseFill = isForeign ? foreignFill : neutralFill;
|
|
47630
|
+
let fill2 = colorizeActive ? colorByIso.get(iso) ?? baseFill : baseFill;
|
|
46648
47631
|
let label;
|
|
46649
47632
|
let lineNumber = -1;
|
|
46650
47633
|
let layer = "base";
|
|
@@ -46653,12 +47636,14 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46653
47636
|
lineNumber = r.lineNumber;
|
|
46654
47637
|
layer = layerKind;
|
|
46655
47638
|
label = r.name;
|
|
47639
|
+
} else {
|
|
47640
|
+
label = f.properties?.name;
|
|
46656
47641
|
}
|
|
46657
47642
|
regions.push({
|
|
46658
47643
|
id: iso,
|
|
46659
47644
|
d,
|
|
46660
47645
|
fill: fill2,
|
|
46661
|
-
stroke: regionStroke,
|
|
47646
|
+
stroke: colorizeActive ? colorizeStroke(fill2) : regionStroke,
|
|
46662
47647
|
lineNumber,
|
|
46663
47648
|
layer,
|
|
46664
47649
|
...label !== void 0 && { label },
|
|
@@ -46686,9 +47671,41 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46686
47671
|
});
|
|
46687
47672
|
}
|
|
46688
47673
|
}
|
|
47674
|
+
const pointInRings = (px, py, rings) => {
|
|
47675
|
+
let inside = false;
|
|
47676
|
+
for (const ring of rings) {
|
|
47677
|
+
for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
|
|
47678
|
+
const [xi, yi] = ring[i];
|
|
47679
|
+
const [xj, yj] = ring[j];
|
|
47680
|
+
if (yi > py !== yj > py && px < (xj - xi) * (py - yi) / (yj - yi) + xi)
|
|
47681
|
+
inside = !inside;
|
|
47682
|
+
}
|
|
47683
|
+
}
|
|
47684
|
+
return inside;
|
|
47685
|
+
};
|
|
47686
|
+
const fillHitTargets = [...regions, ...insetRegions].map((r) => ({
|
|
47687
|
+
fill: r.fill,
|
|
47688
|
+
rings: parsePathRings(r.d)
|
|
47689
|
+
}));
|
|
47690
|
+
const fillAt = (x, y) => {
|
|
47691
|
+
let hit = water;
|
|
47692
|
+
for (const t of fillHitTargets)
|
|
47693
|
+
if (pointInRings(x, y, t.rings)) hit = t.fill;
|
|
47694
|
+
return hit;
|
|
47695
|
+
};
|
|
47696
|
+
const labelOnFill = (fill2) => {
|
|
47697
|
+
const color = contrastRatio(fill2, palette.textOnFillDark) >= contrastRatio(fill2, palette.textOnFillLight) ? palette.textOnFillDark : palette.textOnFillLight;
|
|
47698
|
+
const haloColor = color === palette.textOnFillLight ? palette.textOnFillDark : palette.textOnFillLight;
|
|
47699
|
+
return {
|
|
47700
|
+
color,
|
|
47701
|
+
halo: contrastRatio(fill2, color) < REGION_LABEL_HALO_RATIO,
|
|
47702
|
+
haloColor
|
|
47703
|
+
};
|
|
47704
|
+
};
|
|
47705
|
+
const reliefAllowed = resolved.directives.noRelief !== true;
|
|
46689
47706
|
const relief = [];
|
|
46690
47707
|
let reliefHatch = null;
|
|
46691
|
-
if (
|
|
47708
|
+
if (reliefAllowed && data.mountainRanges) {
|
|
46692
47709
|
for (const [, f] of decodeLayer(data.mountainRanges)) {
|
|
46693
47710
|
const viewF = isGlobalView ? dropFrameFillers(f) : cullFeatureToView(f);
|
|
46694
47711
|
if (!viewF) continue;
|
|
@@ -46704,16 +47721,32 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46704
47721
|
if (relief.length) {
|
|
46705
47722
|
const darkTone = isDark ? palette.bg : palette.text;
|
|
46706
47723
|
const lightTone = isDark ? palette.text : palette.bg;
|
|
46707
|
-
const
|
|
47724
|
+
const reliefLandRef = colorizeActive ? isDark ? palette.surface : palette.bg : neutralFill;
|
|
47725
|
+
const landLum = relativeLuminance(reliefLandRef);
|
|
46708
47726
|
const tone = Math.abs(landLum - relativeLuminance(darkTone)) > 0.04 ? darkTone : lightTone;
|
|
46709
47727
|
reliefHatch = {
|
|
46710
|
-
color: mix(tone,
|
|
47728
|
+
color: mix(tone, reliefLandRef, RELIEF_HATCH_STRENGTH),
|
|
46711
47729
|
spacing: RELIEF_HATCH_SPACING,
|
|
46712
47730
|
width: RELIEF_HATCH_WIDTH
|
|
46713
47731
|
};
|
|
46714
47732
|
}
|
|
46715
47733
|
}
|
|
46716
|
-
|
|
47734
|
+
let coastlineStyle = null;
|
|
47735
|
+
if (resolved.directives.noCoastline !== true) {
|
|
47736
|
+
const minDim = Math.min(width, height);
|
|
47737
|
+
coastlineStyle = {
|
|
47738
|
+
color: mix(regionStroke, water, COASTLINE_STROKE_MIX),
|
|
47739
|
+
// N equal-width rings: distance steps outward by COASTLINE_STEP; opacity
|
|
47740
|
+
// fades linearly from NEAR (innermost) to FAR (outermost).
|
|
47741
|
+
lines: Array.from({ length: COASTLINE_RING_COUNT }, (_, k) => ({
|
|
47742
|
+
d: (COASTLINE_D0 + k * COASTLINE_STEP) * minDim,
|
|
47743
|
+
thickness: COASTLINE_THICKNESS * minDim,
|
|
47744
|
+
opacity: COASTLINE_OPACITY_NEAR + (COASTLINE_OPACITY_FAR - COASTLINE_OPACITY_NEAR) * k / (COASTLINE_RING_COUNT - 1)
|
|
47745
|
+
})),
|
|
47746
|
+
minExtent: (isGlobalView ? COASTLINE_MIN_EXTENT_GLOBAL : COASTLINE_MIN_EXTENT) * minDim
|
|
47747
|
+
};
|
|
47748
|
+
}
|
|
47749
|
+
const riverColor = mix(palette.colors.blue, water, 32);
|
|
46717
47750
|
const rivers = [];
|
|
46718
47751
|
if (data.rivers) {
|
|
46719
47752
|
for (const [, f] of decodeLayer(data.rivers)) {
|
|
@@ -46769,38 +47802,108 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46769
47802
|
const xy = project(p.lon, p.lat);
|
|
46770
47803
|
if (xy) projected.push({ p, xy });
|
|
46771
47804
|
}
|
|
46772
|
-
const
|
|
47805
|
+
const placePoi = (e, cx, cy, clusterId) => {
|
|
47806
|
+
const { fill: fill2, stroke: stroke2 } = poiFill(e.p);
|
|
47807
|
+
poiScreen.set(e.p.id, { cx, cy, r: radiusFor(e.p) });
|
|
47808
|
+
const num = routeNumberById.get(e.p.id);
|
|
47809
|
+
pois.push({
|
|
47810
|
+
id: e.p.id,
|
|
47811
|
+
cx,
|
|
47812
|
+
cy,
|
|
47813
|
+
r: radiusFor(e.p),
|
|
47814
|
+
fill: fill2,
|
|
47815
|
+
stroke: stroke2,
|
|
47816
|
+
lineNumber: e.p.lineNumber,
|
|
47817
|
+
implicit: !!e.p.implicit,
|
|
47818
|
+
isOrigin: originIds.has(e.p.id),
|
|
47819
|
+
...num !== void 0 && { routeNumber: num },
|
|
47820
|
+
...Object.keys(e.p.tags).length > 0 && { tags: e.p.tags },
|
|
47821
|
+
...clusterId !== void 0 && { clusterId }
|
|
47822
|
+
});
|
|
47823
|
+
};
|
|
47824
|
+
const clusters = [];
|
|
47825
|
+
const connected = /* @__PURE__ */ new Set();
|
|
47826
|
+
for (const e of resolved.edges) {
|
|
47827
|
+
connected.add(e.fromId);
|
|
47828
|
+
connected.add(e.toId);
|
|
47829
|
+
}
|
|
47830
|
+
for (const rt of resolved.routes) {
|
|
47831
|
+
rt.stopIds.forEach((id) => connected.add(id));
|
|
47832
|
+
}
|
|
47833
|
+
const radiusOf = (e) => radiusFor(e.p);
|
|
46773
47834
|
for (const e of projected) {
|
|
46774
|
-
|
|
46775
|
-
|
|
46776
|
-
|
|
46777
|
-
|
|
46778
|
-
|
|
46779
|
-
|
|
46780
|
-
|
|
46781
|
-
|
|
46782
|
-
|
|
46783
|
-
|
|
46784
|
-
|
|
46785
|
-
|
|
46786
|
-
|
|
46787
|
-
|
|
46788
|
-
|
|
46789
|
-
|
|
46790
|
-
|
|
46791
|
-
|
|
46792
|
-
|
|
46793
|
-
|
|
46794
|
-
|
|
46795
|
-
|
|
46796
|
-
|
|
46797
|
-
|
|
46798
|
-
|
|
46799
|
-
|
|
46800
|
-
|
|
46801
|
-
|
|
46802
|
-
|
|
46803
|
-
|
|
47835
|
+
if (connected.has(e.p.id)) placePoi(e, e.xy[0], e.xy[1]);
|
|
47836
|
+
}
|
|
47837
|
+
const groups = [];
|
|
47838
|
+
for (const e of projected) {
|
|
47839
|
+
if (connected.has(e.p.id)) continue;
|
|
47840
|
+
const r = radiusOf(e);
|
|
47841
|
+
const near = groups.find(
|
|
47842
|
+
(g) => g.some(
|
|
47843
|
+
(q) => Math.hypot(q.xy[0] - e.xy[0], q.xy[1] - e.xy[1]) < (r + radiusOf(q)) * STACK_OVERLAP
|
|
47844
|
+
)
|
|
47845
|
+
);
|
|
47846
|
+
if (near) near.push(e);
|
|
47847
|
+
else groups.push([e]);
|
|
47848
|
+
}
|
|
47849
|
+
for (const g of groups) {
|
|
47850
|
+
if (g.length === 1) {
|
|
47851
|
+
placePoi(g[0], g[0].xy[0], g[0].xy[1]);
|
|
47852
|
+
continue;
|
|
47853
|
+
}
|
|
47854
|
+
const clusterId = g[0].p.id;
|
|
47855
|
+
const cx0 = g.reduce((s, e) => s + e.xy[0], 0) / g.length;
|
|
47856
|
+
const cy0 = g.reduce((s, e) => s + e.xy[1], 0) / g.length;
|
|
47857
|
+
const maxR = Math.max(...g.map(radiusOf));
|
|
47858
|
+
const sep = 2 * maxR + STACK_RING_GAP;
|
|
47859
|
+
const ringR = Math.max(
|
|
47860
|
+
COLO_R,
|
|
47861
|
+
sep / (2 * Math.sin(Math.PI / Math.max(g.length, 2)))
|
|
47862
|
+
);
|
|
47863
|
+
const positions = g.map((e, i) => {
|
|
47864
|
+
if (g.length <= STACK_RING_MAX) {
|
|
47865
|
+
const ang2 = -Math.PI / 2 + i * 2 * Math.PI / g.length;
|
|
47866
|
+
return {
|
|
47867
|
+
e,
|
|
47868
|
+
mx: cx0 + Math.cos(ang2) * ringR,
|
|
47869
|
+
my: cy0 + Math.sin(ang2) * ringR
|
|
47870
|
+
};
|
|
47871
|
+
}
|
|
47872
|
+
const ang = i * GOLDEN_ANGLE;
|
|
47873
|
+
const rr = ringR * Math.sqrt((i + 1) / g.length);
|
|
47874
|
+
return { e, mx: cx0 + Math.cos(ang) * rr, my: cy0 + Math.sin(ang) * rr };
|
|
47875
|
+
});
|
|
47876
|
+
let minX = cx0 - maxR;
|
|
47877
|
+
let maxX = cx0 + maxR;
|
|
47878
|
+
let minY = cy0 - maxR;
|
|
47879
|
+
let maxY = cy0 + maxR;
|
|
47880
|
+
for (const { mx, my, e } of positions) {
|
|
47881
|
+
const r = radiusOf(e);
|
|
47882
|
+
minX = Math.min(minX, mx - r);
|
|
47883
|
+
maxX = Math.max(maxX, mx + r);
|
|
47884
|
+
minY = Math.min(minY, my - r);
|
|
47885
|
+
maxY = Math.max(maxY, my + r);
|
|
47886
|
+
}
|
|
47887
|
+
let dx = 0;
|
|
47888
|
+
let dy = 0;
|
|
47889
|
+
if (minX + dx < 2) dx = 2 - minX;
|
|
47890
|
+
if (maxX + dx > width - 2) dx = width - 2 - maxX;
|
|
47891
|
+
if (minY + dy < 2) dy = 2 - minY;
|
|
47892
|
+
if (maxY + dy > height - 2) dy = height - 2 - maxY;
|
|
47893
|
+
const legsOut = [];
|
|
47894
|
+
for (const { e, mx, my } of positions) {
|
|
47895
|
+
const fx = mx + dx;
|
|
47896
|
+
const fy = my + dy;
|
|
47897
|
+
placePoi(e, fx, fy, clusterId);
|
|
47898
|
+
legsOut.push({ x2: fx, y2: fy, color: poiFill(e.p).fill });
|
|
47899
|
+
}
|
|
47900
|
+
clusters.push({
|
|
47901
|
+
id: clusterId,
|
|
47902
|
+
cx: cx0 + dx,
|
|
47903
|
+
cy: cy0 + dy,
|
|
47904
|
+
count: g.length,
|
|
47905
|
+
hitR: ringR + maxR + 6,
|
|
47906
|
+
legs: legsOut
|
|
46804
47907
|
});
|
|
46805
47908
|
}
|
|
46806
47909
|
const legs = [];
|
|
@@ -46850,16 +47953,26 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46850
47953
|
if (!a || !b) continue;
|
|
46851
47954
|
const mx = (a.cx + b.cx) / 2;
|
|
46852
47955
|
const my = (a.cy + b.cy) / 2;
|
|
47956
|
+
const bow = {
|
|
47957
|
+
curved: leg.style === "arc",
|
|
47958
|
+
offset: 0,
|
|
47959
|
+
labelX: mx,
|
|
47960
|
+
labelY: my - 4
|
|
47961
|
+
};
|
|
47962
|
+
const routeLabelStyle = leg.label !== void 0 ? labelOnFill(fillAt(bow.labelX, bow.labelY)) : void 0;
|
|
46853
47963
|
legs.push({
|
|
46854
|
-
d: legPath(a, b,
|
|
47964
|
+
d: legPath(a, b, bow.curved, bow.offset),
|
|
46855
47965
|
width: routeWidthFor(Number(leg.value)),
|
|
46856
47966
|
color: mix(palette.text, palette.bg, 72),
|
|
46857
47967
|
arrow: true,
|
|
46858
47968
|
lineNumber: leg.lineNumber,
|
|
46859
47969
|
...leg.label !== void 0 && {
|
|
46860
47970
|
label: leg.label,
|
|
46861
|
-
labelX:
|
|
46862
|
-
labelY:
|
|
47971
|
+
labelX: bow.labelX,
|
|
47972
|
+
labelY: bow.labelY,
|
|
47973
|
+
labelColor: routeLabelStyle.color,
|
|
47974
|
+
labelHalo: routeLabelStyle.halo,
|
|
47975
|
+
labelHaloColor: routeLabelStyle.haloColor
|
|
46863
47976
|
}
|
|
46864
47977
|
});
|
|
46865
47978
|
}
|
|
@@ -46887,20 +48000,29 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46887
48000
|
const a = poiScreen.get(e.fromId);
|
|
46888
48001
|
const b = poiScreen.get(e.toId);
|
|
46889
48002
|
if (!a || !b) return;
|
|
46890
|
-
const
|
|
46891
|
-
const offset = n > 1 ? (i - (n - 1) / 2) * FAN_STEP : 0;
|
|
48003
|
+
const fanOffset = n > 1 ? (i - (n - 1) / 2) * FAN_STEP : 0;
|
|
46892
48004
|
const mx = (a.cx + b.cx) / 2;
|
|
46893
48005
|
const my = (a.cy + b.cy) / 2;
|
|
48006
|
+
const bow = {
|
|
48007
|
+
curved: e.style === "arc" || n > 1,
|
|
48008
|
+
offset: fanOffset,
|
|
48009
|
+
labelX: mx,
|
|
48010
|
+
labelY: my - 4
|
|
48011
|
+
};
|
|
48012
|
+
const edgeLabelStyle = e.label !== void 0 ? labelOnFill(fillAt(bow.labelX, bow.labelY)) : void 0;
|
|
46894
48013
|
legs.push({
|
|
46895
|
-
d: legPath(a, b, curved, offset),
|
|
48014
|
+
d: legPath(a, b, bow.curved, bow.offset),
|
|
46896
48015
|
width: widthFor(e),
|
|
46897
48016
|
color: mix(palette.text, palette.bg, 66),
|
|
46898
48017
|
arrow: e.directed,
|
|
46899
48018
|
lineNumber: e.lineNumber,
|
|
46900
48019
|
...e.label !== void 0 && {
|
|
46901
48020
|
label: e.label,
|
|
46902
|
-
labelX:
|
|
46903
|
-
labelY:
|
|
48021
|
+
labelX: bow.labelX,
|
|
48022
|
+
labelY: bow.labelY,
|
|
48023
|
+
labelColor: edgeLabelStyle.color,
|
|
48024
|
+
labelHalo: edgeLabelStyle.halo,
|
|
48025
|
+
labelHaloColor: edgeLabelStyle.haloColor
|
|
46904
48026
|
}
|
|
46905
48027
|
});
|
|
46906
48028
|
});
|
|
@@ -46942,25 +48064,25 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46942
48064
|
}
|
|
46943
48065
|
}
|
|
46944
48066
|
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));
|
|
46945
|
-
const
|
|
48067
|
+
const showRegionLabels = resolved.directives.noRegionLabels !== true;
|
|
48068
|
+
const isCompact = width < COMPACT_WIDTH_PX;
|
|
46946
48069
|
const LABEL_PADX = 6;
|
|
46947
48070
|
const LABEL_PADY = 3;
|
|
46948
|
-
const labelW = (text) => measureLegendText(text,
|
|
46949
|
-
const labelH =
|
|
48071
|
+
const labelW = (text) => measureLegendText(text, FONT2) + 2 * LABEL_PADX;
|
|
48072
|
+
const labelH = FONT2 + 2 * LABEL_PADY;
|
|
46950
48073
|
const pushRegionLabel = (x, y, text, fill2, lineNumber) => {
|
|
46951
|
-
const color =
|
|
46952
|
-
|
|
46953
|
-
|
|
46954
|
-
|
|
48074
|
+
const { color, haloColor } = labelOnFill(fill2);
|
|
48075
|
+
const halfW = measureLegendText(text, FONT2) / 2;
|
|
48076
|
+
const overflows = [y - FONT2 * 0.55, y - FONT2 * 0.1].some(
|
|
48077
|
+
(sy) => fillAt(x - halfW, sy) !== fill2 || fillAt(x + halfW, sy) !== fill2
|
|
46955
48078
|
);
|
|
46956
|
-
const haloColor = color === palette.textOnFillLight ? palette.textOnFillDark : palette.textOnFillLight;
|
|
46957
48079
|
labels.push({
|
|
46958
48080
|
x,
|
|
46959
48081
|
y,
|
|
46960
48082
|
text,
|
|
46961
48083
|
anchor: "middle",
|
|
46962
48084
|
color,
|
|
46963
|
-
halo:
|
|
48085
|
+
halo: overflows,
|
|
46964
48086
|
haloColor,
|
|
46965
48087
|
lineNumber
|
|
46966
48088
|
});
|
|
@@ -46969,21 +48091,50 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46969
48091
|
US: [-98.5, 39.5]
|
|
46970
48092
|
// CONUS geographic centre (near Lebanon, Kansas)
|
|
46971
48093
|
};
|
|
46972
|
-
|
|
46973
|
-
|
|
46974
|
-
|
|
46975
|
-
|
|
46976
|
-
|
|
48094
|
+
const REGION_LABEL_GAP = 2;
|
|
48095
|
+
const regionLabelRect = (cx, cy, text) => {
|
|
48096
|
+
const w = measureLegendText(text, FONT2) + 2 * REGION_LABEL_GAP;
|
|
48097
|
+
return { x: cx - w / 2, y: cy - FONT2 / 2, w, h: FONT2 };
|
|
48098
|
+
};
|
|
48099
|
+
if (showRegionLabels) {
|
|
48100
|
+
const frameContainers = new Set(resolved.poiFrameContainers);
|
|
48101
|
+
const entries = regions.map((r) => {
|
|
48102
|
+
const isContainer = frameContainers.has(r.id);
|
|
48103
|
+
if (r.layer === "base" && !isContainer || r.label === void 0)
|
|
48104
|
+
return null;
|
|
48105
|
+
const isUsState = r.layer === "us-state" || r.id.startsWith("US-");
|
|
48106
|
+
const f = isUsState ? usLayer?.get(r.id) : worldLayer.get(r.id);
|
|
48107
|
+
if (!f) return null;
|
|
46977
48108
|
const [[x0, y0], [x1, y1]] = path.bounds(f);
|
|
46978
|
-
const
|
|
46979
|
-
|
|
46980
|
-
const
|
|
48109
|
+
const boxW = x1 - x0;
|
|
48110
|
+
const boxH = y1 - y0;
|
|
48111
|
+
const abbrev = isUsState ? r.id.replace(/^US-/, "") : void 0;
|
|
48112
|
+
const candidates = abbrev !== void 0 ? isCompact ? [abbrev, r.label] : [r.label, abbrev] : [r.label];
|
|
48113
|
+
const anchor = !isUsState ? WORLD_LABEL_ANCHORS[r.id] : void 0;
|
|
46981
48114
|
const c = anchor ? project(anchor[0], anchor[1]) : path.centroid(f);
|
|
46982
|
-
if (!c || !Number.isFinite(c[0]))
|
|
48115
|
+
if (!c || !Number.isFinite(c[0])) return null;
|
|
48116
|
+
return { r, c, boxW, boxH, area: boxW * boxH, candidates };
|
|
48117
|
+
}).filter((e) => e !== null).sort((a, b) => b.area - a.area || a.r.lineNumber - b.r.lineNumber);
|
|
48118
|
+
const placedRegionRects = [];
|
|
48119
|
+
const POI_LABEL_PAD = 14;
|
|
48120
|
+
const poiObstacles = pois.map((p) => ({
|
|
48121
|
+
x: p.cx - p.r - POI_LABEL_PAD,
|
|
48122
|
+
y: p.cy - p.r - POI_LABEL_PAD,
|
|
48123
|
+
w: 2 * (p.r + POI_LABEL_PAD),
|
|
48124
|
+
h: 2 * (p.r + POI_LABEL_PAD)
|
|
48125
|
+
}));
|
|
48126
|
+
for (const { r, c, boxW, boxH, candidates } of entries) {
|
|
48127
|
+
const text = candidates.find((t) => {
|
|
48128
|
+
if (labelW(t) > boxW || labelH > boxH) return false;
|
|
48129
|
+
const rect = regionLabelRect(c[0], c[1], t);
|
|
48130
|
+
return !placedRegionRects.some((p) => rectsOverlap(rect, p)) && !poiObstacles.some((o) => rectsOverlap(rect, o));
|
|
48131
|
+
});
|
|
48132
|
+
if (text === void 0) continue;
|
|
48133
|
+
placedRegionRects.push(regionLabelRect(c[0], c[1], text));
|
|
46983
48134
|
pushRegionLabel(c[0], c[1], text, r.fill, r.lineNumber);
|
|
46984
48135
|
}
|
|
46985
48136
|
for (const seed of insetLabelSeeds) {
|
|
46986
|
-
const text =
|
|
48137
|
+
const text = isCompact ? seed.iso.replace(/^US-/, "") : seed.name;
|
|
46987
48138
|
const src = regionById.get(seed.iso);
|
|
46988
48139
|
pushRegionLabel(
|
|
46989
48140
|
seed.x,
|
|
@@ -46994,22 +48145,26 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46994
48145
|
);
|
|
46995
48146
|
}
|
|
46996
48147
|
}
|
|
46997
|
-
|
|
46998
|
-
|
|
46999
|
-
const ordered = [...pois].sort(
|
|
47000
|
-
(a, b) => a.lineNumber - b.lineNumber || (a.id < b.id ? -1 : 1)
|
|
47001
|
-
);
|
|
48148
|
+
if (resolved.directives.noPoiLabels !== true) {
|
|
48149
|
+
const ordered = [...pois].filter((p) => p.clusterId === void 0).sort((a, b) => a.lineNumber - b.lineNumber || (a.id < b.id ? -1 : 1));
|
|
47002
48150
|
const poiById = new Map(resolved.pois.map((q) => [q.id, q]));
|
|
47003
48151
|
const labelText = (p) => {
|
|
47004
48152
|
const src = poiById.get(p.id);
|
|
47005
48153
|
return src?.label ?? src?.name ?? p.id;
|
|
47006
48154
|
};
|
|
47007
|
-
const poiLabH =
|
|
48155
|
+
const poiLabH = FONT2 * 1.25;
|
|
47008
48156
|
const labelInfo = (p) => {
|
|
47009
48157
|
const text = labelText(p);
|
|
47010
|
-
return { text, w: measureLegendText(text,
|
|
48158
|
+
return { text, w: measureLegendText(text, FONT2) };
|
|
47011
48159
|
};
|
|
47012
48160
|
const GAP = 3;
|
|
48161
|
+
const clusterMembersById = /* @__PURE__ */ new Map();
|
|
48162
|
+
for (const p of pois) {
|
|
48163
|
+
if (p.clusterId === void 0) continue;
|
|
48164
|
+
const arr = clusterMembersById.get(p.clusterId);
|
|
48165
|
+
if (arr) arr.push(p);
|
|
48166
|
+
else clusterMembersById.set(p.clusterId, [p]);
|
|
48167
|
+
}
|
|
47013
48168
|
const inlineRect = (p, w, side) => {
|
|
47014
48169
|
switch (side) {
|
|
47015
48170
|
case "right":
|
|
@@ -47039,11 +48194,11 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47039
48194
|
const x = side === "right" ? rect.x : side === "left" ? rect.x + w : p.cx;
|
|
47040
48195
|
labels.push({
|
|
47041
48196
|
x,
|
|
47042
|
-
y: rect.y + poiLabH / 2 +
|
|
48197
|
+
y: rect.y + poiLabH / 2 + FONT2 / 3,
|
|
47043
48198
|
text,
|
|
47044
48199
|
anchor,
|
|
47045
48200
|
color: palette.text,
|
|
47046
|
-
halo:
|
|
48201
|
+
halo: false,
|
|
47047
48202
|
haloColor: palette.bg,
|
|
47048
48203
|
poiId: p.id,
|
|
47049
48204
|
lineNumber: p.lineNumber
|
|
@@ -47054,43 +48209,60 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47054
48209
|
return rect.x >= 0 && rect.x + rect.w <= width && rect.y >= 0 && rect.y + rect.h <= height && !collides(rect);
|
|
47055
48210
|
};
|
|
47056
48211
|
const GROUP_R = 30;
|
|
47057
|
-
const
|
|
48212
|
+
const groups2 = [];
|
|
47058
48213
|
for (const p of ordered) {
|
|
47059
|
-
const near =
|
|
48214
|
+
const near = groups2.find(
|
|
47060
48215
|
(g) => g.some((q) => Math.hypot(q.cx - p.cx, q.cy - p.cy) < GROUP_R)
|
|
47061
48216
|
);
|
|
47062
48217
|
if (near) near.push(p);
|
|
47063
|
-
else
|
|
48218
|
+
else groups2.push([p]);
|
|
47064
48219
|
}
|
|
47065
48220
|
const ROW_GAP2 = 3;
|
|
47066
48221
|
const step = poiLabH + ROW_GAP2;
|
|
47067
48222
|
const COL_GAP = 16;
|
|
47068
|
-
const
|
|
47069
|
-
|
|
48223
|
+
const makeItems = (group) => group.map((p) => ({ p, ...labelInfo(p) })).sort((a, b) => a.p.cy - b.p.cy || (a.text < b.text ? -1 : 1));
|
|
48224
|
+
const columnRows = (items, side) => {
|
|
47070
48225
|
const left = Math.min(...items.map((o) => o.p.cx - o.p.r));
|
|
47071
48226
|
const right = Math.max(...items.map((o) => o.p.cx + o.p.r));
|
|
47072
|
-
const cyMid = (Math.min(...items.map((o) => o.p.cy)) + Math.max(...items.map((o) => o.p.cy))) / 2;
|
|
47073
48227
|
const maxW = Math.max(...items.map((o) => o.w));
|
|
47074
|
-
const
|
|
47075
|
-
const colX = side === "right" ? right + COL_GAP : left - COL_GAP;
|
|
48228
|
+
const cyMid = (Math.min(...items.map((o) => o.p.cy)) + Math.max(...items.map((o) => o.p.cy))) / 2;
|
|
48229
|
+
const colX = side === "right" ? Math.min(right + COL_GAP, width - 2 - maxW) : Math.max(left - COL_GAP, 2 + maxW);
|
|
47076
48230
|
const totalH = items.length * step;
|
|
47077
48231
|
let startY = cyMid - totalH / 2;
|
|
47078
48232
|
startY = Math.max(2, Math.min(startY, height - totalH - 2));
|
|
47079
|
-
items.
|
|
48233
|
+
return items.map((o, i) => {
|
|
47080
48234
|
const rowCy = startY + i * step + step / 2;
|
|
47081
|
-
|
|
47082
|
-
|
|
47083
|
-
|
|
47084
|
-
|
|
47085
|
-
|
|
47086
|
-
|
|
48235
|
+
return {
|
|
48236
|
+
o,
|
|
48237
|
+
colX,
|
|
48238
|
+
rowCy,
|
|
48239
|
+
rect: {
|
|
48240
|
+
x: side === "right" ? colX : colX - o.w,
|
|
48241
|
+
y: rowCy - poiLabH / 2,
|
|
48242
|
+
w: o.w,
|
|
48243
|
+
h: poiLabH
|
|
48244
|
+
}
|
|
48245
|
+
};
|
|
48246
|
+
});
|
|
48247
|
+
};
|
|
48248
|
+
const wouldColumnBeClean = (items, side) => columnRows(items, side).every(
|
|
48249
|
+
({ rect }) => rect.x >= 0 && rect.x + rect.w <= width && rect.y >= 0 && rect.y + rect.h <= height && !collides(rect)
|
|
48250
|
+
);
|
|
48251
|
+
const defaultColumnSide = (items) => {
|
|
48252
|
+
const right = Math.max(...items.map((o) => o.p.cx + o.p.r));
|
|
48253
|
+
const maxW = Math.max(...items.map((o) => o.w));
|
|
48254
|
+
return right + COL_GAP + maxW <= width - 2 ? "right" : "left";
|
|
48255
|
+
};
|
|
48256
|
+
const commitColumn = (items, side, clusterId) => {
|
|
48257
|
+
for (const { o, colX, rowCy, rect } of columnRows(items, side)) {
|
|
48258
|
+
obstacles.push(rect);
|
|
47087
48259
|
labels.push({
|
|
47088
48260
|
x: colX,
|
|
47089
|
-
y: rowCy +
|
|
48261
|
+
y: rowCy + FONT2 / 3,
|
|
47090
48262
|
text: o.text,
|
|
47091
48263
|
anchor: side === "right" ? "start" : "end",
|
|
47092
48264
|
color: palette.text,
|
|
47093
|
-
halo:
|
|
48265
|
+
halo: false,
|
|
47094
48266
|
haloColor: palette.bg,
|
|
47095
48267
|
leader: {
|
|
47096
48268
|
x1: o.p.cx,
|
|
@@ -47100,24 +48272,141 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47100
48272
|
},
|
|
47101
48273
|
leaderColor: o.p.fill,
|
|
47102
48274
|
poiId: o.p.id,
|
|
47103
|
-
lineNumber: o.p.lineNumber
|
|
48275
|
+
lineNumber: o.p.lineNumber,
|
|
48276
|
+
...clusterId !== void 0 && { clusterMember: clusterId }
|
|
47104
48277
|
});
|
|
48278
|
+
}
|
|
48279
|
+
};
|
|
48280
|
+
const pushHidden = (p) => {
|
|
48281
|
+
const { text, w } = labelInfo(p);
|
|
48282
|
+
let x = p.cx + p.r + GAP;
|
|
48283
|
+
let anchor = "start";
|
|
48284
|
+
if (x + w > width) {
|
|
48285
|
+
x = p.cx - p.r - GAP - w;
|
|
48286
|
+
anchor = "end";
|
|
48287
|
+
}
|
|
48288
|
+
const y = Math.max(0, Math.min(p.cy - poiLabH / 2, height - poiLabH));
|
|
48289
|
+
labels.push({
|
|
48290
|
+
x: anchor === "start" ? x : x + w,
|
|
48291
|
+
y: y + poiLabH / 2 + FONT2 / 3,
|
|
48292
|
+
text,
|
|
48293
|
+
anchor,
|
|
48294
|
+
color: palette.text,
|
|
48295
|
+
halo: false,
|
|
48296
|
+
haloColor: palette.bg,
|
|
48297
|
+
poiId: p.id,
|
|
48298
|
+
hidden: true,
|
|
48299
|
+
lineNumber: p.lineNumber
|
|
47105
48300
|
});
|
|
47106
48301
|
};
|
|
47107
|
-
for (const
|
|
48302
|
+
for (const [clusterId, members] of clusterMembersById) {
|
|
48303
|
+
if (members.length === 0) continue;
|
|
48304
|
+
const items = makeItems(members);
|
|
48305
|
+
const side = wouldColumnBeClean(items, "right") ? "right" : wouldColumnBeClean(items, "left") ? "left" : defaultColumnSide(items);
|
|
48306
|
+
commitColumn(items, side, clusterId);
|
|
48307
|
+
}
|
|
48308
|
+
const maxExtent = MAX_CLUSTER_EXTENT_FACTOR * Math.min(width, height);
|
|
48309
|
+
const clusterPending = [];
|
|
48310
|
+
for (const g of groups2) {
|
|
48311
|
+
const items = makeItems(g);
|
|
47108
48312
|
if (g.length === 1) {
|
|
47109
|
-
const p =
|
|
47110
|
-
const { text, w } = labelInfo(p);
|
|
48313
|
+
const { p, text, w } = items[0];
|
|
47111
48314
|
const side = ["right", "left", "above", "below"].find(
|
|
47112
48315
|
(s) => inlineFits(p, w, s)
|
|
47113
48316
|
);
|
|
47114
|
-
if (side)
|
|
47115
|
-
|
|
47116
|
-
|
|
48317
|
+
if (side) pushInline(p, text, w, side);
|
|
48318
|
+
else commitColumn(items, defaultColumnSide(items));
|
|
48319
|
+
continue;
|
|
48320
|
+
}
|
|
48321
|
+
const left = Math.min(...items.map((o) => o.p.cx - o.p.r));
|
|
48322
|
+
const right = Math.max(...items.map((o) => o.p.cx + o.p.r));
|
|
48323
|
+
const minCy = Math.min(...items.map((o) => o.p.cy));
|
|
48324
|
+
const maxCy = Math.max(...items.map((o) => o.p.cy));
|
|
48325
|
+
const diag = Math.hypot(right - left, maxCy - minCy);
|
|
48326
|
+
if (diag > maxExtent || items.length > MAX_COLUMN_ROWS) {
|
|
48327
|
+
items.forEach((o) => pushHidden(o.p));
|
|
48328
|
+
} else {
|
|
48329
|
+
clusterPending.push(items);
|
|
48330
|
+
}
|
|
48331
|
+
}
|
|
48332
|
+
for (const items of clusterPending) {
|
|
48333
|
+
const side = ["right", "left"].find(
|
|
48334
|
+
(s) => wouldColumnBeClean(items, s)
|
|
48335
|
+
);
|
|
48336
|
+
if (side) commitColumn(items, side);
|
|
48337
|
+
else items.forEach((o) => pushHidden(o.p));
|
|
48338
|
+
}
|
|
48339
|
+
}
|
|
48340
|
+
if (resolved.directives.noContextLabels !== true) {
|
|
48341
|
+
for (const l of labels) {
|
|
48342
|
+
if (l.hidden) continue;
|
|
48343
|
+
const w = labelW(l.text);
|
|
48344
|
+
const x = l.anchor === "start" ? l.x : l.anchor === "end" ? l.x - w : l.x - w / 2;
|
|
48345
|
+
obstacles.push({ x, y: l.y - labelH / 2, w, h: labelH });
|
|
48346
|
+
}
|
|
48347
|
+
for (const box of insets)
|
|
48348
|
+
obstacles.push({ x: box.x, y: box.y, w: box.w, h: box.h });
|
|
48349
|
+
const countryCandidates = [];
|
|
48350
|
+
for (const f of worldLayer.values()) {
|
|
48351
|
+
const iso = typeof f.id === "string" ? f.id : String(f.id ?? "");
|
|
48352
|
+
if (!iso || regionById.has(iso)) continue;
|
|
48353
|
+
let hasReferencedSub = false;
|
|
48354
|
+
for (const k of regionById.keys())
|
|
48355
|
+
if (k.startsWith(iso + "-")) {
|
|
48356
|
+
hasReferencedSub = true;
|
|
48357
|
+
break;
|
|
47117
48358
|
}
|
|
48359
|
+
if (hasReferencedSub) continue;
|
|
48360
|
+
const b = path.bounds(f);
|
|
48361
|
+
const [x0, y0] = b[0];
|
|
48362
|
+
const [x1, y1] = b[1];
|
|
48363
|
+
if (!Number.isFinite(x0) || !Number.isFinite(x1)) continue;
|
|
48364
|
+
const anchorLngLat = WORLD_LABEL_ANCHORS[iso];
|
|
48365
|
+
const a = anchorLngLat ? project(anchorLngLat[0], anchorLngLat[1]) : path.centroid(f);
|
|
48366
|
+
countryCandidates.push({
|
|
48367
|
+
name: f.properties?.name ?? iso,
|
|
48368
|
+
bbox: [x0, y0, x1, y1],
|
|
48369
|
+
anchor: a && Number.isFinite(a[0]) ? [a[0], a[1]] : null
|
|
48370
|
+
});
|
|
48371
|
+
}
|
|
48372
|
+
const framedStateContainers = (resolved.poiFrameContainers ?? []).some(
|
|
48373
|
+
(id) => id.startsWith("US-")
|
|
48374
|
+
);
|
|
48375
|
+
if (usLayer && framedStateContainers) {
|
|
48376
|
+
const containerSet = new Set(resolved.poiFrameContainers);
|
|
48377
|
+
for (const [iso, f] of usLayer) {
|
|
48378
|
+
if (containerSet.has(iso) || regionById.has(iso)) continue;
|
|
48379
|
+
const viewF = cullFeatureToView(f);
|
|
48380
|
+
if (!viewF) continue;
|
|
48381
|
+
const b = path.bounds(viewF);
|
|
48382
|
+
const [x0, y0] = b[0];
|
|
48383
|
+
const [x1, y1] = b[1];
|
|
48384
|
+
if (!Number.isFinite(x0) || !Number.isFinite(x1)) continue;
|
|
48385
|
+
const a = path.centroid(viewF);
|
|
48386
|
+
countryCandidates.push({
|
|
48387
|
+
name: f.properties?.name ?? iso,
|
|
48388
|
+
bbox: [x0, y0, x1, y1],
|
|
48389
|
+
anchor: a && Number.isFinite(a[0]) ? [a[0], a[1]] : null
|
|
48390
|
+
});
|
|
47118
48391
|
}
|
|
47119
|
-
placeColumn(g);
|
|
47120
48392
|
}
|
|
48393
|
+
const contextLabels = placeContextLabels({
|
|
48394
|
+
projection: resolved.projection,
|
|
48395
|
+
dLonSpan,
|
|
48396
|
+
dLatSpan,
|
|
48397
|
+
width,
|
|
48398
|
+
height,
|
|
48399
|
+
waterBodies: data.waterBodies,
|
|
48400
|
+
countries: countryCandidates,
|
|
48401
|
+
palette,
|
|
48402
|
+
project,
|
|
48403
|
+
collides,
|
|
48404
|
+
// Water labels must stay over open water — `fillAt` returns the ocean
|
|
48405
|
+
// backdrop colour off-land and a region fill on-land (lakes/states count
|
|
48406
|
+
// as land here, which is the safe side for an ocean name).
|
|
48407
|
+
overLand: (x, y) => fillAt(x, y) !== water
|
|
48408
|
+
});
|
|
48409
|
+
labels.push(...contextLabels);
|
|
47121
48410
|
}
|
|
47122
48411
|
let legend = null;
|
|
47123
48412
|
if (!resolved.directives.noLegend) {
|
|
@@ -47154,27 +48443,33 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47154
48443
|
rivers,
|
|
47155
48444
|
relief,
|
|
47156
48445
|
reliefHatch,
|
|
48446
|
+
coastlineStyle,
|
|
47157
48447
|
legs,
|
|
47158
48448
|
pois,
|
|
48449
|
+
clusters,
|
|
47159
48450
|
labels,
|
|
47160
48451
|
legend,
|
|
47161
48452
|
insets,
|
|
47162
48453
|
insetRegions,
|
|
47163
48454
|
projection,
|
|
47164
|
-
stretch: stretchParams
|
|
48455
|
+
stretch: stretchParams,
|
|
48456
|
+
diagnostics: []
|
|
47165
48457
|
};
|
|
47166
48458
|
}
|
|
47167
|
-
var import_d3_geo2, import_topojson_client2, FIT_PAD, RAMP_FLOOR, R_DEFAULT, R_MIN, R_MAX, W_MIN, W_MAX,
|
|
48459
|
+
var import_d3_geo2, import_topojson_client2, 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;
|
|
47168
48460
|
var init_layout15 = __esm({
|
|
47169
48461
|
"src/map/layout.ts"() {
|
|
47170
48462
|
"use strict";
|
|
47171
48463
|
import_d3_geo2 = require("d3-geo");
|
|
47172
48464
|
import_topojson_client2 = require("topojson-client");
|
|
47173
48465
|
init_color_utils();
|
|
48466
|
+
init_geo();
|
|
48467
|
+
init_colorize();
|
|
47174
48468
|
init_colors();
|
|
47175
48469
|
init_label_layout();
|
|
47176
48470
|
init_legend_constants();
|
|
47177
48471
|
init_title_constants();
|
|
48472
|
+
init_context_labels();
|
|
47178
48473
|
FIT_PAD = 24;
|
|
47179
48474
|
RAMP_FLOOR = 15;
|
|
47180
48475
|
R_DEFAULT = 6;
|
|
@@ -47182,32 +48477,66 @@ var init_layout15 = __esm({
|
|
|
47182
48477
|
R_MAX = 22;
|
|
47183
48478
|
W_MIN = 1.25;
|
|
47184
48479
|
W_MAX = 8;
|
|
47185
|
-
|
|
47186
|
-
|
|
48480
|
+
FONT2 = 11;
|
|
48481
|
+
MAX_CLUSTER_EXTENT_FACTOR = 0.18;
|
|
48482
|
+
MAX_COLUMN_ROWS = 7;
|
|
48483
|
+
REGION_LABEL_HALO_RATIO = 4.5;
|
|
47187
48484
|
LAND_TINT_LIGHT = 12;
|
|
47188
48485
|
LAND_TINT_DARK = 24;
|
|
47189
48486
|
TAG_TINT_LIGHT = 60;
|
|
47190
48487
|
TAG_TINT_DARK = 68;
|
|
47191
|
-
WATER_TINT_LIGHT =
|
|
47192
|
-
WATER_TINT_DARK =
|
|
48488
|
+
WATER_TINT_LIGHT = 24;
|
|
48489
|
+
WATER_TINT_DARK = 24;
|
|
47193
48490
|
RIVER_WIDTH = 1.3;
|
|
48491
|
+
COMPACT_WIDTH_PX = 480;
|
|
47194
48492
|
RELIEF_MIN_AREA = 12;
|
|
47195
48493
|
RELIEF_MIN_DIM = 2;
|
|
47196
|
-
RELIEF_HATCH_SPACING =
|
|
47197
|
-
RELIEF_HATCH_WIDTH = 0.
|
|
48494
|
+
RELIEF_HATCH_SPACING = 2;
|
|
48495
|
+
RELIEF_HATCH_WIDTH = 0.15;
|
|
47198
48496
|
RELIEF_HATCH_STRENGTH = 32;
|
|
48497
|
+
COASTLINE_RING_COUNT = 5;
|
|
48498
|
+
COASTLINE_D0 = 16e-4;
|
|
48499
|
+
COASTLINE_STEP = 28e-4;
|
|
48500
|
+
COASTLINE_THICKNESS = 14e-4;
|
|
48501
|
+
COASTLINE_OPACITY_NEAR = 0.5;
|
|
48502
|
+
COASTLINE_OPACITY_FAR = 0.1;
|
|
48503
|
+
COASTLINE_MIN_EXTENT = 6e-4;
|
|
48504
|
+
COASTLINE_MIN_EXTENT_GLOBAL = 6e-4;
|
|
48505
|
+
COASTLINE_STROKE_MIX = 32;
|
|
47199
48506
|
FOREIGN_TINT_LIGHT = 30;
|
|
47200
48507
|
FOREIGN_TINT_DARK = 62;
|
|
47201
48508
|
MUTED_FOREIGN_LIGHT = 28;
|
|
47202
48509
|
MUTED_FOREIGN_DARK = 16;
|
|
47203
48510
|
COLO_R = 9;
|
|
47204
48511
|
GOLDEN_ANGLE = 2.399963229728653;
|
|
48512
|
+
STACK_OVERLAP = 1;
|
|
48513
|
+
STACK_RING_MAX = 8;
|
|
48514
|
+
STACK_RING_GAP = 4;
|
|
47205
48515
|
FAN_STEP = 16;
|
|
47206
48516
|
ARC_CURVE_FRAC = 0.18;
|
|
48517
|
+
decodeCache = /* @__PURE__ */ new WeakMap();
|
|
47207
48518
|
usConusProjection = () => (0, import_d3_geo2.geoConicEqualArea)().parallels([29.5, 45.5]).rotate([96, 0]);
|
|
47208
48519
|
alaskaProjection = () => (0, import_d3_geo2.geoConicEqualArea)().rotate([154, 0]).center([-2, 58.5]).parallels([55, 65]);
|
|
47209
48520
|
hawaiiProjection = () => (0, import_d3_geo2.geoMercator)();
|
|
47210
48521
|
INSET_STATES = /* @__PURE__ */ new Set(["US-AK", "US-HI"]);
|
|
48522
|
+
inAlaska = (lon, lat) => lat >= 51 && (lon <= -129 || lon >= 172);
|
|
48523
|
+
inHawaii = (lon, lat) => lat >= 18 && lat <= 23 && lon >= -161 && lon <= -154;
|
|
48524
|
+
FOREIGN_BORDER = {
|
|
48525
|
+
CA: [
|
|
48526
|
+
"US-AK",
|
|
48527
|
+
"US-WA",
|
|
48528
|
+
"US-ID",
|
|
48529
|
+
"US-MT",
|
|
48530
|
+
"US-ND",
|
|
48531
|
+
"US-MN",
|
|
48532
|
+
"US-MI",
|
|
48533
|
+
"US-NY",
|
|
48534
|
+
"US-VT",
|
|
48535
|
+
"US-NH",
|
|
48536
|
+
"US-ME"
|
|
48537
|
+
],
|
|
48538
|
+
MX: ["US-CA", "US-AZ", "US-NM", "US-TX"]
|
|
48539
|
+
};
|
|
47211
48540
|
US_NON_CONUS = /* @__PURE__ */ new Set([
|
|
47212
48541
|
"US-AK",
|
|
47213
48542
|
"US-HI",
|
|
@@ -47226,6 +48555,58 @@ __export(renderer_exports16, {
|
|
|
47226
48555
|
renderMap: () => renderMap,
|
|
47227
48556
|
renderMapForExport: () => renderMapForExport
|
|
47228
48557
|
});
|
|
48558
|
+
function pointInRing2(px, py, ring) {
|
|
48559
|
+
let inside = false;
|
|
48560
|
+
for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
|
|
48561
|
+
const [xi, yi] = ring[i];
|
|
48562
|
+
const [xj, yj] = ring[j];
|
|
48563
|
+
if (yi > py !== yj > py && px < (xj - xi) * (py - yi) / (yj - yi) + xi)
|
|
48564
|
+
inside = !inside;
|
|
48565
|
+
}
|
|
48566
|
+
return inside;
|
|
48567
|
+
}
|
|
48568
|
+
function ringToPath(ring) {
|
|
48569
|
+
let d = "";
|
|
48570
|
+
for (let i = 0; i < ring.length; i++)
|
|
48571
|
+
d += (i ? "L" : "M") + ring[i][0] + "," + ring[i][1];
|
|
48572
|
+
return d + "Z";
|
|
48573
|
+
}
|
|
48574
|
+
function coastlineOuterRings(regions, minExtent) {
|
|
48575
|
+
const paths = [];
|
|
48576
|
+
for (const r of regions) {
|
|
48577
|
+
const rings = parsePathRings(r.d);
|
|
48578
|
+
for (let i = 0; i < rings.length; i++) {
|
|
48579
|
+
const ring = rings[i];
|
|
48580
|
+
if (ring.length < 3) continue;
|
|
48581
|
+
let minX = Infinity;
|
|
48582
|
+
let minY = Infinity;
|
|
48583
|
+
let maxX = -Infinity;
|
|
48584
|
+
let maxY = -Infinity;
|
|
48585
|
+
for (const [x, y] of ring) {
|
|
48586
|
+
if (x < minX) minX = x;
|
|
48587
|
+
if (x > maxX) maxX = x;
|
|
48588
|
+
if (y < minY) minY = y;
|
|
48589
|
+
if (y > maxY) maxY = y;
|
|
48590
|
+
}
|
|
48591
|
+
if (Math.max(maxX - minX, maxY - minY) < minExtent) continue;
|
|
48592
|
+
const [fx, fy] = ring[0];
|
|
48593
|
+
let depth = 0;
|
|
48594
|
+
for (let j = 0; j < rings.length; j++)
|
|
48595
|
+
if (j !== i && pointInRing2(fx, fy, rings[j])) depth++;
|
|
48596
|
+
if (depth % 2 === 1) continue;
|
|
48597
|
+
paths.push(ringToPath(ring));
|
|
48598
|
+
}
|
|
48599
|
+
}
|
|
48600
|
+
return paths;
|
|
48601
|
+
}
|
|
48602
|
+
function appendWaterLines(g, outerRings, style, flatWater) {
|
|
48603
|
+
const d = outerRings.join(" ");
|
|
48604
|
+
const linesOuterFirst = [...style.lines].sort((a, b) => b.d - a.d);
|
|
48605
|
+
for (const line12 of linesOuterFirst) {
|
|
48606
|
+
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");
|
|
48607
|
+
g.append("path").attr("d", d).attr("stroke", flatWater).attr("stroke-width", 2 * line12.d).attr("stroke-linejoin", "round").attr("stroke-linecap", "round");
|
|
48608
|
+
}
|
|
48609
|
+
}
|
|
47229
48610
|
function renderMap(container, resolved, data, palette, isDark, onClickItem, exportDims, activeGroupOverride) {
|
|
47230
48611
|
d3Selection18.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
47231
48612
|
const width = exportDims?.width ?? container.clientWidth;
|
|
@@ -47238,6 +48619,11 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47238
48619
|
{
|
|
47239
48620
|
palette,
|
|
47240
48621
|
isDark,
|
|
48622
|
+
// Export-only: forward the contain-fit request from mapExportDimensions so a
|
|
48623
|
+
// clamped/floored (off-aspect) export canvas letterboxes instead of
|
|
48624
|
+
// stretch-distorting. The in-app preview pane passes no exportDims → unset →
|
|
48625
|
+
// keeps the global stretch-fill.
|
|
48626
|
+
preferContain: exportDims?.preferContain ?? false,
|
|
47241
48627
|
...activeGroupOverride !== void 0 && {
|
|
47242
48628
|
activeGroup: activeGroupOverride
|
|
47243
48629
|
}
|
|
@@ -47251,6 +48637,7 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47251
48637
|
const gRegions = svg.append("g").attr("class", "dgmo-map-regions");
|
|
47252
48638
|
const drawRegion = (g, r, strokeWidth) => {
|
|
47253
48639
|
const p = g.append("path").attr("d", r.d).attr("fill", r.fill).attr("stroke", r.stroke).attr("stroke-width", strokeWidth);
|
|
48640
|
+
if (r.label) p.attr("data-region-name", r.label);
|
|
47254
48641
|
if (r.layer !== "base") {
|
|
47255
48642
|
p.classed("dgmo-map-region", true).attr("data-region", r.id);
|
|
47256
48643
|
if (r.value !== void 0) p.attr("data-value", r.value);
|
|
@@ -47285,6 +48672,38 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47285
48672
|
gRelief.append("line").attr("x1", 0).attr("y1", y).attr("x2", width).attr("y2", y);
|
|
47286
48673
|
}
|
|
47287
48674
|
}
|
|
48675
|
+
if (layout.coastlineStyle) {
|
|
48676
|
+
const cs = layout.coastlineStyle;
|
|
48677
|
+
const maskId = "dgmo-map-water-mask";
|
|
48678
|
+
const mask = defs.append("mask").attr("id", maskId).attr("maskUnits", "userSpaceOnUse").attr("x", 0).attr("y", 0).attr("width", width).attr("height", height);
|
|
48679
|
+
mask.append("rect").attr("x", 0).attr("y", 0).attr("width", width).attr("height", height).attr("fill", "white");
|
|
48680
|
+
const landD = layout.regions.filter((r) => r.id !== "lake").map((r) => r.d).join(" ");
|
|
48681
|
+
const lakeD = layout.regions.filter((r) => r.id === "lake").map((r) => r.d).join(" ");
|
|
48682
|
+
if (landD) mask.append("path").attr("d", landD).attr("fill", "black");
|
|
48683
|
+
if (lakeD) mask.append("path").attr("d", lakeD).attr("fill", "white");
|
|
48684
|
+
if (layout.insets.length) {
|
|
48685
|
+
const reach = Math.max(0, ...cs.lines.map((l) => l.d + l.thickness));
|
|
48686
|
+
for (const box of layout.insets) {
|
|
48687
|
+
const d = box.points.map((p, i) => `${i ? "L" : "M"}${p[0]},${p[1]}`).join("") + "Z";
|
|
48688
|
+
mask.append("path").attr("d", d).attr("fill", "black").attr("stroke", "black").attr("stroke-width", 2 * reach).attr("stroke-linejoin", "round");
|
|
48689
|
+
}
|
|
48690
|
+
}
|
|
48691
|
+
const gWater = svg.append("g").attr("class", "dgmo-map-water-lines").attr("fill", "none").attr("mask", `url(#${maskId})`);
|
|
48692
|
+
appendWaterLines(
|
|
48693
|
+
gWater,
|
|
48694
|
+
coastlineOuterRings(layout.regions, cs.minExtent),
|
|
48695
|
+
cs,
|
|
48696
|
+
layout.background
|
|
48697
|
+
);
|
|
48698
|
+
const byStroke = /* @__PURE__ */ new Map();
|
|
48699
|
+
for (const r of layout.regions) {
|
|
48700
|
+
const arr = byStroke.get(r.stroke);
|
|
48701
|
+
if (arr) arr.push(r.d);
|
|
48702
|
+
else byStroke.set(r.stroke, [r.d]);
|
|
48703
|
+
}
|
|
48704
|
+
for (const [stroke2, ds] of byStroke)
|
|
48705
|
+
gWater.append("path").attr("d", ds.join(" ")).attr("stroke", stroke2).attr("stroke-width", 0.5).attr("stroke-linejoin", "round");
|
|
48706
|
+
}
|
|
47288
48707
|
if (layout.rivers.length) {
|
|
47289
48708
|
const gRivers = svg.append("g").attr("class", "dgmo-map-rivers").attr("fill", "none");
|
|
47290
48709
|
for (const r of layout.rivers) {
|
|
@@ -47293,15 +48712,61 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47293
48712
|
}
|
|
47294
48713
|
if (layout.insets.length) {
|
|
47295
48714
|
const insetG = svg.append("g").attr("class", "dgmo-map-insets");
|
|
47296
|
-
|
|
48715
|
+
layout.insets.forEach((box, bi) => {
|
|
47297
48716
|
const d = box.points.map((p, i) => `${i ? "L" : "M"}${p[0]},${p[1]}`).join("") + "Z";
|
|
47298
48717
|
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");
|
|
47299
|
-
|
|
48718
|
+
if (box.contextLand) {
|
|
48719
|
+
const clipId = `dgmo-map-inset-clip-${bi}`;
|
|
48720
|
+
defs.append("clipPath").attr("id", clipId).append("path").attr("d", d);
|
|
48721
|
+
insetG.append("path").attr("d", box.contextLand.d).attr("fill", box.contextLand.fill).attr("clip-path", `url(#${clipId})`);
|
|
48722
|
+
}
|
|
48723
|
+
});
|
|
47300
48724
|
for (const r of layout.insetRegions) drawRegion(insetG, r, 0.5);
|
|
47301
|
-
|
|
48725
|
+
if (layout.coastlineStyle) {
|
|
48726
|
+
const cs = layout.coastlineStyle;
|
|
48727
|
+
const maskId = "dgmo-map-inset-water-mask";
|
|
48728
|
+
const mask = defs.append("mask").attr("id", maskId).attr("maskUnits", "userSpaceOnUse").attr("x", 0).attr("y", 0).attr("width", width).attr("height", height);
|
|
48729
|
+
for (const box of layout.insets) {
|
|
48730
|
+
const d = box.points.map((p, i) => `${i ? "L" : "M"}${p[0]},${p[1]}`).join("") + "Z";
|
|
48731
|
+
mask.append("path").attr("d", d).attr("fill", "white");
|
|
48732
|
+
}
|
|
48733
|
+
layout.insets.forEach((box, bi) => {
|
|
48734
|
+
if (box.contextLand)
|
|
48735
|
+
mask.append("path").attr("d", box.contextLand.d).attr("fill", "black").attr("clip-path", `url(#dgmo-map-inset-clip-${bi})`);
|
|
48736
|
+
});
|
|
48737
|
+
for (const r of layout.insetRegions)
|
|
48738
|
+
if (r.id !== "lake")
|
|
48739
|
+
mask.append("path").attr("d", r.d).attr("fill", "black");
|
|
48740
|
+
for (const r of layout.insetRegions)
|
|
48741
|
+
if (r.id === "lake")
|
|
48742
|
+
mask.append("path").attr("d", r.d).attr("fill", "white");
|
|
48743
|
+
const clipId = "dgmo-map-inset-water-clip";
|
|
48744
|
+
const clip = defs.append("clipPath").attr("id", clipId);
|
|
48745
|
+
for (const box of layout.insets) {
|
|
48746
|
+
const d = box.points.map((p, i) => `${i ? "L" : "M"}${p[0]},${p[1]}`).join("") + "Z";
|
|
48747
|
+
clip.append("path").attr("d", d);
|
|
48748
|
+
}
|
|
48749
|
+
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})`);
|
|
48750
|
+
appendWaterLines(
|
|
48751
|
+
gInsetWater,
|
|
48752
|
+
coastlineOuterRings(layout.insetRegions, cs.minExtent),
|
|
48753
|
+
cs,
|
|
48754
|
+
layout.background
|
|
48755
|
+
);
|
|
48756
|
+
for (const r of layout.insetRegions)
|
|
48757
|
+
gInsetWater.append("path").attr("d", r.d).attr("stroke", r.stroke).attr("stroke-width", 0.5).attr("stroke-linejoin", "round");
|
|
48758
|
+
}
|
|
48759
|
+
}
|
|
48760
|
+
const wireSync = (sel, lineNumber) => {
|
|
48761
|
+
if (lineNumber < 1) return;
|
|
48762
|
+
sel.attr("data-line-number", lineNumber);
|
|
48763
|
+
if (onClickItem)
|
|
48764
|
+
sel.style("cursor", "pointer").on("click", () => onClickItem(lineNumber));
|
|
48765
|
+
};
|
|
47302
48766
|
const gLegs = svg.append("g").attr("class", "dgmo-map-legs").attr("fill", "none");
|
|
47303
48767
|
layout.legs.forEach((leg, i) => {
|
|
47304
48768
|
const p = gLegs.append("path").attr("d", leg.d).attr("stroke", leg.color).attr("stroke-width", leg.width).attr("stroke-linecap", "round");
|
|
48769
|
+
wireSync(p, leg.lineNumber);
|
|
47305
48770
|
if (leg.arrow) {
|
|
47306
48771
|
const id = `dgmo-map-arrow-${i}`;
|
|
47307
48772
|
const s = arrowSize(leg.width);
|
|
@@ -47309,25 +48774,38 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47309
48774
|
p.attr("marker-end", `url(#${id})`);
|
|
47310
48775
|
}
|
|
47311
48776
|
if (leg.label !== void 0 && leg.labelX !== void 0) {
|
|
47312
|
-
emitText(
|
|
48777
|
+
const lt = emitText(
|
|
47313
48778
|
gLegs,
|
|
47314
48779
|
leg.labelX,
|
|
47315
48780
|
leg.labelY ?? 0,
|
|
47316
48781
|
leg.label,
|
|
47317
48782
|
"middle",
|
|
47318
|
-
palette.textMuted,
|
|
47319
|
-
haloColor,
|
|
47320
|
-
true,
|
|
48783
|
+
leg.labelColor ?? palette.textMuted,
|
|
48784
|
+
leg.labelHaloColor ?? haloColor,
|
|
48785
|
+
leg.labelHalo ?? true,
|
|
47321
48786
|
LABEL_FONT - 1
|
|
47322
48787
|
);
|
|
48788
|
+
wireSync(lt, leg.lineNumber);
|
|
47323
48789
|
}
|
|
47324
48790
|
});
|
|
48791
|
+
const gSpider = svg.append("g").attr("class", "dgmo-map-spider");
|
|
48792
|
+
for (const cl of layout.clusters) {
|
|
48793
|
+
if (!exportDims) {
|
|
48794
|
+
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");
|
|
48795
|
+
}
|
|
48796
|
+
for (const leg of cl.legs) {
|
|
48797
|
+
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");
|
|
48798
|
+
}
|
|
48799
|
+
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");
|
|
48800
|
+
}
|
|
47325
48801
|
const gPois = svg.append("g").attr("class", "dgmo-map-pois");
|
|
47326
48802
|
for (const poi of layout.pois) {
|
|
47327
48803
|
if (poi.isOrigin) {
|
|
47328
48804
|
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);
|
|
47329
48805
|
}
|
|
47330
48806
|
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);
|
|
48807
|
+
if (poi.clusterId !== void 0)
|
|
48808
|
+
c.attr("data-cluster-member", poi.clusterId);
|
|
47331
48809
|
if (poi.tags) {
|
|
47332
48810
|
for (const [group, value] of Object.entries(poi.tags)) {
|
|
47333
48811
|
c.attr(`data-tag-${group.toLowerCase()}`, value.toLowerCase());
|
|
@@ -47355,12 +48833,32 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47355
48833
|
}
|
|
47356
48834
|
const gLabels = svg.append("g").attr("class", "dgmo-map-labels");
|
|
47357
48835
|
for (const lab of layout.labels) {
|
|
48836
|
+
if (lab.hidden) {
|
|
48837
|
+
if (exportDims) continue;
|
|
48838
|
+
emitText(
|
|
48839
|
+
gLabels,
|
|
48840
|
+
lab.x,
|
|
48841
|
+
lab.y,
|
|
48842
|
+
lab.text,
|
|
48843
|
+
lab.anchor,
|
|
48844
|
+
lab.color,
|
|
48845
|
+
lab.haloColor,
|
|
48846
|
+
lab.halo,
|
|
48847
|
+
LABEL_FONT,
|
|
48848
|
+
lab.italic,
|
|
48849
|
+
lab.letterSpacing
|
|
48850
|
+
).attr("data-poi", lab.poiId ?? null).attr("data-poi-hidden", "").style("opacity", 0).style("pointer-events", "none");
|
|
48851
|
+
continue;
|
|
48852
|
+
}
|
|
47358
48853
|
if (lab.leader) {
|
|
47359
48854
|
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(
|
|
47360
48855
|
"stroke",
|
|
47361
48856
|
lab.leaderColor ?? mix(palette.textMuted, palette.bg, 60)
|
|
47362
48857
|
).attr("stroke-width", lab.leaderColor ? 1 : 0.75);
|
|
47363
48858
|
if (lab.poiId !== void 0) line12.attr("data-poi", lab.poiId);
|
|
48859
|
+
if (lab.clusterMember !== void 0)
|
|
48860
|
+
line12.attr("data-cluster-member", lab.clusterMember);
|
|
48861
|
+
wireSync(line12, lab.lineNumber);
|
|
47364
48862
|
}
|
|
47365
48863
|
const t = emitText(
|
|
47366
48864
|
gLabels,
|
|
@@ -47371,11 +48869,38 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47371
48869
|
lab.color,
|
|
47372
48870
|
lab.haloColor,
|
|
47373
48871
|
lab.halo,
|
|
47374
|
-
LABEL_FONT
|
|
48872
|
+
LABEL_FONT,
|
|
48873
|
+
lab.italic,
|
|
48874
|
+
lab.letterSpacing,
|
|
48875
|
+
lab.lines
|
|
47375
48876
|
);
|
|
47376
48877
|
if (lab.poiId !== void 0) {
|
|
47377
48878
|
t.attr("data-poi", lab.poiId).style("cursor", "default");
|
|
47378
48879
|
}
|
|
48880
|
+
if (lab.clusterMember !== void 0) {
|
|
48881
|
+
t.attr("data-cluster-member", lab.clusterMember);
|
|
48882
|
+
}
|
|
48883
|
+
wireSync(t, lab.lineNumber);
|
|
48884
|
+
}
|
|
48885
|
+
if (!exportDims && layout.clusters.length) {
|
|
48886
|
+
const gBadge = svg.append("g").attr("class", "dgmo-map-cluster-badges");
|
|
48887
|
+
for (const cl of layout.clusters) {
|
|
48888
|
+
const g = gBadge.append("g").attr("data-cluster", cl.id).style("opacity", 0).style("pointer-events", "none");
|
|
48889
|
+
const R = 9;
|
|
48890
|
+
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);
|
|
48891
|
+
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);
|
|
48892
|
+
emitText(
|
|
48893
|
+
g,
|
|
48894
|
+
cl.cx,
|
|
48895
|
+
cl.cy + 3,
|
|
48896
|
+
String(cl.count),
|
|
48897
|
+
"middle",
|
|
48898
|
+
palette.text,
|
|
48899
|
+
palette.bg,
|
|
48900
|
+
false,
|
|
48901
|
+
LABEL_FONT
|
|
48902
|
+
);
|
|
48903
|
+
}
|
|
47379
48904
|
}
|
|
47380
48905
|
if (layout.legend) {
|
|
47381
48906
|
const legendY = (layout.title ? TITLE_Y + TITLE_FONT_SIZE : 0) + (layout.subtitle ? TITLE_FONT_SIZE : 0) + 8;
|
|
@@ -47412,7 +48937,7 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47412
48937
|
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);
|
|
47413
48938
|
}
|
|
47414
48939
|
if (layout.subtitle) {
|
|
47415
|
-
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);
|
|
48940
|
+
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);
|
|
47416
48941
|
}
|
|
47417
48942
|
if (layout.caption) {
|
|
47418
48943
|
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);
|
|
@@ -47421,10 +48946,21 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47421
48946
|
function renderMapForExport(container, resolved, data, palette, isDark, exportDims) {
|
|
47422
48947
|
renderMap(container, resolved, data, palette, isDark, void 0, exportDims);
|
|
47423
48948
|
}
|
|
47424
|
-
function emitText(g, x, y, text, anchor, color, halo, withHalo, fontSize) {
|
|
47425
|
-
const t = g.append("text").attr("x", x).attr("y", y).attr("text-anchor", anchor).attr("font-size", fontSize).attr("fill", color)
|
|
48949
|
+
function emitText(g, x, y, text, anchor, color, halo, withHalo, fontSize, italic, letterSpacing, lines) {
|
|
48950
|
+
const t = g.append("text").attr("x", x).attr("y", y).attr("text-anchor", anchor).attr("font-size", fontSize).attr("fill", color);
|
|
48951
|
+
if (lines && lines.length > 1) {
|
|
48952
|
+
const lineHeight = fontSize + 2;
|
|
48953
|
+
const startDy = -((lines.length - 1) / 2) * lineHeight;
|
|
48954
|
+
lines.forEach((ln, i) => {
|
|
48955
|
+
t.append("tspan").attr("x", x).attr("dy", i === 0 ? startDy : lineHeight).text(ln);
|
|
48956
|
+
});
|
|
48957
|
+
} else {
|
|
48958
|
+
t.text(text);
|
|
48959
|
+
}
|
|
48960
|
+
if (italic) t.attr("font-style", "italic");
|
|
48961
|
+
if (letterSpacing) t.attr("letter-spacing", letterSpacing);
|
|
47426
48962
|
if (withHalo) {
|
|
47427
|
-
t.attr("paint-order", "stroke fill").attr("stroke", halo).attr("stroke-width",
|
|
48963
|
+
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);
|
|
47428
48964
|
}
|
|
47429
48965
|
return t;
|
|
47430
48966
|
}
|
|
@@ -47442,6 +48978,56 @@ var init_renderer16 = __esm({
|
|
|
47442
48978
|
}
|
|
47443
48979
|
});
|
|
47444
48980
|
|
|
48981
|
+
// src/map/dimensions.ts
|
|
48982
|
+
var dimensions_exports = {};
|
|
48983
|
+
__export(dimensions_exports, {
|
|
48984
|
+
mapContentAspect: () => mapContentAspect,
|
|
48985
|
+
mapExportDimensions: () => mapExportDimensions
|
|
48986
|
+
});
|
|
48987
|
+
function mapContentAspect(resolved, data, ref = REF) {
|
|
48988
|
+
const { projection, fitTarget } = buildMapProjection(resolved, data);
|
|
48989
|
+
projection.fitSize([ref, ref], fitTarget);
|
|
48990
|
+
const b = (0, import_d3_geo3.geoPath)(projection).bounds(fitTarget);
|
|
48991
|
+
const w = b[1][0] - b[0][0];
|
|
48992
|
+
const h = b[1][1] - b[0][1];
|
|
48993
|
+
const aspect = w / h;
|
|
48994
|
+
return Number.isFinite(aspect) && aspect > 0 ? aspect : FALLBACK_ASPECT;
|
|
48995
|
+
}
|
|
48996
|
+
function mapExportDimensions(resolved, data, baseWidth = 1200) {
|
|
48997
|
+
const raw = mapContentAspect(resolved, data);
|
|
48998
|
+
const clamped = Math.max(ASPECT_MIN, Math.min(ASPECT_MAX, raw));
|
|
48999
|
+
const width = baseWidth;
|
|
49000
|
+
let height = Math.round(width / clamped);
|
|
49001
|
+
let chromeReserve = 0;
|
|
49002
|
+
if (resolved.title && resolved.pois.length > 0) {
|
|
49003
|
+
const bannerBottom = (resolved.subtitle ? TITLE_Y + TITLE_FONT_SIZE : TITLE_Y) + TITLE_FONT_SIZE / 2;
|
|
49004
|
+
chromeReserve += Math.max(FIT_PAD2, bannerBottom + TITLE_GAP) - FIT_PAD2;
|
|
49005
|
+
}
|
|
49006
|
+
let floored = false;
|
|
49007
|
+
if (height - chromeReserve < MIN_MAP_BAND) {
|
|
49008
|
+
height = Math.round(chromeReserve + MIN_MAP_BAND);
|
|
49009
|
+
floored = true;
|
|
49010
|
+
}
|
|
49011
|
+
const preferContain = clamped !== raw || floored;
|
|
49012
|
+
return { width, height, preferContain };
|
|
49013
|
+
}
|
|
49014
|
+
var import_d3_geo3, FIT_PAD2, TITLE_GAP, ASPECT_MAX, ASPECT_MIN, MIN_MAP_BAND, FALLBACK_ASPECT, REF;
|
|
49015
|
+
var init_dimensions = __esm({
|
|
49016
|
+
"src/map/dimensions.ts"() {
|
|
49017
|
+
"use strict";
|
|
49018
|
+
import_d3_geo3 = require("d3-geo");
|
|
49019
|
+
init_title_constants();
|
|
49020
|
+
init_layout15();
|
|
49021
|
+
FIT_PAD2 = 24;
|
|
49022
|
+
TITLE_GAP = 16;
|
|
49023
|
+
ASPECT_MAX = 3;
|
|
49024
|
+
ASPECT_MIN = 0.9;
|
|
49025
|
+
MIN_MAP_BAND = 200;
|
|
49026
|
+
FALLBACK_ASPECT = 1.5;
|
|
49027
|
+
REF = 1e3;
|
|
49028
|
+
}
|
|
49029
|
+
});
|
|
49030
|
+
|
|
47445
49031
|
// src/map/load-data.ts
|
|
47446
49032
|
var load_data_exports = {};
|
|
47447
49033
|
__export(load_data_exports, {
|
|
@@ -47500,12 +49086,17 @@ function loadMapData() {
|
|
|
47500
49086
|
mountainRanges,
|
|
47501
49087
|
naLand,
|
|
47502
49088
|
naLakes,
|
|
49089
|
+
waterBodies,
|
|
47503
49090
|
gazetteer
|
|
47504
49091
|
] = await Promise.all([
|
|
49092
|
+
// worldCoarse (110m) is LOAD-BEARING but NOT a render source: the world
|
|
49093
|
+
// basemap renders from worldDetail (50m) at all scales (resolver pins
|
|
49094
|
+
// basemaps.world = 'detail'). Coarse stays as the authoritative region
|
|
49095
|
+
// name index + dominant-landmass bbox source in resolver.ts. Do not drop it.
|
|
47505
49096
|
readJson(nb, dir, FILES.worldCoarse),
|
|
47506
49097
|
readJson(nb, dir, FILES.worldDetail),
|
|
47507
49098
|
readJson(nb, dir, FILES.usStates),
|
|
47508
|
-
// Lakes/rivers/mountain/NA assets are optional — older bundles may predate them.
|
|
49099
|
+
// Lakes/rivers/mountain/NA/water assets are optional — older bundles may predate them.
|
|
47509
49100
|
readJson(nb, dir, FILES.lakes).catch(() => void 0),
|
|
47510
49101
|
readJson(nb, dir, FILES.rivers).catch(() => void 0),
|
|
47511
49102
|
readJson(nb, dir, FILES.mountainRanges).catch(
|
|
@@ -47513,6 +49104,7 @@ function loadMapData() {
|
|
|
47513
49104
|
),
|
|
47514
49105
|
readJson(nb, dir, FILES.naLand).catch(() => void 0),
|
|
47515
49106
|
readJson(nb, dir, FILES.naLakes).catch(() => void 0),
|
|
49107
|
+
readJson(nb, dir, FILES.waterBodies).catch(() => void 0),
|
|
47516
49108
|
readJson(nb, dir, FILES.gazetteer)
|
|
47517
49109
|
]);
|
|
47518
49110
|
return validate({
|
|
@@ -47524,7 +49116,8 @@ function loadMapData() {
|
|
|
47524
49116
|
...rivers && { rivers },
|
|
47525
49117
|
...mountainRanges && { mountainRanges },
|
|
47526
49118
|
...naLand && { naLand },
|
|
47527
|
-
...naLakes && { naLakes }
|
|
49119
|
+
...naLakes && { naLakes },
|
|
49120
|
+
...waterBodies && { waterBodies }
|
|
47528
49121
|
});
|
|
47529
49122
|
})().catch((e) => {
|
|
47530
49123
|
cache = void 0;
|
|
@@ -47546,6 +49139,7 @@ var init_load_data = __esm({
|
|
|
47546
49139
|
mountainRanges: "mountain-ranges.json",
|
|
47547
49140
|
naLand: "na-land.json",
|
|
47548
49141
|
naLakes: "na-lakes.json",
|
|
49142
|
+
waterBodies: "water-bodies.json",
|
|
47549
49143
|
gazetteer: "gazetteer.json"
|
|
47550
49144
|
};
|
|
47551
49145
|
CANDIDATE_DIRS = [
|
|
@@ -49558,8 +51152,8 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
|
|
|
49558
51152
|
const lines = splitParticipantLabel(p.label, LABEL_MAX_CHARS);
|
|
49559
51153
|
if (lines.length === 0) continue;
|
|
49560
51154
|
const widest = Math.max(...lines.map((l) => l.length));
|
|
49561
|
-
const
|
|
49562
|
-
uniformBoxWidth = Math.max(uniformBoxWidth,
|
|
51155
|
+
const labelWidth2 = widest * LABEL_CHAR_WIDTH + 10;
|
|
51156
|
+
uniformBoxWidth = Math.max(uniformBoxWidth, labelWidth2);
|
|
49563
51157
|
}
|
|
49564
51158
|
uniformBoxWidth = Math.min(MAX_BOX_WIDTH, uniformBoxWidth);
|
|
49565
51159
|
const effectiveGap = Math.max(PARTICIPANT_GAP, uniformBoxWidth + 30);
|
|
@@ -52254,15 +53848,15 @@ function renderArcDiagram(container, parsed, palette, _isDark, onClickItem, expo
|
|
|
52254
53848
|
textColor,
|
|
52255
53849
|
onClickItem
|
|
52256
53850
|
);
|
|
52257
|
-
const
|
|
52258
|
-
for (const node of nodes)
|
|
53851
|
+
const neighbors2 = /* @__PURE__ */ new Map();
|
|
53852
|
+
for (const node of nodes) neighbors2.set(node, /* @__PURE__ */ new Set());
|
|
52259
53853
|
for (const link of links) {
|
|
52260
|
-
|
|
52261
|
-
|
|
53854
|
+
neighbors2.get(link.source).add(link.target);
|
|
53855
|
+
neighbors2.get(link.target).add(link.source);
|
|
52262
53856
|
}
|
|
52263
53857
|
const FADE_OPACITY3 = 0.1;
|
|
52264
53858
|
function handleMouseEnter(hovered) {
|
|
52265
|
-
const connected =
|
|
53859
|
+
const connected = neighbors2.get(hovered);
|
|
52266
53860
|
g.selectAll(".arc-link").each(function() {
|
|
52267
53861
|
const el = d3Selection23.select(this);
|
|
52268
53862
|
const src = el.attr("data-source");
|
|
@@ -54197,7 +55791,7 @@ function renderVenn(container, parsed, palette, _isDark, onClickItem, exportDims
|
|
|
54197
55791
|
8,
|
|
54198
55792
|
Math.floor(OVERLAP_WRAP_TARGET_W / OVERLAP_CH_W)
|
|
54199
55793
|
);
|
|
54200
|
-
function
|
|
55794
|
+
function wrapLabel3(text, maxChars) {
|
|
54201
55795
|
const words = text.split(/\s+/).filter(Boolean);
|
|
54202
55796
|
const lines = [];
|
|
54203
55797
|
let cur = "";
|
|
@@ -54243,7 +55837,7 @@ function renderVenn(container, parsed, palette, _isDark, onClickItem, exportDims
|
|
|
54243
55837
|
if (!ov.label) continue;
|
|
54244
55838
|
const idxs = ov.sets.map((s) => vennSets.findIndex((vs) => vs.name === s));
|
|
54245
55839
|
if (idxs.some((idx) => idx < 0)) continue;
|
|
54246
|
-
const lines =
|
|
55840
|
+
const lines = wrapLabel3(ov.label, MAX_WRAP_CHARS);
|
|
54247
55841
|
wrappedOverlapLabels.set(ov, lines);
|
|
54248
55842
|
const dir = predictOverlapDirRaw(idxs);
|
|
54249
55843
|
const longest = lines.reduce((m, l) => Math.max(m, l.length), 0);
|
|
@@ -55681,6 +57275,7 @@ async function renderForExport(content, theme, palette, viewState, options) {
|
|
|
55681
57275
|
const { parseMap: parseMap2 } = await Promise.resolve().then(() => (init_parser12(), parser_exports11));
|
|
55682
57276
|
const { resolveMap: resolveMap2 } = await Promise.resolve().then(() => (init_resolver2(), resolver_exports));
|
|
55683
57277
|
const { renderMapForExport: renderMapForExport2 } = await Promise.resolve().then(() => (init_renderer16(), renderer_exports16));
|
|
57278
|
+
const { mapExportDimensions: mapExportDimensions2 } = await Promise.resolve().then(() => (init_dimensions(), dimensions_exports));
|
|
55684
57279
|
const effectivePalette2 = await resolveExportPalette(theme, palette);
|
|
55685
57280
|
const mapParsed = parseMap2(content);
|
|
55686
57281
|
let mapData = options?.mapData;
|
|
@@ -55693,14 +57288,15 @@ async function renderForExport(content, theme, palette, viewState, options) {
|
|
|
55693
57288
|
}
|
|
55694
57289
|
}
|
|
55695
57290
|
const mapResolved = resolveMap2(mapParsed, mapData);
|
|
55696
|
-
const
|
|
57291
|
+
const dims2 = mapExportDimensions2(mapResolved, mapData, EXPORT_WIDTH);
|
|
57292
|
+
const container2 = createExportContainer(dims2.width, dims2.height);
|
|
55697
57293
|
renderMapForExport2(
|
|
55698
57294
|
container2,
|
|
55699
57295
|
mapResolved,
|
|
55700
57296
|
mapData,
|
|
55701
57297
|
effectivePalette2,
|
|
55702
57298
|
theme === "dark",
|
|
55703
|
-
|
|
57299
|
+
dims2
|
|
55704
57300
|
);
|
|
55705
57301
|
return finalizeSvgExport(container2, theme, effectivePalette2);
|
|
55706
57302
|
}
|
|
@@ -56561,7 +58157,8 @@ async function render(content, options) {
|
|
|
56561
58157
|
...options?.c4Container !== void 0 && {
|
|
56562
58158
|
c4Container: options.c4Container
|
|
56563
58159
|
},
|
|
56564
|
-
...options?.tagGroup !== void 0 && { tagGroup: options.tagGroup }
|
|
58160
|
+
...options?.tagGroup !== void 0 && { tagGroup: options.tagGroup },
|
|
58161
|
+
...options?.mapData !== void 0 && { mapData: options.mapData }
|
|
56565
58162
|
});
|
|
56566
58163
|
if (chartType === "map") {
|
|
56567
58164
|
try {
|
|
@@ -56572,7 +58169,7 @@ async function render(content, options) {
|
|
|
56572
58169
|
Promise.resolve().then(() => (init_load_data(), load_data_exports))
|
|
56573
58170
|
]
|
|
56574
58171
|
);
|
|
56575
|
-
const data = await loadMapData2();
|
|
58172
|
+
const data = options?.mapData ?? await loadMapData2();
|
|
56576
58173
|
diagnostics = [...resolveMap2(parseMap2(content), data).diagnostics];
|
|
56577
58174
|
} catch {
|
|
56578
58175
|
}
|
|
@@ -56740,22 +58337,20 @@ var DIRECTIVE_KEYWORDS = /* @__PURE__ */ new Set([
|
|
|
56740
58337
|
// Sequence
|
|
56741
58338
|
"activations",
|
|
56742
58339
|
"no-activations",
|
|
56743
|
-
// Map (§24B) directives
|
|
56744
|
-
"region",
|
|
56745
|
-
"projection",
|
|
58340
|
+
// Map (§24B) directives — cosmetics on by default, bare `no-*` opt-outs
|
|
56746
58341
|
"region-metric",
|
|
56747
58342
|
"poi-metric",
|
|
56748
58343
|
"flow-metric",
|
|
56749
|
-
"
|
|
56750
|
-
"
|
|
56751
|
-
"default-country",
|
|
56752
|
-
"default-state",
|
|
56753
|
-
"no-legend",
|
|
56754
|
-
"no-insets",
|
|
56755
|
-
"muted",
|
|
56756
|
-
"natural",
|
|
56757
|
-
"subtitle",
|
|
58344
|
+
"locale",
|
|
58345
|
+
"active-tag",
|
|
56758
58346
|
"caption",
|
|
58347
|
+
"no-legend",
|
|
58348
|
+
"no-coastline",
|
|
58349
|
+
"no-relief",
|
|
58350
|
+
"no-context-labels",
|
|
58351
|
+
"no-region-labels",
|
|
58352
|
+
"no-poi-labels",
|
|
58353
|
+
"no-colorize",
|
|
56759
58354
|
"poi",
|
|
56760
58355
|
"route",
|
|
56761
58356
|
// Data charts
|
|
@@ -57048,7 +58643,11 @@ var ATTRIBUTE_KEYS = /* @__PURE__ */ new Set([
|
|
|
57048
58643
|
"collapsed",
|
|
57049
58644
|
"tech",
|
|
57050
58645
|
"span",
|
|
57051
|
-
"split"
|
|
58646
|
+
"split",
|
|
58647
|
+
// Map (§24B) reserved keys
|
|
58648
|
+
"value",
|
|
58649
|
+
"label",
|
|
58650
|
+
"style"
|
|
57052
58651
|
]);
|
|
57053
58652
|
function applyAttributeKeys(tokens) {
|
|
57054
58653
|
for (let i = 0; i < tokens.length - 1; i++) {
|
|
@@ -57421,7 +59020,7 @@ pre.dgmo, code.language-dgmo, pre > code.language-dgmo,
|
|
|
57421
59020
|
|
|
57422
59021
|
// src/auto/index.ts
|
|
57423
59022
|
init_safe_href();
|
|
57424
|
-
var VERSION = "0.
|
|
59023
|
+
var VERSION = "0.22.0";
|
|
57425
59024
|
var DEFAULTS = {
|
|
57426
59025
|
theme: "auto",
|
|
57427
59026
|
palette: "nord",
|