@diagrammo/dgmo 0.21.0 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -6
- package/dist/advanced.cjs +2521 -623
- package/dist/advanced.d.cts +917 -534
- package/dist/advanced.d.ts +917 -534
- package/dist/advanced.js +2516 -623
- package/dist/auto.cjs +2333 -608
- package/dist/auto.js +119 -119
- package/dist/auto.mjs +2335 -609
- package/dist/cli.cjs +168 -168
- package/dist/editor.cjs +13 -15
- package/dist/editor.js +13 -15
- package/dist/highlight.cjs +15 -12
- package/dist/highlight.js +15 -12
- package/dist/index.cjs +2317 -595
- package/dist/index.d.cts +4 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +2319 -596
- package/dist/internal.cjs +2521 -623
- package/dist/internal.d.cts +917 -534
- package/dist/internal.d.ts +917 -534
- package/dist/internal.js +2516 -623
- package/dist/map-data/PROVENANCE.json +1 -1
- package/dist/map-data/mountain-ranges.json +1 -0
- package/dist/map-data/water-bodies.json +1 -0
- package/docs/language-reference.md +44 -31
- package/gallery/fixtures/map-categorical-world.dgmo +16 -0
- package/gallery/fixtures/map-categorical.dgmo +0 -1
- package/gallery/fixtures/map-choropleth.dgmo +0 -1
- package/gallery/fixtures/map-coastline.dgmo +7 -0
- package/gallery/fixtures/map-colorize.dgmo +11 -0
- package/gallery/fixtures/map-direct-color.dgmo +9 -0
- package/gallery/fixtures/map-reference-world.dgmo +11 -0
- package/gallery/fixtures/map-region-scope.dgmo +0 -3
- package/gallery/fixtures/map-route.dgmo +0 -1
- package/package.json +1 -1
- package/src/advanced.ts +26 -1
- package/src/boxes-and-lines/renderer.ts +39 -12
- package/src/cli.ts +1 -1
- package/src/completion.ts +32 -24
- package/src/cycle/renderer.ts +14 -1
- package/src/d3.ts +23 -11
- package/src/editor/highlight-api.ts +4 -0
- package/src/editor/keywords.ts +13 -15
- package/src/infra/renderer.ts +35 -7
- package/src/map/colorize.ts +54 -0
- package/src/map/context-labels.ts +429 -0
- package/src/map/data/PROVENANCE.json +1 -1
- package/src/map/data/mountain-ranges.json +1 -0
- package/src/map/data/types.ts +34 -0
- package/src/map/data/water-bodies.json +1 -0
- package/src/map/dimensions.ts +117 -0
- package/src/map/geo-query.ts +295 -0
- package/src/map/geo.ts +305 -2
- package/src/map/invert.ts +111 -0
- package/src/map/layout.ts +1504 -335
- package/src/map/load-data.ts +16 -2
- package/src/map/parser.ts +57 -111
- package/src/map/renderer.ts +556 -13
- package/src/map/resolved-types.ts +24 -2
- package/src/map/resolver.ts +237 -67
- package/src/map/types.ts +39 -23
- package/src/mindmap/renderer.ts +10 -1
- package/src/palettes/atlas.ts +77 -0
- package/src/palettes/blueprint.ts +73 -0
- package/src/palettes/color-utils.ts +58 -1
- package/src/palettes/index.ts +12 -3
- package/src/palettes/slate.ts +73 -0
- package/src/palettes/tidewater.ts +73 -0
- package/src/render.ts +8 -1
- package/src/tech-radar/renderer.ts +3 -0
- package/src/tech-radar/types.ts +3 -0
- package/src/utils/d3-types.ts +5 -0
- package/src/utils/legend-layout.ts +21 -4
- package/src/utils/legend-types.ts +7 -0
- package/src/utils/reserved-key-registry.ts +3 -0
- package/src/palettes/bold.ts +0 -67
package/dist/auto.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,28 +16289,13 @@ 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
|
-
case "region-metric":
|
|
16292
|
+
case "region-metric": {
|
|
15879
16293
|
dup(d.regionMetric);
|
|
15880
|
-
|
|
16294
|
+
const { label: rmLabel, colorName: rmColor } = peelTrailingColorName(value);
|
|
16295
|
+
d.regionMetric = rmLabel;
|
|
16296
|
+
if (rmColor) d.regionMetricColor = rmColor;
|
|
15881
16297
|
break;
|
|
16298
|
+
}
|
|
15882
16299
|
case "poi-metric":
|
|
15883
16300
|
dup(d.poiMetric);
|
|
15884
16301
|
d.poiMetric = value;
|
|
@@ -15887,85 +16304,43 @@ function parseMap(content) {
|
|
|
15887
16304
|
dup(d.flowMetric);
|
|
15888
16305
|
d.flowMetric = value;
|
|
15889
16306
|
break;
|
|
15890
|
-
case "
|
|
15891
|
-
dup(d.
|
|
15892
|
-
|
|
15893
|
-
const s = parseScale(value, line12);
|
|
15894
|
-
if (s) d.scale = s;
|
|
15895
|
-
}
|
|
15896
|
-
break;
|
|
15897
|
-
case "region-labels":
|
|
15898
|
-
dup(d.regionLabels);
|
|
15899
|
-
if (value && !["full", "abbrev", "off"].includes(value))
|
|
15900
|
-
pushWarning(
|
|
15901
|
-
line12,
|
|
15902
|
-
`Unknown region-labels "${value}" (expected full | abbrev | off).`
|
|
15903
|
-
);
|
|
15904
|
-
d.regionLabels = value;
|
|
15905
|
-
break;
|
|
15906
|
-
case "poi-labels":
|
|
15907
|
-
dup(d.poiLabels);
|
|
15908
|
-
if (value && !["off", "auto", "all"].includes(value))
|
|
15909
|
-
pushWarning(
|
|
15910
|
-
line12,
|
|
15911
|
-
`Unknown poi-labels "${value}" (expected off | auto | all).`
|
|
15912
|
-
);
|
|
15913
|
-
d.poiLabels = value;
|
|
15914
|
-
break;
|
|
15915
|
-
case "default-country":
|
|
15916
|
-
dup(d.defaultCountry);
|
|
15917
|
-
d.defaultCountry = value;
|
|
15918
|
-
break;
|
|
15919
|
-
case "default-state":
|
|
15920
|
-
dup(d.defaultState);
|
|
15921
|
-
d.defaultState = value;
|
|
16307
|
+
case "locale":
|
|
16308
|
+
dup(d.locale);
|
|
16309
|
+
d.locale = value;
|
|
15922
16310
|
break;
|
|
15923
16311
|
case "active-tag":
|
|
15924
16312
|
dup(d.activeTag);
|
|
15925
16313
|
d.activeTag = value;
|
|
15926
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. ──
|
|
15927
16321
|
case "no-legend":
|
|
15928
16322
|
d.noLegend = true;
|
|
15929
16323
|
break;
|
|
15930
|
-
case "
|
|
15931
|
-
|
|
15932
|
-
if (d.basemapStyle !== void 0 && d.basemapStyle !== key)
|
|
15933
|
-
pushWarning(
|
|
15934
|
-
line12,
|
|
15935
|
-
`Conflicting basemap dress \u2014 "${d.basemapStyle}" then "${key}"; last wins.`
|
|
15936
|
-
);
|
|
15937
|
-
d.basemapStyle = key;
|
|
16324
|
+
case "no-coastline":
|
|
16325
|
+
d.noCoastline = true;
|
|
15938
16326
|
break;
|
|
15939
|
-
case "
|
|
15940
|
-
|
|
15941
|
-
d.subtitle = value;
|
|
16327
|
+
case "no-relief":
|
|
16328
|
+
d.noRelief = true;
|
|
15942
16329
|
break;
|
|
15943
|
-
case "
|
|
15944
|
-
|
|
15945
|
-
|
|
16330
|
+
case "no-context-labels":
|
|
16331
|
+
d.noContextLabels = true;
|
|
16332
|
+
break;
|
|
16333
|
+
case "no-region-labels":
|
|
16334
|
+
d.noRegionLabels = true;
|
|
16335
|
+
break;
|
|
16336
|
+
case "no-poi-labels":
|
|
16337
|
+
d.noPoiLabels = true;
|
|
16338
|
+
break;
|
|
16339
|
+
case "no-colorize":
|
|
16340
|
+
d.noColorize = true;
|
|
15946
16341
|
break;
|
|
15947
16342
|
}
|
|
15948
16343
|
}
|
|
15949
|
-
function parseScale(value, line12) {
|
|
15950
|
-
const toks = value.split(/\s+/).filter(Boolean);
|
|
15951
|
-
const min = Number(toks[0]);
|
|
15952
|
-
const max = Number(toks[1]);
|
|
15953
|
-
if (!Number.isFinite(min) || !Number.isFinite(max)) {
|
|
15954
|
-
pushError(line12, `scale requires numeric <min> <max> (got "${value}").`);
|
|
15955
|
-
return null;
|
|
15956
|
-
}
|
|
15957
|
-
const scale = { min, max };
|
|
15958
|
-
if (toks[2] === "center") {
|
|
15959
|
-
const c = Number(toks[3]);
|
|
15960
|
-
if (Number.isFinite(c)) scale.center = c;
|
|
15961
|
-
else
|
|
15962
|
-
pushError(
|
|
15963
|
-
line12,
|
|
15964
|
-
`scale center requires a number (got "${toks[3] ?? ""}").`
|
|
15965
|
-
);
|
|
15966
|
-
}
|
|
15967
|
-
return scale;
|
|
15968
|
-
}
|
|
15969
16344
|
function handleTag(trimmed, line12) {
|
|
15970
16345
|
const m = matchTagBlockHeading(trimmed);
|
|
15971
16346
|
if (!m) {
|
|
@@ -16039,6 +16414,7 @@ function parseMap(content) {
|
|
|
16039
16414
|
};
|
|
16040
16415
|
if (regionScope !== void 0) region.scope = regionScope;
|
|
16041
16416
|
if (valueNum !== void 0) region.value = valueNum;
|
|
16417
|
+
if (split.color) region.color = split.color;
|
|
16042
16418
|
regions.push(region);
|
|
16043
16419
|
}
|
|
16044
16420
|
function handlePoi(rest, line12, indent) {
|
|
@@ -16063,6 +16439,7 @@ function parseMap(content) {
|
|
|
16063
16439
|
const poi = { pos, tags, meta, lineNumber: line12 };
|
|
16064
16440
|
if (split.alias) poi.alias = split.alias;
|
|
16065
16441
|
if (label !== void 0) poi.label = label;
|
|
16442
|
+
if (split.color) poi.color = split.color;
|
|
16066
16443
|
pois.push(poi);
|
|
16067
16444
|
open.poi = { poi, indent };
|
|
16068
16445
|
}
|
|
@@ -16163,13 +16540,15 @@ function parseMap(content) {
|
|
|
16163
16540
|
pushError(line12, `Edge has an empty endpoint: "${trimmed}".`);
|
|
16164
16541
|
continue;
|
|
16165
16542
|
}
|
|
16166
|
-
const
|
|
16543
|
+
const isLast = k === links.length - 1;
|
|
16544
|
+
const meta = isLast ? lastSplit.meta : {};
|
|
16545
|
+
const style = links[k].style === "arc" ? "arc" : "straight";
|
|
16167
16546
|
edges.push({
|
|
16168
16547
|
from,
|
|
16169
16548
|
to,
|
|
16170
16549
|
...links[k].label !== void 0 && { label: links[k].label },
|
|
16171
16550
|
directed: links[k].directed,
|
|
16172
|
-
style
|
|
16551
|
+
style,
|
|
16173
16552
|
meta,
|
|
16174
16553
|
lineNumber: line12
|
|
16175
16554
|
});
|
|
@@ -16255,20 +16634,19 @@ var init_parser12 = __esm({
|
|
|
16255
16634
|
LEG_ARROW_RE = /^(-[^>]*?->|->|~[^>]*?~>|~>|--)\s+(.+)$/;
|
|
16256
16635
|
AT_RE = /(^|[\s,])at\s*:/i;
|
|
16257
16636
|
DIRECTIVE_SET = /* @__PURE__ */ new Set([
|
|
16258
|
-
"region",
|
|
16259
|
-
"projection",
|
|
16260
16637
|
"region-metric",
|
|
16261
16638
|
"poi-metric",
|
|
16262
16639
|
"flow-metric",
|
|
16263
|
-
"
|
|
16264
|
-
"region-labels",
|
|
16265
|
-
"poi-labels",
|
|
16266
|
-
"default-country",
|
|
16267
|
-
"default-state",
|
|
16640
|
+
"locale",
|
|
16268
16641
|
"active-tag",
|
|
16642
|
+
"caption",
|
|
16269
16643
|
"no-legend",
|
|
16270
|
-
"
|
|
16271
|
-
"
|
|
16644
|
+
"no-coastline",
|
|
16645
|
+
"no-relief",
|
|
16646
|
+
"no-context-labels",
|
|
16647
|
+
"no-region-labels",
|
|
16648
|
+
"no-poi-labels",
|
|
16649
|
+
"no-colorize"
|
|
16272
16650
|
]);
|
|
16273
16651
|
}
|
|
16274
16652
|
});
|
|
@@ -24189,8 +24567,8 @@ function renderKanban(container, parsed, palette, isDark, options) {
|
|
|
24189
24567
|
let metaY = separatorY + sCardSeparatorGap + sCardMetaFontSize;
|
|
24190
24568
|
for (const meta of tagMeta) {
|
|
24191
24569
|
cg.append("text").attr("x", cx + sCardPaddingX).attr("y", metaY).attr("font-size", sCardMetaFontSize).attr("fill", onCardText).text(`${meta.label}: `);
|
|
24192
|
-
const
|
|
24193
|
-
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);
|
|
24194
24572
|
metaY += sCardMetaLineHeight;
|
|
24195
24573
|
}
|
|
24196
24574
|
for (const detail of card.details) {
|
|
@@ -24534,8 +24912,8 @@ function renderSwimlaneCard(parent, cardLayout, tagGroups, activeTagGroup, palet
|
|
|
24534
24912
|
let metaY = separatorY + sCardSeparatorGap + sCardMetaFontSize;
|
|
24535
24913
|
for (const meta of tagMeta) {
|
|
24536
24914
|
cg.append("text").attr("x", cx + sCardPaddingX).attr("y", metaY).attr("font-size", sCardMetaFontSize).attr("fill", palette.textMuted).text(`${meta.label}: `);
|
|
24537
|
-
const
|
|
24538
|
-
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);
|
|
24539
24917
|
metaY += sCardMetaLineHeight;
|
|
24540
24918
|
}
|
|
24541
24919
|
for (const detail of card.details) {
|
|
@@ -25370,8 +25748,8 @@ function classifyEREntities(tables, relationships) {
|
|
|
25370
25748
|
}
|
|
25371
25749
|
}
|
|
25372
25750
|
const mmParticipants = /* @__PURE__ */ new Set();
|
|
25373
|
-
for (const [id,
|
|
25374
|
-
if (
|
|
25751
|
+
for (const [id, neighbors2] of tableStarNeighbors) {
|
|
25752
|
+
if (neighbors2.size >= 2) mmParticipants.add(id);
|
|
25375
25753
|
}
|
|
25376
25754
|
const indegreeValues = Object.values(indegreeMap);
|
|
25377
25755
|
const mean = indegreeValues.reduce((a, b) => a + b, 0) / indegreeValues.length;
|
|
@@ -26042,7 +26420,8 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26042
26420
|
controlsExpanded,
|
|
26043
26421
|
onToggleDescriptions,
|
|
26044
26422
|
onToggleControlsExpand,
|
|
26045
|
-
exportMode = false
|
|
26423
|
+
exportMode = false,
|
|
26424
|
+
controlsHost
|
|
26046
26425
|
} = options ?? {};
|
|
26047
26426
|
d3Selection6.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
26048
26427
|
const width = exportDims?.width ?? container.clientWidth;
|
|
@@ -26060,7 +26439,11 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26060
26439
|
const sGroupLabelZone = sctx.structural(GROUP_LABEL_ZONE);
|
|
26061
26440
|
const sTitleFontSize = sctx.text(TITLE_FONT_SIZE);
|
|
26062
26441
|
const sTitleY = sctx.structural(TITLE_Y);
|
|
26063
|
-
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(
|
|
26064
26447
|
getMaxLegendReservedHeight(
|
|
26065
26448
|
{
|
|
26066
26449
|
groups: parsed.tagGroups,
|
|
@@ -26069,7 +26452,7 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26069
26452
|
},
|
|
26070
26453
|
width
|
|
26071
26454
|
)
|
|
26072
|
-
);
|
|
26455
|
+
) : 0;
|
|
26073
26456
|
const activeGroup = resolveActiveTagGroup(
|
|
26074
26457
|
parsed.tagGroups,
|
|
26075
26458
|
parsed.options["active-tag"],
|
|
@@ -26384,10 +26767,10 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26384
26767
|
const hasDescriptions = parsed.nodes.some(
|
|
26385
26768
|
(n) => n.description && n.description.length > 0
|
|
26386
26769
|
);
|
|
26387
|
-
const hasLegend = parsed.tagGroups.length > 0 || hasDescriptions;
|
|
26770
|
+
const hasLegend = parsed.tagGroups.length > 0 || hasDescriptions && controlsHost !== "app";
|
|
26388
26771
|
if (hasLegend) {
|
|
26389
26772
|
let controlsGroup;
|
|
26390
|
-
if (hasDescriptions && onToggleDescriptions) {
|
|
26773
|
+
if (hasDescriptions && (onToggleDescriptions || controlsHost === "app")) {
|
|
26391
26774
|
controlsGroup = {
|
|
26392
26775
|
toggles: [
|
|
26393
26776
|
{
|
|
@@ -26405,7 +26788,14 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26405
26788
|
groups: parsed.tagGroups,
|
|
26406
26789
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
26407
26790
|
mode: exportMode ? "export" : "preview",
|
|
26408
|
-
|
|
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 }
|
|
26409
26799
|
};
|
|
26410
26800
|
const legendState = {
|
|
26411
26801
|
activeGroup,
|
|
@@ -27653,8 +28043,9 @@ function renderMindmap(container, parsed, layout, palette, isDark, onClickItem,
|
|
|
27653
28043
|
const containerHeight = exportDims?.height ?? (container.getBoundingClientRect().height || 600);
|
|
27654
28044
|
d3Selection7.select(container).selectAll("*").remove();
|
|
27655
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";
|
|
27656
28047
|
const hasControls = !!options?.onToggleColorByDepth || !!options?.onToggleDescriptions;
|
|
27657
|
-
const hasLegend = parsed.tagGroups.length > 0 || hasControls;
|
|
28048
|
+
const hasLegend = parsed.tagGroups.length > 0 || hasControls && !appHosted;
|
|
27658
28049
|
const fixedLegend = !isExport && hasLegend;
|
|
27659
28050
|
const legendReserve = fixedLegend ? getMaxLegendReservedHeight(
|
|
27660
28051
|
{
|
|
@@ -27748,7 +28139,10 @@ function renderMindmap(container, parsed, layout, palette, isDark, onClickItem,
|
|
|
27748
28139
|
}),
|
|
27749
28140
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
27750
28141
|
mode: options?.exportMode ? "export" : "preview",
|
|
27751
|
-
...controlsToggles !== void 0 && { controlsGroup: controlsToggles }
|
|
28142
|
+
...controlsToggles !== void 0 && { controlsGroup: controlsToggles },
|
|
28143
|
+
...options?.controlsHost !== void 0 && {
|
|
28144
|
+
controlsHost: options.controlsHost
|
|
28145
|
+
}
|
|
27752
28146
|
};
|
|
27753
28147
|
const legendState = {
|
|
27754
28148
|
activeGroup: options?.colorByDepth ? null : activeTagGroup !== void 0 ? activeTagGroup : parsed.options["active-tag"] ?? null,
|
|
@@ -28192,8 +28586,8 @@ function computeFieldAlignX(children) {
|
|
|
28192
28586
|
for (const child of children) {
|
|
28193
28587
|
if (child.metadata["_labelField"] === "true" && child.children.length >= 2) {
|
|
28194
28588
|
const labelEl = child.children[0];
|
|
28195
|
-
const
|
|
28196
|
-
maxLabelWidth = Math.max(maxLabelWidth,
|
|
28589
|
+
const labelWidth2 = labelEl.label.length * CHAR_WIDTH5;
|
|
28590
|
+
maxLabelWidth = Math.max(maxLabelWidth, labelWidth2);
|
|
28197
28591
|
labelFieldCount++;
|
|
28198
28592
|
}
|
|
28199
28593
|
}
|
|
@@ -33157,7 +33551,7 @@ function hasRoles(node) {
|
|
|
33157
33551
|
function computeNodeWidth2(node, expanded, options) {
|
|
33158
33552
|
const badgeVal = node.computedConcurrentInvocations === 0 && node.computedInstances > 1 ? node.computedInstances : 0;
|
|
33159
33553
|
const badgeLen = badgeVal > 0 ? `${badgeVal}x`.length + 2 : 0;
|
|
33160
|
-
const
|
|
33554
|
+
const labelWidth2 = (node.label.length + badgeLen) * CHAR_WIDTH7 + PADDING_X3;
|
|
33161
33555
|
const allKeys = [];
|
|
33162
33556
|
if (node.computedRps > 0) allKeys.push("RPS");
|
|
33163
33557
|
if (expanded) {
|
|
@@ -33201,7 +33595,7 @@ function computeNodeWidth2(node, expanded, options) {
|
|
|
33201
33595
|
allKeys.push("overflow");
|
|
33202
33596
|
}
|
|
33203
33597
|
}
|
|
33204
|
-
if (allKeys.length === 0) return Math.max(MIN_NODE_WIDTH2,
|
|
33598
|
+
if (allKeys.length === 0) return Math.max(MIN_NODE_WIDTH2, labelWidth2);
|
|
33205
33599
|
const maxKeyLen = Math.max(...allKeys.map((k) => k.length));
|
|
33206
33600
|
let maxRowWidth = 0;
|
|
33207
33601
|
if (node.computedRps > 0) {
|
|
@@ -33289,7 +33683,7 @@ function computeNodeWidth2(node, expanded, options) {
|
|
|
33289
33683
|
truncated.length * META_CHAR_WIDTH3 + PADDING_X3
|
|
33290
33684
|
);
|
|
33291
33685
|
}
|
|
33292
|
-
return Math.max(MIN_NODE_WIDTH2,
|
|
33686
|
+
return Math.max(MIN_NODE_WIDTH2, labelWidth2, maxRowWidth + 20, descWidth);
|
|
33293
33687
|
}
|
|
33294
33688
|
function computeNodeHeight2(node, expanded, options) {
|
|
33295
33689
|
const propCount = countDisplayProps(node, expanded, options);
|
|
@@ -34838,8 +35232,9 @@ function computeInfraLegendGroups(nodes, tagGroups, palette, edges) {
|
|
|
34838
35232
|
}
|
|
34839
35233
|
return groups;
|
|
34840
35234
|
}
|
|
34841
|
-
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) {
|
|
34842
35236
|
if (legendGroups.length === 0 && !playback) return;
|
|
35237
|
+
const appHostedPlayback = controlsHost === "app" && !!playback;
|
|
34843
35238
|
const legendG = rootSvg.append("g").attr("transform", `translate(0, ${legendY})`);
|
|
34844
35239
|
if (activeGroup) {
|
|
34845
35240
|
legendG.attr("data-legend-active", activeGroup.toLowerCase());
|
|
@@ -34848,14 +35243,29 @@ function renderLegend3(rootSvg, legendGroups, totalWidth, legendY, palette, isDa
|
|
|
34848
35243
|
name: g.name,
|
|
34849
35244
|
entries: g.entries.map((e) => ({ value: e.value, color: e.color }))
|
|
34850
35245
|
}));
|
|
34851
|
-
if (playback) {
|
|
35246
|
+
if (playback && !appHostedPlayback) {
|
|
34852
35247
|
allGroups.push({ name: "Playback", entries: [] });
|
|
34853
35248
|
}
|
|
34854
35249
|
const legendConfig = {
|
|
34855
35250
|
groups: allGroups,
|
|
34856
35251
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
34857
35252
|
mode: exportMode ? "export" : "preview",
|
|
34858
|
-
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
|
+
}
|
|
34859
35269
|
};
|
|
34860
35270
|
const legendState = { activeGroup };
|
|
34861
35271
|
renderLegendD3(
|
|
@@ -34906,8 +35316,9 @@ function renderLegend3(rootSvg, legendGroups, totalWidth, legendY, palette, isDa
|
|
|
34906
35316
|
}
|
|
34907
35317
|
}
|
|
34908
35318
|
}
|
|
34909
|
-
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) {
|
|
34910
35320
|
d3Selection11.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
35321
|
+
const appHostedPlayback = controlsHost === "app" && !!playback;
|
|
34911
35322
|
const ctx = ScaleContext.identity();
|
|
34912
35323
|
const sc = buildScaledConstants(ctx);
|
|
34913
35324
|
const legendGroups = computeInfraLegendGroups(
|
|
@@ -34916,7 +35327,7 @@ function renderInfra(container, layout, palette, isDark, title, titleLineNumber,
|
|
|
34916
35327
|
palette,
|
|
34917
35328
|
layout.edges
|
|
34918
35329
|
);
|
|
34919
|
-
const hasLegend = legendGroups.length > 0 || !!playback;
|
|
35330
|
+
const hasLegend = legendGroups.length > 0 || !!playback && !appHostedPlayback;
|
|
34920
35331
|
const fixedLegend = !exportMode && hasLegend;
|
|
34921
35332
|
const legendDynamicH = hasLegend ? getMaxLegendReservedHeight(
|
|
34922
35333
|
{
|
|
@@ -35060,7 +35471,8 @@ function renderInfra(container, layout, palette, isDark, title, titleLineNumber,
|
|
|
35060
35471
|
isDark,
|
|
35061
35472
|
activeGroup ?? null,
|
|
35062
35473
|
playback ?? void 0,
|
|
35063
|
-
exportMode
|
|
35474
|
+
exportMode,
|
|
35475
|
+
controlsHost
|
|
35064
35476
|
);
|
|
35065
35477
|
legendSvg.selectAll(".infra-legend-group").style("pointer-events", "auto");
|
|
35066
35478
|
} else {
|
|
@@ -35073,7 +35485,8 @@ function renderInfra(container, layout, palette, isDark, title, titleLineNumber,
|
|
|
35073
35485
|
isDark,
|
|
35074
35486
|
activeGroup ?? null,
|
|
35075
35487
|
playback ?? void 0,
|
|
35076
|
-
exportMode
|
|
35488
|
+
exportMode,
|
|
35489
|
+
controlsHost
|
|
35077
35490
|
);
|
|
35078
35491
|
}
|
|
35079
35492
|
}
|
|
@@ -42708,6 +43121,9 @@ function renderTechRadar(container, parsed, palette, isDark, onClickItem, export
|
|
|
42708
43121
|
onToggle: (active) => options.onToggleListing(active)
|
|
42709
43122
|
}
|
|
42710
43123
|
]
|
|
43124
|
+
},
|
|
43125
|
+
...options.controlsHost !== void 0 && {
|
|
43126
|
+
controlsHost: options.controlsHost
|
|
42711
43127
|
}
|
|
42712
43128
|
};
|
|
42713
43129
|
const legendState = {
|
|
@@ -44531,7 +44947,7 @@ function computeCycleLayout(parsed, options) {
|
|
|
44531
44947
|
const circleNodes = parsed.options["circle-nodes"] === "true";
|
|
44532
44948
|
const nodeDims = parsed.nodes.map((node) => {
|
|
44533
44949
|
const hasDesc = !hideDescriptions && node.description.length > 0;
|
|
44534
|
-
const
|
|
44950
|
+
const labelWidth2 = Math.max(
|
|
44535
44951
|
MIN_NODE_WIDTH4,
|
|
44536
44952
|
node.label.length * LABEL_CHAR_W + NODE_PAD_X * 2
|
|
44537
44953
|
);
|
|
@@ -44540,12 +44956,12 @@ function computeCycleLayout(parsed, options) {
|
|
|
44540
44956
|
}
|
|
44541
44957
|
if (!hasDesc) {
|
|
44542
44958
|
return {
|
|
44543
|
-
width: Math.min(MAX_NODE_WIDTH3,
|
|
44959
|
+
width: Math.min(MAX_NODE_WIDTH3, labelWidth2),
|
|
44544
44960
|
height: PLAIN_NODE_HEIGHT,
|
|
44545
44961
|
wrappedDesc: []
|
|
44546
44962
|
};
|
|
44547
44963
|
}
|
|
44548
|
-
return chooseDescribedRectDims(node.description,
|
|
44964
|
+
return chooseDescribedRectDims(node.description, labelWidth2);
|
|
44549
44965
|
});
|
|
44550
44966
|
if (circleNodes) {
|
|
44551
44967
|
const maxDiam = Math.max(...nodeDims.map((d) => d.width));
|
|
@@ -44741,10 +45157,10 @@ function computeCycleLayout(parsed, options) {
|
|
|
44741
45157
|
scale
|
|
44742
45158
|
};
|
|
44743
45159
|
}
|
|
44744
|
-
function chooseDescribedRectDims(description,
|
|
45160
|
+
function chooseDescribedRectDims(description, labelWidth2) {
|
|
44745
45161
|
const minW = Math.min(
|
|
44746
45162
|
MAX_NODE_WIDTH3,
|
|
44747
|
-
Math.max(MIN_NODE_WIDTH4,
|
|
45163
|
+
Math.max(MIN_NODE_WIDTH4, labelWidth2, DESC_MIN_WIDTH)
|
|
44748
45164
|
);
|
|
44749
45165
|
let best = null;
|
|
44750
45166
|
let bestScore = Infinity;
|
|
@@ -45172,7 +45588,8 @@ function renderCycle(container, parsed, palette, isDark, onClickItem, exportDims
|
|
|
45172
45588
|
const hideDescriptions = (renderOptions?.hideDescriptions ?? false) || parsed.options["no-descriptions"] === "true" || viewState?.hd === true;
|
|
45173
45589
|
const showDescriptions = !hideDescriptions;
|
|
45174
45590
|
const hasDescriptions = parsed.nodes.some((n) => n.description.length > 0) || parsed.edges.some((e) => e.description.length > 0);
|
|
45175
|
-
const
|
|
45591
|
+
const appHostedControls = renderOptions?.controlsHost === "app";
|
|
45592
|
+
const hasLegend = !appHostedControls && hasDescriptions && !!renderOptions?.onToggleDescriptions;
|
|
45176
45593
|
const showTitle = !!parsed.title && parsed.options["no-title"] !== "on";
|
|
45177
45594
|
const legendOffset = hasLegend ? sLegendHeight : 0;
|
|
45178
45595
|
const layoutHeight = height - (showTitle ? sTitleAreaHeight : 0) - legendOffset;
|
|
@@ -45209,7 +45626,10 @@ function renderCycle(container, parsed, palette, isDark, onClickItem, exportDims
|
|
|
45209
45626
|
groups: [],
|
|
45210
45627
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
45211
45628
|
mode: renderOptions?.exportMode ? "export" : "preview",
|
|
45212
|
-
controlsGroup
|
|
45629
|
+
controlsGroup,
|
|
45630
|
+
...renderOptions?.controlsHost !== void 0 && {
|
|
45631
|
+
controlsHost: renderOptions.controlsHost
|
|
45632
|
+
}
|
|
45213
45633
|
};
|
|
45214
45634
|
const legendState = {
|
|
45215
45635
|
activeGroup: null,
|
|
@@ -45480,6 +45900,107 @@ function featureIndex(topo) {
|
|
|
45480
45900
|
}
|
|
45481
45901
|
return idx;
|
|
45482
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
|
+
}
|
|
45483
46004
|
function featureBbox(topo, geomId) {
|
|
45484
46005
|
const geom = geomObject(topo).geometries.find((g) => g.id === geomId);
|
|
45485
46006
|
if (!geom) return null;
|
|
@@ -45491,6 +46012,74 @@ function featureBbox(topo, geomId) {
|
|
|
45491
46012
|
[b[1][0], b[1][1]]
|
|
45492
46013
|
];
|
|
45493
46014
|
}
|
|
46015
|
+
function explodePolygons(gj) {
|
|
46016
|
+
const g = gj.geometry ?? gj;
|
|
46017
|
+
const t = g.type;
|
|
46018
|
+
const coords = g.coordinates;
|
|
46019
|
+
if (t === "Polygon") {
|
|
46020
|
+
return [
|
|
46021
|
+
{ type: "Feature", geometry: { type: "Polygon", coordinates: coords } }
|
|
46022
|
+
];
|
|
46023
|
+
}
|
|
46024
|
+
if (t === "MultiPolygon") {
|
|
46025
|
+
return coords.map((rings) => ({
|
|
46026
|
+
type: "Feature",
|
|
46027
|
+
geometry: { type: "Polygon", coordinates: rings }
|
|
46028
|
+
}));
|
|
46029
|
+
}
|
|
46030
|
+
return [];
|
|
46031
|
+
}
|
|
46032
|
+
function bboxGap(a, b) {
|
|
46033
|
+
const lonGap = Math.max(0, a[0][0] - b[1][0], b[0][0] - a[1][0]);
|
|
46034
|
+
const latGap = Math.max(0, a[0][1] - b[1][1], b[0][1] - a[1][1]);
|
|
46035
|
+
return Math.max(lonGap, latGap);
|
|
46036
|
+
}
|
|
46037
|
+
function featureBboxPrimary(topo, geomId) {
|
|
46038
|
+
const geom = geomObject(topo).geometries.find((g) => g.id === geomId);
|
|
46039
|
+
if (!geom) return null;
|
|
46040
|
+
const gj = (0, import_topojson_client.feature)(topo, geom);
|
|
46041
|
+
const parts = explodePolygons(gj);
|
|
46042
|
+
if (parts.length <= 1) return featureBbox(topo, geomId);
|
|
46043
|
+
const polys = parts.map((p) => {
|
|
46044
|
+
const b = (0, import_d3_geo.geoBounds)(p);
|
|
46045
|
+
if (!b || !Number.isFinite(b[0][0])) return null;
|
|
46046
|
+
const wraps = b[1][0] < b[0][0];
|
|
46047
|
+
const bbox = [
|
|
46048
|
+
[b[0][0], b[0][1]],
|
|
46049
|
+
[b[1][0], b[1][1]]
|
|
46050
|
+
];
|
|
46051
|
+
return { bbox, area: (0, import_d3_geo.geoArea)(p), wraps };
|
|
46052
|
+
}).filter(
|
|
46053
|
+
(p) => p !== null
|
|
46054
|
+
);
|
|
46055
|
+
if (polys.length <= 1 || polys.some((p) => p.wraps))
|
|
46056
|
+
return featureBbox(topo, geomId);
|
|
46057
|
+
const maxArea = Math.max(...polys.map((p) => p.area));
|
|
46058
|
+
const anchor = polys.find((p) => p.area === maxArea);
|
|
46059
|
+
const cluster = [
|
|
46060
|
+
[anchor.bbox[0][0], anchor.bbox[0][1]],
|
|
46061
|
+
[anchor.bbox[1][0], anchor.bbox[1][1]]
|
|
46062
|
+
];
|
|
46063
|
+
const remaining = polys.filter((p) => p !== anchor);
|
|
46064
|
+
let added = true;
|
|
46065
|
+
while (added) {
|
|
46066
|
+
added = false;
|
|
46067
|
+
for (let i = remaining.length - 1; i >= 0; i--) {
|
|
46068
|
+
const p = remaining[i];
|
|
46069
|
+
const near = bboxGap(p.bbox, cluster) <= DETACH_GAP_DEG;
|
|
46070
|
+
const large = p.area >= DETACH_AREA_FRAC * maxArea;
|
|
46071
|
+
if (near || large) {
|
|
46072
|
+
cluster[0][0] = Math.min(cluster[0][0], p.bbox[0][0]);
|
|
46073
|
+
cluster[0][1] = Math.min(cluster[0][1], p.bbox[0][1]);
|
|
46074
|
+
cluster[1][0] = Math.max(cluster[1][0], p.bbox[1][0]);
|
|
46075
|
+
cluster[1][1] = Math.max(cluster[1][1], p.bbox[1][1]);
|
|
46076
|
+
remaining.splice(i, 1);
|
|
46077
|
+
added = true;
|
|
46078
|
+
}
|
|
46079
|
+
}
|
|
46080
|
+
}
|
|
46081
|
+
return cluster;
|
|
46082
|
+
}
|
|
45494
46083
|
function unionExtent(boxes, points) {
|
|
45495
46084
|
const lats = [];
|
|
45496
46085
|
const lons = [];
|
|
@@ -45529,13 +46118,17 @@ function unionLongitudes(lons) {
|
|
|
45529
46118
|
}
|
|
45530
46119
|
return { west: pts[gapIdx], east: pts[gapIdx - 1] + 360 };
|
|
45531
46120
|
}
|
|
45532
|
-
var import_topojson_client, import_d3_geo, fold;
|
|
46121
|
+
var import_topojson_client, import_d3_geo, fold, adjacencyCache, EDGE_EPS, DETACH_GAP_DEG, DETACH_AREA_FRAC;
|
|
45533
46122
|
var init_geo = __esm({
|
|
45534
46123
|
"src/map/geo.ts"() {
|
|
45535
46124
|
"use strict";
|
|
45536
46125
|
import_topojson_client = require("topojson-client");
|
|
45537
46126
|
import_d3_geo = require("d3-geo");
|
|
45538
46127
|
fold = (s) => s.normalize("NFD").replace(/\p{Diacritic}/gu, "").toLowerCase().trim();
|
|
46128
|
+
adjacencyCache = /* @__PURE__ */ new WeakMap();
|
|
46129
|
+
EDGE_EPS = 1e-9;
|
|
46130
|
+
DETACH_GAP_DEG = 10;
|
|
46131
|
+
DETACH_AREA_FRAC = 0.25;
|
|
45539
46132
|
}
|
|
45540
46133
|
});
|
|
45541
46134
|
|
|
@@ -45553,6 +46146,12 @@ function looksUS(lat, lon) {
|
|
|
45553
46146
|
if (lat < 15 || lat > 72) return false;
|
|
45554
46147
|
return lon >= -180 && lon <= -64 || lon >= 172;
|
|
45555
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
|
+
}
|
|
45556
46155
|
function resolveMap(parsed, data) {
|
|
45557
46156
|
const diagnostics = [...parsed.diagnostics];
|
|
45558
46157
|
const err = (line12, message, code) => {
|
|
@@ -45563,9 +46162,6 @@ function resolveMap(parsed, data) {
|
|
|
45563
46162
|
};
|
|
45564
46163
|
const result = {
|
|
45565
46164
|
title: parsed.title,
|
|
45566
|
-
...parsed.directives.subtitle !== void 0 && {
|
|
45567
|
-
subtitle: parsed.directives.subtitle
|
|
45568
|
-
},
|
|
45569
46165
|
...parsed.directives.caption !== void 0 && {
|
|
45570
46166
|
caption: parsed.directives.caption
|
|
45571
46167
|
},
|
|
@@ -45575,7 +46171,7 @@ function resolveMap(parsed, data) {
|
|
|
45575
46171
|
// renderer's job (step 4) — the resolver only carries `tags` + `tagGroups`
|
|
45576
46172
|
// through; it never resolves a tag value to a palette color (#10).
|
|
45577
46173
|
directives: { ...parsed.directives },
|
|
45578
|
-
basemaps: { world: "
|
|
46174
|
+
basemaps: { world: "detail", subdivisions: [] },
|
|
45579
46175
|
regions: [],
|
|
45580
46176
|
pois: [],
|
|
45581
46177
|
edges: [],
|
|
@@ -45584,7 +46180,8 @@ function resolveMap(parsed, data) {
|
|
|
45584
46180
|
[-180, -85],
|
|
45585
46181
|
[180, 85]
|
|
45586
46182
|
],
|
|
45587
|
-
projection: "
|
|
46183
|
+
projection: "equirectangular",
|
|
46184
|
+
poiFrameContainers: [],
|
|
45588
46185
|
diagnostics,
|
|
45589
46186
|
error: parsed.error
|
|
45590
46187
|
};
|
|
@@ -45594,7 +46191,10 @@ function resolveMap(parsed, data) {
|
|
|
45594
46191
|
...[...countryIndex.values()].map((v) => v.name),
|
|
45595
46192
|
...[...usStateIndex.values()].map((v) => v.name)
|
|
45596
46193
|
];
|
|
45597
|
-
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) => {
|
|
45598
46198
|
const f = fold(r.name);
|
|
45599
46199
|
return usStateIndex.has(f) && !countryIndex.has(f);
|
|
45600
46200
|
}) || parsed.regions.some(
|
|
@@ -45639,12 +46239,12 @@ function resolveMap(parsed, data) {
|
|
|
45639
46239
|
chosen = { ...inState, layer: "us-state" };
|
|
45640
46240
|
} else {
|
|
45641
46241
|
chosen = { ...inCountry, layer: "country" };
|
|
46242
|
+
warn2(
|
|
46243
|
+
r.lineNumber,
|
|
46244
|
+
`"${r.name}" is both a country and a US state \u2014 resolved as ${chosen.layer} (${chosen.id}). Pin it with an ISO code (${inState.id} / ${inCountry.id}) or name + scope ("${r.name} US" / "${r.name} ${inCountry.id}").`,
|
|
46245
|
+
"W_MAP_REGION_AMBIGUOUS"
|
|
46246
|
+
);
|
|
45642
46247
|
}
|
|
45643
|
-
warn2(
|
|
45644
|
-
r.lineNumber,
|
|
45645
|
-
`"${r.name}" is both a country and a US state \u2014 resolved as ${chosen.layer} (${chosen.id}). Pin it with an ISO code (${inState.id} / ${inCountry.id}) or name + scope ("${r.name} US" / "${r.name} ${inCountry.id}").`,
|
|
45646
|
-
"W_MAP_REGION_AMBIGUOUS"
|
|
45647
|
-
);
|
|
45648
46248
|
} else if (inState) {
|
|
45649
46249
|
chosen = { ...inState, layer: "us-state" };
|
|
45650
46250
|
} else if (inCountry) {
|
|
@@ -45668,6 +46268,7 @@ function resolveMap(parsed, data) {
|
|
|
45668
46268
|
name: chosen.name,
|
|
45669
46269
|
layer: chosen.layer,
|
|
45670
46270
|
...r.value !== void 0 && { value: r.value },
|
|
46271
|
+
...r.color !== void 0 && { color: r.color },
|
|
45671
46272
|
tags: r.tags,
|
|
45672
46273
|
meta: r.meta,
|
|
45673
46274
|
lineNumber: r.lineNumber
|
|
@@ -45744,7 +46345,7 @@ function resolveMap(parsed, data) {
|
|
|
45744
46345
|
if (!scope)
|
|
45745
46346
|
warn2(
|
|
45746
46347
|
line12,
|
|
45747
|
-
`"${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.`,
|
|
45748
46349
|
"W_MAP_AMBIGUOUS_NAME"
|
|
45749
46350
|
);
|
|
45750
46351
|
}
|
|
@@ -45757,17 +46358,21 @@ function resolveMap(parsed, data) {
|
|
|
45757
46358
|
return fold(pos.name);
|
|
45758
46359
|
};
|
|
45759
46360
|
const poiCountries = [];
|
|
45760
|
-
let
|
|
46361
|
+
let anyUsPoi = false;
|
|
46362
|
+
let anyNonNaPoi = false;
|
|
45761
46363
|
const noteCountry = (iso) => {
|
|
45762
46364
|
if (iso) {
|
|
45763
46365
|
poiCountries.push(iso);
|
|
45764
|
-
if (iso
|
|
46366
|
+
if (iso === "US") anyUsPoi = true;
|
|
46367
|
+
if (iso !== "US" && iso !== "CA" && iso !== "MX") anyNonNaPoi = true;
|
|
45765
46368
|
}
|
|
45766
46369
|
};
|
|
45767
46370
|
const deferred = [];
|
|
45768
46371
|
for (const p of parsed.pois) {
|
|
45769
46372
|
if (p.pos.kind === "coords") {
|
|
45770
|
-
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;
|
|
45771
46376
|
addResolvedPoi(p.pos.lat, p.pos.lon, p);
|
|
45772
46377
|
continue;
|
|
45773
46378
|
}
|
|
@@ -45785,14 +46390,15 @@ function resolveMap(parsed, data) {
|
|
|
45785
46390
|
deferred.push(p);
|
|
45786
46391
|
}
|
|
45787
46392
|
}
|
|
45788
|
-
const inferredCountry =
|
|
46393
|
+
const inferredCountry = localeCountry ?? mostCommonCountry(regions, poiCountries) ?? void 0;
|
|
46394
|
+
const inferredScope = localeSubdivision ?? inferredCountry;
|
|
45789
46395
|
for (const p of deferred) {
|
|
45790
46396
|
if (p.pos.kind !== "name") continue;
|
|
45791
46397
|
const got = lookupName(
|
|
45792
46398
|
p.pos.name,
|
|
45793
46399
|
p.pos.scope,
|
|
45794
46400
|
p.lineNumber,
|
|
45795
|
-
|
|
46401
|
+
inferredScope,
|
|
45796
46402
|
true
|
|
45797
46403
|
);
|
|
45798
46404
|
if (got.kind === "ok") {
|
|
@@ -45809,6 +46415,7 @@ function resolveMap(parsed, data) {
|
|
|
45809
46415
|
lat,
|
|
45810
46416
|
lon,
|
|
45811
46417
|
...p.label !== void 0 && { label: p.label },
|
|
46418
|
+
...p.color !== void 0 && { color: p.color },
|
|
45812
46419
|
tags: p.tags,
|
|
45813
46420
|
meta: p.meta,
|
|
45814
46421
|
lineNumber: p.lineNumber
|
|
@@ -45861,7 +46468,8 @@ function resolveMap(parsed, data) {
|
|
|
45861
46468
|
const meta = sizeValue !== void 0 ? { value: sizeValue } : {};
|
|
45862
46469
|
if (pos.kind === "coords") {
|
|
45863
46470
|
const id = alias ? fold(alias) : `@${pos.lat},${pos.lon}`;
|
|
45864
|
-
if (
|
|
46471
|
+
if (looksUS(pos.lat, pos.lon)) anyUsPoi = true;
|
|
46472
|
+
else if (!looksNorthAmericaNeighbor(pos.lat, pos.lon)) anyNonNaPoi = true;
|
|
45865
46473
|
if (!registry.has(id)) {
|
|
45866
46474
|
registerPoi(
|
|
45867
46475
|
id,
|
|
@@ -45884,7 +46492,7 @@ function resolveMap(parsed, data) {
|
|
|
45884
46492
|
if (registry.has(f)) return f;
|
|
45885
46493
|
const aliased = declaredByName.get(f);
|
|
45886
46494
|
if (aliased) return aliased;
|
|
45887
|
-
const got = lookupName(pos.name, pos.scope, line12,
|
|
46495
|
+
const got = lookupName(pos.name, pos.scope, line12, inferredScope, true);
|
|
45888
46496
|
if (got.kind !== "ok") return null;
|
|
45889
46497
|
noteCountry(got.iso);
|
|
45890
46498
|
registerPoi(
|
|
@@ -45941,9 +46549,12 @@ function resolveMap(parsed, data) {
|
|
|
45941
46549
|
}
|
|
45942
46550
|
routes.push({ stopIds, legs, lineNumber: rt.lineNumber });
|
|
45943
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;
|
|
45944
46556
|
const subdivisions = [];
|
|
45945
|
-
if (usSubdivisionReferenced ||
|
|
45946
|
-
subdivisions.push("us-states");
|
|
46557
|
+
if (usSubdivisionReferenced || usOriented) subdivisions.push("us-states");
|
|
45947
46558
|
const regionBoxes = [];
|
|
45948
46559
|
for (const ref of referencedRegionIds) {
|
|
45949
46560
|
const bb = featureBbox(data.usStates, ref.id);
|
|
@@ -45951,7 +46562,7 @@ function resolveMap(parsed, data) {
|
|
|
45951
46562
|
}
|
|
45952
46563
|
for (const r of regions) {
|
|
45953
46564
|
if (r.layer === "country") {
|
|
45954
|
-
const bb =
|
|
46565
|
+
const bb = featureBboxPrimary(data.worldCoarse, r.iso);
|
|
45955
46566
|
if (bb) regionBoxes.push(bb);
|
|
45956
46567
|
}
|
|
45957
46568
|
}
|
|
@@ -45961,23 +46572,56 @@ function resolveMap(parsed, data) {
|
|
|
45961
46572
|
[-180, -85],
|
|
45962
46573
|
[180, 85]
|
|
45963
46574
|
];
|
|
45964
|
-
|
|
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
|
+
}
|
|
45965
46612
|
const lonSpan = extent2[1][0] - extent2[0][0];
|
|
45966
46613
|
const latSpan = extent2[1][1] - extent2[0][1];
|
|
45967
46614
|
const span = Math.max(lonSpan, latSpan);
|
|
45968
|
-
const
|
|
46615
|
+
const maxAbsLat = Math.max(Math.abs(extent2[0][1]), Math.abs(extent2[1][1]));
|
|
45969
46616
|
let projection;
|
|
45970
|
-
|
|
45971
|
-
|
|
45972
|
-
|
|
45973
|
-
} else if (usDominant) {
|
|
46617
|
+
if (isPoiOnly && usOriented && lonSpan < US_NATIONAL_LON_SPAN) {
|
|
46618
|
+
projection = "mercator";
|
|
46619
|
+
} else if (usOriented) {
|
|
45974
46620
|
projection = "albers-usa";
|
|
45975
|
-
} else if (span > WORLD_SPAN) {
|
|
46621
|
+
} else if (span > WORLD_SPAN || maxAbsLat > MERCATOR_MAX_LAT) {
|
|
45976
46622
|
projection = "equirectangular";
|
|
45977
|
-
} else if (span < MERCATOR_MAX_SPAN) {
|
|
45978
|
-
projection = "mercator";
|
|
45979
46623
|
} else {
|
|
45980
|
-
projection = "
|
|
46624
|
+
projection = "mercator";
|
|
45981
46625
|
}
|
|
45982
46626
|
if (lonSpan >= 180) {
|
|
45983
46627
|
extent2 = [
|
|
@@ -45990,11 +46634,20 @@ function resolveMap(parsed, data) {
|
|
|
45990
46634
|
result.edges = edges;
|
|
45991
46635
|
result.routes = routes;
|
|
45992
46636
|
result.basemaps = {
|
|
45993
|
-
|
|
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",
|
|
45994
46646
|
subdivisions
|
|
45995
46647
|
};
|
|
45996
46648
|
result.extent = extent2;
|
|
45997
46649
|
result.projection = projection;
|
|
46650
|
+
result.poiFrameContainers = containerRegionIds;
|
|
45998
46651
|
result.error = parsed.error ?? firstError(diagnostics);
|
|
45999
46652
|
return result;
|
|
46000
46653
|
}
|
|
@@ -46031,17 +46684,20 @@ function firstError(diags) {
|
|
|
46031
46684
|
const e = diags.find((d) => d.severity === "error");
|
|
46032
46685
|
return e ? formatDgmoError(e) : null;
|
|
46033
46686
|
}
|
|
46034
|
-
var WORLD_SPAN,
|
|
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;
|
|
46035
46688
|
var init_resolver2 = __esm({
|
|
46036
46689
|
"src/map/resolver.ts"() {
|
|
46037
46690
|
"use strict";
|
|
46038
46691
|
init_diagnostics();
|
|
46039
46692
|
init_geo();
|
|
46040
46693
|
WORLD_SPAN = 90;
|
|
46041
|
-
|
|
46694
|
+
MERCATOR_MAX_LAT = 80;
|
|
46042
46695
|
PAD_FRACTION = 0.05;
|
|
46696
|
+
REGION_PAD_FRACTION = 0.12;
|
|
46043
46697
|
WORLD_LAT_SOUTH = -58;
|
|
46044
46698
|
WORLD_LAT_NORTH = 78;
|
|
46699
|
+
POI_ZOOM_FLOOR_DEG = 7;
|
|
46700
|
+
US_NATIONAL_LON_SPAN = 48;
|
|
46045
46701
|
REGION_ALIASES = {
|
|
46046
46702
|
// Common everyday names → the Natural-Earth display name actually shipped.
|
|
46047
46703
|
"united states": "united states of america",
|
|
@@ -46119,112 +46775,269 @@ var init_resolver2 = __esm({
|
|
|
46119
46775
|
}
|
|
46120
46776
|
});
|
|
46121
46777
|
|
|
46122
|
-
// src/map/
|
|
46123
|
-
|
|
46124
|
-
|
|
46125
|
-
|
|
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
|
+
}
|
|
46126
46800
|
});
|
|
46127
|
-
|
|
46128
|
-
|
|
46129
|
-
|
|
46130
|
-
|
|
46131
|
-
|
|
46132
|
-
|
|
46133
|
-
return
|
|
46134
|
-
}
|
|
46135
|
-
|
|
46136
|
-
|
|
46137
|
-
|
|
46138
|
-
|
|
46139
|
-
|
|
46140
|
-
|
|
46141
|
-
|
|
46142
|
-
|
|
46143
|
-
|
|
46144
|
-
|
|
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]);
|
|
46145
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 };
|
|
46146
46861
|
}
|
|
46147
|
-
|
|
46148
|
-
`map data assets not found near ${baseDir} (looked in ${CANDIDATE_DIRS.join(", ")}). Run \`pnpm build:map-data\` and \`pnpm build\`.`
|
|
46149
|
-
);
|
|
46862
|
+
return best?.lines ?? [text];
|
|
46150
46863
|
}
|
|
46151
|
-
function
|
|
46152
|
-
const
|
|
46153
|
-
|
|
46154
|
-
|
|
46155
|
-
}
|
|
46156
|
-
return data;
|
|
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 };
|
|
46157
46868
|
}
|
|
46158
|
-
function
|
|
46159
|
-
|
|
46160
|
-
const url = import_meta.url;
|
|
46161
|
-
if (url) return nb.dirname(nb.fileURLToPath(url));
|
|
46162
|
-
} catch {
|
|
46163
|
-
}
|
|
46164
|
-
if (typeof __dirname !== "undefined") return __dirname;
|
|
46165
|
-
return process.cwd();
|
|
46869
|
+
function rectFits(r, width, height) {
|
|
46870
|
+
return r.x >= 0 && r.y >= 0 && r.x + r.w <= width && r.y + r.h <= height;
|
|
46166
46871
|
}
|
|
46167
|
-
function
|
|
46168
|
-
|
|
46169
|
-
|
|
46170
|
-
|
|
46171
|
-
|
|
46172
|
-
|
|
46173
|
-
|
|
46174
|
-
|
|
46175
|
-
|
|
46176
|
-
|
|
46177
|
-
|
|
46178
|
-
|
|
46179
|
-
|
|
46180
|
-
|
|
46181
|
-
|
|
46182
|
-
|
|
46183
|
-
|
|
46184
|
-
|
|
46185
|
-
|
|
46186
|
-
|
|
46187
|
-
|
|
46188
|
-
|
|
46189
|
-
|
|
46190
|
-
|
|
46191
|
-
|
|
46192
|
-
|
|
46193
|
-
|
|
46194
|
-
|
|
46195
|
-
|
|
46196
|
-
|
|
46197
|
-
|
|
46198
|
-
|
|
46199
|
-
|
|
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]
|
|
46200
46946
|
});
|
|
46201
|
-
}
|
|
46202
|
-
|
|
46203
|
-
|
|
46204
|
-
|
|
46205
|
-
|
|
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;
|
|
46206
47017
|
}
|
|
46207
|
-
var
|
|
46208
|
-
var
|
|
46209
|
-
"src/map/
|
|
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"() {
|
|
46210
47021
|
"use strict";
|
|
46211
|
-
|
|
46212
|
-
|
|
46213
|
-
|
|
46214
|
-
|
|
46215
|
-
|
|
46216
|
-
|
|
46217
|
-
|
|
46218
|
-
|
|
46219
|
-
|
|
46220
|
-
|
|
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
|
|
46221
47040
|
};
|
|
46222
|
-
CANDIDATE_DIRS = [
|
|
46223
|
-
"./data",
|
|
46224
|
-
"./map-data",
|
|
46225
|
-
"../map-data",
|
|
46226
|
-
"../src/map/data"
|
|
46227
|
-
];
|
|
46228
47041
|
}
|
|
46229
47042
|
});
|
|
46230
47043
|
|
|
@@ -46233,12 +47046,34 @@ function geomObject2(topo) {
|
|
|
46233
47046
|
const key = Object.keys(topo.objects)[0];
|
|
46234
47047
|
return topo.objects[key];
|
|
46235
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
|
+
}
|
|
46236
47065
|
function decodeLayer(topo) {
|
|
47066
|
+
const cached = decodeCache.get(topo);
|
|
47067
|
+
if (cached) return cached;
|
|
46237
47068
|
const out = /* @__PURE__ */ new Map();
|
|
46238
47069
|
for (const g of geomObject2(topo).geometries) {
|
|
46239
47070
|
const f = (0, import_topojson_client2.feature)(topo, g);
|
|
46240
|
-
|
|
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);
|
|
46241
47075
|
}
|
|
47076
|
+
decodeCache.set(topo, out);
|
|
46242
47077
|
return out;
|
|
46243
47078
|
}
|
|
46244
47079
|
function projectionFor(family) {
|
|
@@ -46247,38 +47082,35 @@ function projectionFor(family) {
|
|
|
46247
47082
|
return usConusProjection();
|
|
46248
47083
|
case "mercator":
|
|
46249
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)();
|
|
46250
47089
|
case "natural-earth":
|
|
46251
47090
|
return (0, import_d3_geo2.geoNaturalEarth1)();
|
|
46252
|
-
case "equirectangular":
|
|
46253
47091
|
default:
|
|
46254
47092
|
return (0, import_d3_geo2.geoEquirectangular)();
|
|
46255
47093
|
}
|
|
46256
47094
|
}
|
|
46257
|
-
function mapBackgroundColor(palette, isDark = false,
|
|
46258
|
-
|
|
46259
|
-
|
|
46260
|
-
|
|
46261
|
-
|
|
46262
|
-
|
|
46263
|
-
);
|
|
46264
|
-
return mix(palette.colors.blue, palette.bg, WATER_TINT);
|
|
47095
|
+
function mapBackgroundColor(palette, isDark = false, _dataActive = false) {
|
|
47096
|
+
return mix(
|
|
47097
|
+
palette.colors.blue,
|
|
47098
|
+
palette.bg,
|
|
47099
|
+
isDark ? WATER_TINT_DARK : WATER_TINT_LIGHT
|
|
47100
|
+
);
|
|
46265
47101
|
}
|
|
46266
|
-
function mapNeutralLandColor(palette, isDark,
|
|
46267
|
-
if (dataActive)
|
|
46268
|
-
return isDark ? mix(palette.colors.gray, palette.bg, MUTED_LAND_DARK) : palette.bg;
|
|
47102
|
+
function mapNeutralLandColor(palette, isDark, _dataActive = false) {
|
|
46269
47103
|
return mix(
|
|
46270
47104
|
palette.colors.green,
|
|
46271
47105
|
palette.bg,
|
|
46272
47106
|
isDark ? LAND_TINT_DARK : LAND_TINT_LIGHT
|
|
46273
47107
|
);
|
|
46274
47108
|
}
|
|
46275
|
-
function
|
|
46276
|
-
const { palette, isDark } = opts;
|
|
46277
|
-
const { width, height } = size;
|
|
47109
|
+
function buildMapProjection(resolved, data) {
|
|
46278
47110
|
const wantsUsStates = resolved.basemaps.subdivisions.includes("us-states");
|
|
46279
|
-
const usCrisp = resolved.projection === "albers-usa" && wantsUsStates && !!data.naLand;
|
|
47111
|
+
const usCrisp = (resolved.projection === "albers-usa" || resolved.projection === "mercator") && wantsUsStates && !!data.naLand;
|
|
46280
47112
|
const worldTopo = usCrisp ? data.worldDetail : resolved.basemaps.world === "detail" ? data.worldDetail : data.worldCoarse;
|
|
46281
|
-
const worldLayer = decodeLayer(worldTopo);
|
|
47113
|
+
const worldLayer = new Map(decodeLayer(worldTopo));
|
|
46282
47114
|
if (usCrisp && data.naLand) {
|
|
46283
47115
|
const [nbW, nbS, nbE, nbN] = [-140, 10, -52, 66];
|
|
46284
47116
|
const crisp = decodeLayer(data.naLand);
|
|
@@ -46287,17 +47119,110 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46287
47119
|
if (!base) continue;
|
|
46288
47120
|
const [[bw, bs], [be, bn]] = (0, import_d3_geo2.geoBounds)(base);
|
|
46289
47121
|
if (bw >= nbW && be <= nbE && bs >= nbS && bn <= nbN)
|
|
46290
|
-
worldLayer.set(iso, cf);
|
|
47122
|
+
worldLayer.set(iso, { ...cf, properties: base.properties });
|
|
46291
47123
|
}
|
|
46292
47124
|
}
|
|
46293
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);
|
|
46294
47219
|
const usContext = usLayer !== null;
|
|
46295
47220
|
const regionStroke = isDark ? mix(palette.bg, palette.text, 78) : mix(palette.text, palette.bg, 78);
|
|
46296
47221
|
const values = resolved.regions.filter((r) => r.value !== void 0).map((r) => r.value);
|
|
46297
|
-
const
|
|
46298
|
-
const rampMin =
|
|
46299
|
-
const rampMax =
|
|
46300
|
-
const rampHue = palette.colors.red;
|
|
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);
|
|
47225
|
+
const rampHue = resolveColor(resolved.directives.regionMetricColor ?? "", palette) ?? palette.colors.red;
|
|
46301
47226
|
const hasRamp = values.length > 0;
|
|
46302
47227
|
const VALUE_NAME = hasRamp ? resolved.directives.regionMetric?.trim() || "Value" : null;
|
|
46303
47228
|
const matchColorGroup = (v) => {
|
|
@@ -46317,14 +47242,48 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46317
47242
|
activeGroup = VALUE_NAME ?? (resolved.tagGroups.length > 0 ? resolved.tagGroups[0].name : null);
|
|
46318
47243
|
}
|
|
46319
47244
|
const activeIsScore = VALUE_NAME !== null && activeGroup === VALUE_NAME;
|
|
46320
|
-
const mutedBasemap =
|
|
47245
|
+
const mutedBasemap = activeGroup !== null;
|
|
46321
47246
|
const neutralFill = mapNeutralLandColor(palette, isDark, mutedBasemap);
|
|
46322
47247
|
const water = mapBackgroundColor(palette, isDark, mutedBasemap);
|
|
47248
|
+
const lakeStroke = mix(regionStroke, water, 45);
|
|
46323
47249
|
const foreignFill = mix(
|
|
46324
47250
|
palette.colors.gray,
|
|
46325
47251
|
palette.bg,
|
|
46326
47252
|
mutedBasemap ? isDark ? MUTED_FOREIGN_DARK : MUTED_FOREIGN_LIGHT : isDark ? FOREIGN_TINT_DARK : FOREIGN_TINT_LIGHT
|
|
46327
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);
|
|
46328
47287
|
const rampBase = isDark ? mix(palette.surface, palette.text, 28) : palette.bg;
|
|
46329
47288
|
const fillForValue = (s) => {
|
|
46330
47289
|
const t = rampMax > rampMin ? (s - rampMin) / (rampMax - rampMin) : 1;
|
|
@@ -46349,47 +47308,26 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46349
47308
|
isDark ? TAG_TINT_DARK : TAG_TINT_LIGHT
|
|
46350
47309
|
);
|
|
46351
47310
|
};
|
|
47311
|
+
const directFill = (name) => {
|
|
47312
|
+
const hex = name ? resolveColor(name, palette) : null;
|
|
47313
|
+
if (!hex) return null;
|
|
47314
|
+
return mix(hex, palette.bg, isDark ? TAG_TINT_DARK : TAG_TINT_LIGHT);
|
|
47315
|
+
};
|
|
46352
47316
|
const regionFill = (r) => {
|
|
47317
|
+
const direct = directFill(r.color);
|
|
47318
|
+
if (direct) return direct;
|
|
46353
47319
|
if (activeIsScore) {
|
|
46354
47320
|
return r.value !== void 0 ? fillForValue(r.value) : neutralFill;
|
|
46355
47321
|
}
|
|
47322
|
+
if (colorizeActive) return (r.iso && colorByIso.get(r.iso)) ?? neutralFill;
|
|
46356
47323
|
return tagFill(r.tags, activeGroup) ?? neutralFill;
|
|
46357
47324
|
};
|
|
46358
47325
|
const regionById = new Map(resolved.regions.map((r) => [r.iso, r]));
|
|
46359
|
-
const
|
|
46360
|
-
const [[w, s], [e, n]] = resolved.extent;
|
|
46361
|
-
const N = 16;
|
|
46362
|
-
const coords = [];
|
|
46363
|
-
for (let i = 0; i <= N; i++) {
|
|
46364
|
-
const t = i / N;
|
|
46365
|
-
const lon = w + (e - w) * t;
|
|
46366
|
-
const lat = s + (n - s) * t;
|
|
46367
|
-
coords.push([lon, s], [lon, n], [w, lat], [e, lat]);
|
|
46368
|
-
}
|
|
46369
|
-
return {
|
|
46370
|
-
type: "Feature",
|
|
46371
|
-
properties: {},
|
|
46372
|
-
geometry: { type: "MultiPoint", coordinates: coords }
|
|
46373
|
-
};
|
|
46374
|
-
};
|
|
46375
|
-
let fitFeatures;
|
|
46376
|
-
if (resolved.projection === "albers-usa" && usLayer) {
|
|
46377
|
-
fitFeatures = [...usLayer.entries()].filter(([iso]) => !US_NON_CONUS.has(iso)).map(([, f]) => f);
|
|
46378
|
-
} else {
|
|
46379
|
-
fitFeatures = [extentOutline()];
|
|
46380
|
-
}
|
|
46381
|
-
const fitTarget = { type: "FeatureCollection", features: fitFeatures };
|
|
46382
|
-
const projection = projectionFor(resolved.projection);
|
|
46383
|
-
if (resolved.projection !== "albers-usa") {
|
|
46384
|
-
let centerLon = (resolved.extent[0][0] + resolved.extent[1][0]) / 2;
|
|
46385
|
-
if (centerLon > 180) centerLon -= 360;
|
|
46386
|
-
projection.rotate([-centerLon, 0]);
|
|
46387
|
-
}
|
|
46388
|
-
const TITLE_GAP = 16;
|
|
47326
|
+
const TITLE_GAP2 = 16;
|
|
46389
47327
|
let topPad = FIT_PAD;
|
|
46390
47328
|
if (resolved.title && resolved.pois.length > 0) {
|
|
46391
47329
|
const bannerBottom = (resolved.subtitle ? TITLE_Y + TITLE_FONT_SIZE : TITLE_Y) + TITLE_FONT_SIZE / 2;
|
|
46392
|
-
topPad = Math.max(FIT_PAD, bannerBottom +
|
|
47330
|
+
topPad = Math.max(FIT_PAD, bannerBottom + TITLE_GAP2);
|
|
46393
47331
|
}
|
|
46394
47332
|
const fitBox = [
|
|
46395
47333
|
[FIT_PAD, topPad],
|
|
@@ -46399,11 +47337,10 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46399
47337
|
]
|
|
46400
47338
|
];
|
|
46401
47339
|
projection.fitExtent(fitBox, fitTarget);
|
|
46402
|
-
const fitGB = (0, import_d3_geo2.geoBounds)(fitTarget);
|
|
46403
|
-
const fitIsGlobal = fitGB[1][0] - fitGB[0][0] >= 270 || fitGB[1][1] - fitGB[0][1] >= 130;
|
|
46404
47340
|
let path;
|
|
46405
47341
|
let project;
|
|
46406
|
-
|
|
47342
|
+
let stretchParams = null;
|
|
47343
|
+
if (fitIsGlobal && !opts.preferContain) {
|
|
46407
47344
|
const cb = (0, import_d3_geo2.geoPath)(projection).bounds(fitTarget);
|
|
46408
47345
|
const bx0 = cb[0][0];
|
|
46409
47346
|
const by0 = cb[0][1];
|
|
@@ -46413,6 +47350,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46413
47350
|
const oy = fitBox[0][1];
|
|
46414
47351
|
const sx = cw > 0 ? (fitBox[1][0] - ox) / cw : 1;
|
|
46415
47352
|
const sy = ch > 0 ? (fitBox[1][1] - oy) / ch : 1;
|
|
47353
|
+
stretchParams = { sx, sy, ox, oy, bx0, by0 };
|
|
46416
47354
|
const stretch = (x, y) => [
|
|
46417
47355
|
ox + (x - bx0) * sx,
|
|
46418
47356
|
oy + (y - by0) * sy
|
|
@@ -46444,7 +47382,9 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46444
47382
|
const insets = [];
|
|
46445
47383
|
const insetRegions = [];
|
|
46446
47384
|
const insetLabelSeeds = [];
|
|
46447
|
-
|
|
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)) {
|
|
46448
47388
|
const PAD = 8;
|
|
46449
47389
|
const GAP = 12;
|
|
46450
47390
|
const yB = height - FIT_PAD;
|
|
@@ -46475,38 +47415,14 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46475
47415
|
}
|
|
46476
47416
|
return y;
|
|
46477
47417
|
};
|
|
46478
|
-
const
|
|
47418
|
+
const coastFloor = (x0, xr) => {
|
|
46479
47419
|
const n = 24;
|
|
46480
|
-
const pts = [];
|
|
46481
47420
|
let maxY = -Infinity;
|
|
46482
47421
|
for (let i = 0; i <= n; i++) {
|
|
46483
|
-
const
|
|
46484
|
-
|
|
46485
|
-
|
|
46486
|
-
|
|
46487
|
-
if (y > maxY) maxY = y;
|
|
46488
|
-
}
|
|
46489
|
-
}
|
|
46490
|
-
if (pts.length === 0) return () => yB - height * 0.42;
|
|
46491
|
-
let m = 0;
|
|
46492
|
-
if (pts.length >= 2) {
|
|
46493
|
-
let sx = 0, sy = 0, sxx = 0, sxy = 0;
|
|
46494
|
-
for (const [x, y] of pts) {
|
|
46495
|
-
sx += x;
|
|
46496
|
-
sy += y;
|
|
46497
|
-
sxx += x * x;
|
|
46498
|
-
sxy += x * y;
|
|
46499
|
-
}
|
|
46500
|
-
const den = pts.length * sxx - sx * sx;
|
|
46501
|
-
if (den !== 0) m = (pts.length * sxy - sx * sy) / den;
|
|
46502
|
-
}
|
|
46503
|
-
m = Math.max(-0.35, Math.min(0.35, m));
|
|
46504
|
-
let c = -Infinity;
|
|
46505
|
-
for (const [x, y] of pts) {
|
|
46506
|
-
const need = y - m * x + GAP;
|
|
46507
|
-
if (need > c) c = need;
|
|
46508
|
-
}
|
|
46509
|
-
return (x) => m * x + c;
|
|
47422
|
+
const y = at(x0 + (xr - x0) * i / n);
|
|
47423
|
+
if (y > maxY) maxY = y;
|
|
47424
|
+
}
|
|
47425
|
+
return maxY;
|
|
46510
47426
|
};
|
|
46511
47427
|
const placeInset = (iso, proj, boxX, iwReq) => {
|
|
46512
47428
|
const f = usLayer.get(iso);
|
|
@@ -46515,19 +47431,15 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46515
47431
|
const iw = Math.min(iwReq, width - FIT_PAD - x0 - 2 * PAD);
|
|
46516
47432
|
if (iw < 24) return boxX;
|
|
46517
47433
|
const xr = x0 + iw + 2 * PAD;
|
|
46518
|
-
const
|
|
46519
|
-
const
|
|
46520
|
-
const yR = top(xr);
|
|
47434
|
+
const floor = coastFloor(x0, xr);
|
|
47435
|
+
const topGuess = floor > -Infinity ? floor + GAP : yB - height * 0.42;
|
|
46521
47436
|
proj.fitWidth(iw, f);
|
|
46522
47437
|
const bb = (0, import_d3_geo2.geoPath)(proj).bounds(f);
|
|
46523
47438
|
const sh = Number.isFinite(bb[0][0]) ? bb[1][1] - bb[0][1] : iw;
|
|
46524
47439
|
const needH = sh + 2 * PAD;
|
|
46525
|
-
let topFit =
|
|
47440
|
+
let topFit = topGuess;
|
|
46526
47441
|
const bottom = Math.min(topFit + needH, yB);
|
|
46527
47442
|
if (bottom - topFit < needH) topFit = bottom - needH;
|
|
46528
|
-
const lift = topFit - Math.max(yL, yR);
|
|
46529
|
-
const topL = yL + lift;
|
|
46530
|
-
const topR = yR + lift;
|
|
46531
47443
|
proj.fitExtent(
|
|
46532
47444
|
[
|
|
46533
47445
|
[x0 + PAD, topFit + PAD],
|
|
@@ -46537,8 +47449,18 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46537
47449
|
);
|
|
46538
47450
|
const d = (0, import_d3_geo2.geoPath)(proj)(f) ?? "";
|
|
46539
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
|
+
}
|
|
46540
47462
|
const r = regionById.get(iso);
|
|
46541
|
-
let fill2 = neutralFill;
|
|
47463
|
+
let fill2 = colorizeActive ? colorByIso.get(iso) ?? neutralFill : neutralFill;
|
|
46542
47464
|
let lineNumber = -1;
|
|
46543
47465
|
if (r?.layer === "us-state") {
|
|
46544
47466
|
fill2 = regionFill(r);
|
|
@@ -46546,21 +47468,25 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46546
47468
|
}
|
|
46547
47469
|
insets.push({
|
|
46548
47470
|
x: x0,
|
|
46549
|
-
y:
|
|
47471
|
+
y: topFit,
|
|
46550
47472
|
w: xr - x0,
|
|
46551
|
-
h: bottom -
|
|
47473
|
+
h: bottom - topFit,
|
|
46552
47474
|
points: [
|
|
46553
|
-
[x0,
|
|
46554
|
-
[xr,
|
|
47475
|
+
[x0, topFit],
|
|
47476
|
+
[xr, topFit],
|
|
46555
47477
|
[xr, bottom],
|
|
46556
47478
|
[x0, bottom]
|
|
46557
|
-
]
|
|
47479
|
+
],
|
|
47480
|
+
// The FITTED inset projection (just fit to this box) — captured so the
|
|
47481
|
+
// geo-query can invert pixels inside the frame back to AK/HI coords.
|
|
47482
|
+
projection: proj,
|
|
47483
|
+
...contextLand && { contextLand }
|
|
46558
47484
|
});
|
|
46559
47485
|
insetRegions.push({
|
|
46560
47486
|
id: iso,
|
|
46561
47487
|
d,
|
|
46562
47488
|
fill: fill2,
|
|
46563
|
-
stroke: regionStroke,
|
|
47489
|
+
stroke: colorizeActive ? colorizeStroke(fill2) : regionStroke,
|
|
46564
47490
|
lineNumber,
|
|
46565
47491
|
layer: "us-state",
|
|
46566
47492
|
...r?.value !== void 0 && { value: r.value },
|
|
@@ -46573,13 +47499,16 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46573
47499
|
}
|
|
46574
47500
|
return xr;
|
|
46575
47501
|
};
|
|
46576
|
-
|
|
46577
|
-
|
|
46578
|
-
alaskaProjection(),
|
|
46579
|
-
|
|
46580
|
-
|
|
46581
|
-
|
|
46582
|
-
|
|
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
|
+
);
|
|
46583
47512
|
}
|
|
46584
47513
|
const conusFit = resolved.projection === "albers-usa" && !!usLayer;
|
|
46585
47514
|
const classifyExtent = conusFit ? (0, import_d3_geo2.geoBounds)(fitTarget) : resolved.extent;
|
|
@@ -46595,15 +47524,24 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46595
47524
|
};
|
|
46596
47525
|
const ringOverlapsView = (ring) => {
|
|
46597
47526
|
let loMin = Infinity, loMax = -Infinity, rawMin = Infinity, rawMax = -Infinity;
|
|
47527
|
+
const lons = [];
|
|
46598
47528
|
for (const [rawLon] of ring) {
|
|
46599
47529
|
const lon = normLon(rawLon);
|
|
47530
|
+
lons.push(lon);
|
|
46600
47531
|
if (lon < loMin) loMin = lon;
|
|
46601
47532
|
if (lon > loMax) loMax = lon;
|
|
46602
47533
|
if (rawLon < rawMin) rawMin = rawLon;
|
|
46603
47534
|
if (rawLon > rawMax) rawMax = rawLon;
|
|
46604
47535
|
}
|
|
46605
|
-
|
|
46606
|
-
|
|
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;
|
|
46607
47545
|
let px0 = Infinity, py0 = Infinity, px1 = -Infinity, py1 = -Infinity, anyFinite = false;
|
|
46608
47546
|
for (const [lon, lat] of ring) {
|
|
46609
47547
|
const p = project(lon, lat);
|
|
@@ -46676,7 +47614,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46676
47614
|
const regions = [];
|
|
46677
47615
|
const pushRegionLayer = (layerFeatures, layerKind, shouldCull) => {
|
|
46678
47616
|
for (const [iso, f] of layerFeatures) {
|
|
46679
|
-
if (layerKind === "us-state" && usContext && INSET_STATES.has(iso))
|
|
47617
|
+
if (layerKind === "us-state" && usContext && resolved.projection === "albers-usa" && INSET_STATES.has(iso))
|
|
46680
47618
|
continue;
|
|
46681
47619
|
if (layerKind === "country" && usContext && iso === "US") continue;
|
|
46682
47620
|
if (layerKind === "country" && iso === "AQ" && !regionById.has("AQ"))
|
|
@@ -46688,7 +47626,8 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46688
47626
|
if (!d) continue;
|
|
46689
47627
|
const isThisLayer = r?.layer === layerKind;
|
|
46690
47628
|
const isForeign = layerKind === "country" && usContext && iso !== "US";
|
|
46691
|
-
|
|
47629
|
+
const baseFill = isForeign ? foreignFill : neutralFill;
|
|
47630
|
+
let fill2 = colorizeActive ? colorByIso.get(iso) ?? baseFill : baseFill;
|
|
46692
47631
|
let label;
|
|
46693
47632
|
let lineNumber = -1;
|
|
46694
47633
|
let layer = "base";
|
|
@@ -46697,12 +47636,14 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46697
47636
|
lineNumber = r.lineNumber;
|
|
46698
47637
|
layer = layerKind;
|
|
46699
47638
|
label = r.name;
|
|
47639
|
+
} else {
|
|
47640
|
+
label = f.properties?.name;
|
|
46700
47641
|
}
|
|
46701
47642
|
regions.push({
|
|
46702
47643
|
id: iso,
|
|
46703
47644
|
d,
|
|
46704
47645
|
fill: fill2,
|
|
46705
|
-
stroke: regionStroke,
|
|
47646
|
+
stroke: colorizeActive ? colorizeStroke(fill2) : regionStroke,
|
|
46706
47647
|
lineNumber,
|
|
46707
47648
|
layer,
|
|
46708
47649
|
...label !== void 0 && { label },
|
|
@@ -46724,13 +47665,88 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46724
47665
|
id: "lake",
|
|
46725
47666
|
d,
|
|
46726
47667
|
fill: water,
|
|
46727
|
-
stroke:
|
|
47668
|
+
stroke: lakeStroke,
|
|
46728
47669
|
lineNumber: -1,
|
|
46729
47670
|
layer: "base"
|
|
46730
47671
|
});
|
|
46731
47672
|
}
|
|
46732
47673
|
}
|
|
46733
|
-
const
|
|
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;
|
|
47706
|
+
const relief = [];
|
|
47707
|
+
let reliefHatch = null;
|
|
47708
|
+
if (reliefAllowed && data.mountainRanges) {
|
|
47709
|
+
for (const [, f] of decodeLayer(data.mountainRanges)) {
|
|
47710
|
+
const viewF = isGlobalView ? dropFrameFillers(f) : cullFeatureToView(f);
|
|
47711
|
+
if (!viewF) continue;
|
|
47712
|
+
const area2 = path.area(viewF);
|
|
47713
|
+
if (!Number.isFinite(area2) || area2 < RELIEF_MIN_AREA) continue;
|
|
47714
|
+
const box = path.bounds(viewF);
|
|
47715
|
+
if (box[1][0] - box[0][0] < RELIEF_MIN_DIM || box[1][1] - box[0][1] < RELIEF_MIN_DIM)
|
|
47716
|
+
continue;
|
|
47717
|
+
const d = path(viewF) ?? "";
|
|
47718
|
+
if (!d) continue;
|
|
47719
|
+
relief.push({ d });
|
|
47720
|
+
}
|
|
47721
|
+
if (relief.length) {
|
|
47722
|
+
const darkTone = isDark ? palette.bg : palette.text;
|
|
47723
|
+
const lightTone = isDark ? palette.text : palette.bg;
|
|
47724
|
+
const reliefLandRef = colorizeActive ? isDark ? palette.surface : palette.bg : neutralFill;
|
|
47725
|
+
const landLum = relativeLuminance(reliefLandRef);
|
|
47726
|
+
const tone = Math.abs(landLum - relativeLuminance(darkTone)) > 0.04 ? darkTone : lightTone;
|
|
47727
|
+
reliefHatch = {
|
|
47728
|
+
color: mix(tone, reliefLandRef, RELIEF_HATCH_STRENGTH),
|
|
47729
|
+
spacing: RELIEF_HATCH_SPACING,
|
|
47730
|
+
width: RELIEF_HATCH_WIDTH
|
|
47731
|
+
};
|
|
47732
|
+
}
|
|
47733
|
+
}
|
|
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);
|
|
46734
47750
|
const rivers = [];
|
|
46735
47751
|
if (data.rivers) {
|
|
46736
47752
|
for (const [, f] of decodeLayer(data.rivers)) {
|
|
@@ -46751,6 +47767,9 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46751
47767
|
return R_MIN + Math.max(0, Math.min(1, t)) * (R_MAX - R_MIN);
|
|
46752
47768
|
};
|
|
46753
47769
|
const poiFill = (p) => {
|
|
47770
|
+
const directHex = p.color ? resolveColor(p.color, palette) : null;
|
|
47771
|
+
if (directHex)
|
|
47772
|
+
return { fill: directHex, stroke: mix(directHex, palette.text, 18) };
|
|
46754
47773
|
for (const group of resolved.tagGroups) {
|
|
46755
47774
|
const val = p.tags[group.name.toLowerCase()];
|
|
46756
47775
|
if (!val) continue;
|
|
@@ -46783,38 +47802,108 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46783
47802
|
const xy = project(p.lon, p.lat);
|
|
46784
47803
|
if (xy) projected.push({ p, xy });
|
|
46785
47804
|
}
|
|
46786
|
-
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);
|
|
46787
47834
|
for (const e of projected) {
|
|
46788
|
-
|
|
46789
|
-
|
|
46790
|
-
|
|
46791
|
-
|
|
46792
|
-
|
|
46793
|
-
|
|
46794
|
-
|
|
46795
|
-
|
|
46796
|
-
|
|
46797
|
-
|
|
46798
|
-
|
|
46799
|
-
|
|
46800
|
-
|
|
46801
|
-
|
|
46802
|
-
|
|
46803
|
-
|
|
46804
|
-
|
|
46805
|
-
|
|
46806
|
-
|
|
46807
|
-
|
|
46808
|
-
|
|
46809
|
-
|
|
46810
|
-
|
|
46811
|
-
|
|
46812
|
-
|
|
46813
|
-
|
|
46814
|
-
|
|
46815
|
-
|
|
46816
|
-
|
|
46817
|
-
|
|
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
|
|
46818
47907
|
});
|
|
46819
47908
|
}
|
|
46820
47909
|
const legs = [];
|
|
@@ -46864,16 +47953,26 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46864
47953
|
if (!a || !b) continue;
|
|
46865
47954
|
const mx = (a.cx + b.cx) / 2;
|
|
46866
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;
|
|
46867
47963
|
legs.push({
|
|
46868
|
-
d: legPath(a, b,
|
|
47964
|
+
d: legPath(a, b, bow.curved, bow.offset),
|
|
46869
47965
|
width: routeWidthFor(Number(leg.value)),
|
|
46870
47966
|
color: mix(palette.text, palette.bg, 72),
|
|
46871
47967
|
arrow: true,
|
|
46872
47968
|
lineNumber: leg.lineNumber,
|
|
46873
47969
|
...leg.label !== void 0 && {
|
|
46874
47970
|
label: leg.label,
|
|
46875
|
-
labelX:
|
|
46876
|
-
labelY:
|
|
47971
|
+
labelX: bow.labelX,
|
|
47972
|
+
labelY: bow.labelY,
|
|
47973
|
+
labelColor: routeLabelStyle.color,
|
|
47974
|
+
labelHalo: routeLabelStyle.halo,
|
|
47975
|
+
labelHaloColor: routeLabelStyle.haloColor
|
|
46877
47976
|
}
|
|
46878
47977
|
});
|
|
46879
47978
|
}
|
|
@@ -46901,20 +48000,29 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46901
48000
|
const a = poiScreen.get(e.fromId);
|
|
46902
48001
|
const b = poiScreen.get(e.toId);
|
|
46903
48002
|
if (!a || !b) return;
|
|
46904
|
-
const
|
|
46905
|
-
const offset = n > 1 ? (i - (n - 1) / 2) * FAN_STEP : 0;
|
|
48003
|
+
const fanOffset = n > 1 ? (i - (n - 1) / 2) * FAN_STEP : 0;
|
|
46906
48004
|
const mx = (a.cx + b.cx) / 2;
|
|
46907
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;
|
|
46908
48013
|
legs.push({
|
|
46909
|
-
d: legPath(a, b, curved, offset),
|
|
48014
|
+
d: legPath(a, b, bow.curved, bow.offset),
|
|
46910
48015
|
width: widthFor(e),
|
|
46911
48016
|
color: mix(palette.text, palette.bg, 66),
|
|
46912
48017
|
arrow: e.directed,
|
|
46913
48018
|
lineNumber: e.lineNumber,
|
|
46914
48019
|
...e.label !== void 0 && {
|
|
46915
48020
|
label: e.label,
|
|
46916
|
-
labelX:
|
|
46917
|
-
labelY:
|
|
48021
|
+
labelX: bow.labelX,
|
|
48022
|
+
labelY: bow.labelY,
|
|
48023
|
+
labelColor: edgeLabelStyle.color,
|
|
48024
|
+
labelHalo: edgeLabelStyle.halo,
|
|
48025
|
+
labelHaloColor: edgeLabelStyle.haloColor
|
|
46918
48026
|
}
|
|
46919
48027
|
});
|
|
46920
48028
|
});
|
|
@@ -46956,25 +48064,25 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46956
48064
|
}
|
|
46957
48065
|
}
|
|
46958
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));
|
|
46959
|
-
const
|
|
48067
|
+
const showRegionLabels = resolved.directives.noRegionLabels !== true;
|
|
48068
|
+
const isCompact = width < COMPACT_WIDTH_PX;
|
|
46960
48069
|
const LABEL_PADX = 6;
|
|
46961
48070
|
const LABEL_PADY = 3;
|
|
46962
|
-
const labelW = (text) => measureLegendText(text,
|
|
46963
|
-
const labelH =
|
|
48071
|
+
const labelW = (text) => measureLegendText(text, FONT2) + 2 * LABEL_PADX;
|
|
48072
|
+
const labelH = FONT2 + 2 * LABEL_PADY;
|
|
46964
48073
|
const pushRegionLabel = (x, y, text, fill2, lineNumber) => {
|
|
46965
|
-
const color =
|
|
46966
|
-
|
|
46967
|
-
|
|
46968
|
-
|
|
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
|
|
46969
48078
|
);
|
|
46970
|
-
const haloColor = color === palette.textOnFillLight ? palette.textOnFillDark : palette.textOnFillLight;
|
|
46971
48079
|
labels.push({
|
|
46972
48080
|
x,
|
|
46973
48081
|
y,
|
|
46974
48082
|
text,
|
|
46975
48083
|
anchor: "middle",
|
|
46976
48084
|
color,
|
|
46977
|
-
halo:
|
|
48085
|
+
halo: overflows,
|
|
46978
48086
|
haloColor,
|
|
46979
48087
|
lineNumber
|
|
46980
48088
|
});
|
|
@@ -46983,21 +48091,50 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46983
48091
|
US: [-98.5, 39.5]
|
|
46984
48092
|
// CONUS geographic centre (near Lebanon, Kansas)
|
|
46985
48093
|
};
|
|
46986
|
-
|
|
46987
|
-
|
|
46988
|
-
|
|
46989
|
-
|
|
46990
|
-
|
|
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;
|
|
46991
48108
|
const [[x0, y0], [x1, y1]] = path.bounds(f);
|
|
46992
|
-
const
|
|
46993
|
-
|
|
46994
|
-
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;
|
|
46995
48114
|
const c = anchor ? project(anchor[0], anchor[1]) : path.centroid(f);
|
|
46996
|
-
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));
|
|
46997
48134
|
pushRegionLabel(c[0], c[1], text, r.fill, r.lineNumber);
|
|
46998
48135
|
}
|
|
46999
48136
|
for (const seed of insetLabelSeeds) {
|
|
47000
|
-
const text =
|
|
48137
|
+
const text = isCompact ? seed.iso.replace(/^US-/, "") : seed.name;
|
|
47001
48138
|
const src = regionById.get(seed.iso);
|
|
47002
48139
|
pushRegionLabel(
|
|
47003
48140
|
seed.x,
|
|
@@ -47008,22 +48145,26 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47008
48145
|
);
|
|
47009
48146
|
}
|
|
47010
48147
|
}
|
|
47011
|
-
|
|
47012
|
-
|
|
47013
|
-
const ordered = [...pois].sort(
|
|
47014
|
-
(a, b) => a.lineNumber - b.lineNumber || (a.id < b.id ? -1 : 1)
|
|
47015
|
-
);
|
|
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));
|
|
47016
48150
|
const poiById = new Map(resolved.pois.map((q) => [q.id, q]));
|
|
47017
48151
|
const labelText = (p) => {
|
|
47018
48152
|
const src = poiById.get(p.id);
|
|
47019
48153
|
return src?.label ?? src?.name ?? p.id;
|
|
47020
48154
|
};
|
|
47021
|
-
const poiLabH =
|
|
48155
|
+
const poiLabH = FONT2 * 1.25;
|
|
47022
48156
|
const labelInfo = (p) => {
|
|
47023
48157
|
const text = labelText(p);
|
|
47024
|
-
return { text, w: measureLegendText(text,
|
|
48158
|
+
return { text, w: measureLegendText(text, FONT2) };
|
|
47025
48159
|
};
|
|
47026
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
|
+
}
|
|
47027
48168
|
const inlineRect = (p, w, side) => {
|
|
47028
48169
|
switch (side) {
|
|
47029
48170
|
case "right":
|
|
@@ -47053,11 +48194,11 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47053
48194
|
const x = side === "right" ? rect.x : side === "left" ? rect.x + w : p.cx;
|
|
47054
48195
|
labels.push({
|
|
47055
48196
|
x,
|
|
47056
|
-
y: rect.y + poiLabH / 2 +
|
|
48197
|
+
y: rect.y + poiLabH / 2 + FONT2 / 3,
|
|
47057
48198
|
text,
|
|
47058
48199
|
anchor,
|
|
47059
48200
|
color: palette.text,
|
|
47060
|
-
halo:
|
|
48201
|
+
halo: false,
|
|
47061
48202
|
haloColor: palette.bg,
|
|
47062
48203
|
poiId: p.id,
|
|
47063
48204
|
lineNumber: p.lineNumber
|
|
@@ -47068,43 +48209,60 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47068
48209
|
return rect.x >= 0 && rect.x + rect.w <= width && rect.y >= 0 && rect.y + rect.h <= height && !collides(rect);
|
|
47069
48210
|
};
|
|
47070
48211
|
const GROUP_R = 30;
|
|
47071
|
-
const
|
|
48212
|
+
const groups2 = [];
|
|
47072
48213
|
for (const p of ordered) {
|
|
47073
|
-
const near =
|
|
48214
|
+
const near = groups2.find(
|
|
47074
48215
|
(g) => g.some((q) => Math.hypot(q.cx - p.cx, q.cy - p.cy) < GROUP_R)
|
|
47075
48216
|
);
|
|
47076
48217
|
if (near) near.push(p);
|
|
47077
|
-
else
|
|
48218
|
+
else groups2.push([p]);
|
|
47078
48219
|
}
|
|
47079
48220
|
const ROW_GAP2 = 3;
|
|
47080
48221
|
const step = poiLabH + ROW_GAP2;
|
|
47081
48222
|
const COL_GAP = 16;
|
|
47082
|
-
const
|
|
47083
|
-
|
|
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) => {
|
|
47084
48225
|
const left = Math.min(...items.map((o) => o.p.cx - o.p.r));
|
|
47085
48226
|
const right = Math.max(...items.map((o) => o.p.cx + o.p.r));
|
|
47086
|
-
const cyMid = (Math.min(...items.map((o) => o.p.cy)) + Math.max(...items.map((o) => o.p.cy))) / 2;
|
|
47087
48227
|
const maxW = Math.max(...items.map((o) => o.w));
|
|
47088
|
-
const
|
|
47089
|
-
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);
|
|
47090
48230
|
const totalH = items.length * step;
|
|
47091
48231
|
let startY = cyMid - totalH / 2;
|
|
47092
48232
|
startY = Math.max(2, Math.min(startY, height - totalH - 2));
|
|
47093
|
-
items.
|
|
48233
|
+
return items.map((o, i) => {
|
|
47094
48234
|
const rowCy = startY + i * step + step / 2;
|
|
47095
|
-
|
|
47096
|
-
|
|
47097
|
-
|
|
47098
|
-
|
|
47099
|
-
|
|
47100
|
-
|
|
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);
|
|
47101
48259
|
labels.push({
|
|
47102
48260
|
x: colX,
|
|
47103
|
-
y: rowCy +
|
|
48261
|
+
y: rowCy + FONT2 / 3,
|
|
47104
48262
|
text: o.text,
|
|
47105
48263
|
anchor: side === "right" ? "start" : "end",
|
|
47106
48264
|
color: palette.text,
|
|
47107
|
-
halo:
|
|
48265
|
+
halo: false,
|
|
47108
48266
|
haloColor: palette.bg,
|
|
47109
48267
|
leader: {
|
|
47110
48268
|
x1: o.p.cx,
|
|
@@ -47114,24 +48272,141 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47114
48272
|
},
|
|
47115
48273
|
leaderColor: o.p.fill,
|
|
47116
48274
|
poiId: o.p.id,
|
|
47117
|
-
lineNumber: o.p.lineNumber
|
|
48275
|
+
lineNumber: o.p.lineNumber,
|
|
48276
|
+
...clusterId !== void 0 && { clusterMember: clusterId }
|
|
47118
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
|
|
47119
48300
|
});
|
|
47120
48301
|
};
|
|
47121
|
-
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);
|
|
47122
48312
|
if (g.length === 1) {
|
|
47123
|
-
const p =
|
|
47124
|
-
const { text, w } = labelInfo(p);
|
|
48313
|
+
const { p, text, w } = items[0];
|
|
47125
48314
|
const side = ["right", "left", "above", "below"].find(
|
|
47126
48315
|
(s) => inlineFits(p, w, s)
|
|
47127
48316
|
);
|
|
47128
|
-
if (side)
|
|
47129
|
-
|
|
47130
|
-
|
|
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;
|
|
47131
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
|
+
});
|
|
47132
48391
|
}
|
|
47133
|
-
placeColumn(g);
|
|
47134
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);
|
|
47135
48410
|
}
|
|
47136
48411
|
let legend = null;
|
|
47137
48412
|
if (!resolved.directives.noLegend) {
|
|
@@ -47166,24 +48441,35 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47166
48441
|
...resolved.caption !== void 0 && { caption: resolved.caption },
|
|
47167
48442
|
regions,
|
|
47168
48443
|
rivers,
|
|
48444
|
+
relief,
|
|
48445
|
+
reliefHatch,
|
|
48446
|
+
coastlineStyle,
|
|
47169
48447
|
legs,
|
|
47170
48448
|
pois,
|
|
48449
|
+
clusters,
|
|
47171
48450
|
labels,
|
|
47172
48451
|
legend,
|
|
47173
48452
|
insets,
|
|
47174
|
-
insetRegions
|
|
48453
|
+
insetRegions,
|
|
48454
|
+
projection,
|
|
48455
|
+
stretch: stretchParams,
|
|
48456
|
+
diagnostics: []
|
|
47175
48457
|
};
|
|
47176
48458
|
}
|
|
47177
|
-
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;
|
|
47178
48460
|
var init_layout15 = __esm({
|
|
47179
48461
|
"src/map/layout.ts"() {
|
|
47180
48462
|
"use strict";
|
|
47181
48463
|
import_d3_geo2 = require("d3-geo");
|
|
47182
48464
|
import_topojson_client2 = require("topojson-client");
|
|
47183
48465
|
init_color_utils();
|
|
48466
|
+
init_geo();
|
|
48467
|
+
init_colorize();
|
|
48468
|
+
init_colors();
|
|
47184
48469
|
init_label_layout();
|
|
47185
48470
|
init_legend_constants();
|
|
47186
48471
|
init_title_constants();
|
|
48472
|
+
init_context_labels();
|
|
47187
48473
|
FIT_PAD = 24;
|
|
47188
48474
|
RAMP_FLOOR = 15;
|
|
47189
48475
|
R_DEFAULT = 6;
|
|
@@ -47191,29 +48477,66 @@ var init_layout15 = __esm({
|
|
|
47191
48477
|
R_MAX = 22;
|
|
47192
48478
|
W_MIN = 1.25;
|
|
47193
48479
|
W_MAX = 8;
|
|
47194
|
-
|
|
47195
|
-
|
|
47196
|
-
|
|
47197
|
-
|
|
48480
|
+
FONT2 = 11;
|
|
48481
|
+
MAX_CLUSTER_EXTENT_FACTOR = 0.18;
|
|
48482
|
+
MAX_COLUMN_ROWS = 7;
|
|
48483
|
+
REGION_LABEL_HALO_RATIO = 4.5;
|
|
48484
|
+
LAND_TINT_LIGHT = 12;
|
|
48485
|
+
LAND_TINT_DARK = 24;
|
|
47198
48486
|
TAG_TINT_LIGHT = 60;
|
|
47199
48487
|
TAG_TINT_DARK = 68;
|
|
47200
|
-
|
|
48488
|
+
WATER_TINT_LIGHT = 24;
|
|
48489
|
+
WATER_TINT_DARK = 24;
|
|
47201
48490
|
RIVER_WIDTH = 1.3;
|
|
48491
|
+
COMPACT_WIDTH_PX = 480;
|
|
48492
|
+
RELIEF_MIN_AREA = 12;
|
|
48493
|
+
RELIEF_MIN_DIM = 2;
|
|
48494
|
+
RELIEF_HATCH_SPACING = 2;
|
|
48495
|
+
RELIEF_HATCH_WIDTH = 0.15;
|
|
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;
|
|
47202
48506
|
FOREIGN_TINT_LIGHT = 30;
|
|
47203
48507
|
FOREIGN_TINT_DARK = 62;
|
|
47204
|
-
MUTED_WATER_LIGHT = 14;
|
|
47205
|
-
MUTED_WATER_DARK = 10;
|
|
47206
48508
|
MUTED_FOREIGN_LIGHT = 28;
|
|
47207
48509
|
MUTED_FOREIGN_DARK = 16;
|
|
47208
|
-
MUTED_LAND_DARK = 24;
|
|
47209
48510
|
COLO_R = 9;
|
|
47210
48511
|
GOLDEN_ANGLE = 2.399963229728653;
|
|
48512
|
+
STACK_OVERLAP = 1;
|
|
48513
|
+
STACK_RING_MAX = 8;
|
|
48514
|
+
STACK_RING_GAP = 4;
|
|
47211
48515
|
FAN_STEP = 16;
|
|
47212
48516
|
ARC_CURVE_FRAC = 0.18;
|
|
48517
|
+
decodeCache = /* @__PURE__ */ new WeakMap();
|
|
47213
48518
|
usConusProjection = () => (0, import_d3_geo2.geoConicEqualArea)().parallels([29.5, 45.5]).rotate([96, 0]);
|
|
47214
48519
|
alaskaProjection = () => (0, import_d3_geo2.geoConicEqualArea)().rotate([154, 0]).center([-2, 58.5]).parallels([55, 65]);
|
|
47215
48520
|
hawaiiProjection = () => (0, import_d3_geo2.geoMercator)();
|
|
47216
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
|
+
};
|
|
47217
48540
|
US_NON_CONUS = /* @__PURE__ */ new Set([
|
|
47218
48541
|
"US-AK",
|
|
47219
48542
|
"US-HI",
|
|
@@ -47232,6 +48555,58 @@ __export(renderer_exports16, {
|
|
|
47232
48555
|
renderMap: () => renderMap,
|
|
47233
48556
|
renderMapForExport: () => renderMapForExport
|
|
47234
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
|
+
}
|
|
47235
48610
|
function renderMap(container, resolved, data, palette, isDark, onClickItem, exportDims, activeGroupOverride) {
|
|
47236
48611
|
d3Selection18.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
47237
48612
|
const width = exportDims?.width ?? container.clientWidth;
|
|
@@ -47244,6 +48619,11 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47244
48619
|
{
|
|
47245
48620
|
palette,
|
|
47246
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,
|
|
47247
48627
|
...activeGroupOverride !== void 0 && {
|
|
47248
48628
|
activeGroup: activeGroupOverride
|
|
47249
48629
|
}
|
|
@@ -47257,6 +48637,7 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47257
48637
|
const gRegions = svg.append("g").attr("class", "dgmo-map-regions");
|
|
47258
48638
|
const drawRegion = (g, r, strokeWidth) => {
|
|
47259
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);
|
|
47260
48641
|
if (r.layer !== "base") {
|
|
47261
48642
|
p.classed("dgmo-map-region", true).attr("data-region", r.id);
|
|
47262
48643
|
if (r.value !== void 0) p.attr("data-value", r.value);
|
|
@@ -47277,6 +48658,52 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47277
48658
|
}
|
|
47278
48659
|
};
|
|
47279
48660
|
for (const r of layout.regions) drawRegion(gRegions, r, 0.5);
|
|
48661
|
+
if (layout.relief.length && layout.reliefHatch) {
|
|
48662
|
+
const h = layout.reliefHatch;
|
|
48663
|
+
const rangeClipId = "dgmo-relief-clip";
|
|
48664
|
+
const landClipId = "dgmo-relief-land";
|
|
48665
|
+
const rangeClip = defs.append("clipPath").attr("id", rangeClipId);
|
|
48666
|
+
for (const s of layout.relief) rangeClip.append("path").attr("d", s.d);
|
|
48667
|
+
const landClip = defs.append("clipPath").attr("id", landClipId);
|
|
48668
|
+
for (const r of layout.regions)
|
|
48669
|
+
if (r.id !== "lake") landClip.append("path").attr("d", r.d);
|
|
48670
|
+
const gRelief = svg.append("g").attr("clip-path", `url(#${landClipId})`).append("g").attr("class", "dgmo-map-relief").attr("clip-path", `url(#${rangeClipId})`).attr("stroke", h.color).attr("stroke-width", h.width).attr("vector-effect", "non-scaling-stroke");
|
|
48671
|
+
for (let y = h.spacing; y < height; y += h.spacing) {
|
|
48672
|
+
gRelief.append("line").attr("x1", 0).attr("y1", y).attr("x2", width).attr("y2", y);
|
|
48673
|
+
}
|
|
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
|
+
}
|
|
47280
48707
|
if (layout.rivers.length) {
|
|
47281
48708
|
const gRivers = svg.append("g").attr("class", "dgmo-map-rivers").attr("fill", "none");
|
|
47282
48709
|
for (const r of layout.rivers) {
|
|
@@ -47285,15 +48712,61 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47285
48712
|
}
|
|
47286
48713
|
if (layout.insets.length) {
|
|
47287
48714
|
const insetG = svg.append("g").attr("class", "dgmo-map-insets");
|
|
47288
|
-
|
|
48715
|
+
layout.insets.forEach((box, bi) => {
|
|
47289
48716
|
const d = box.points.map((p, i) => `${i ? "L" : "M"}${p[0]},${p[1]}`).join("") + "Z";
|
|
47290
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");
|
|
47291
|
-
|
|
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
|
+
});
|
|
47292
48724
|
for (const r of layout.insetRegions) drawRegion(insetG, r, 0.5);
|
|
47293
|
-
|
|
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
|
+
};
|
|
47294
48766
|
const gLegs = svg.append("g").attr("class", "dgmo-map-legs").attr("fill", "none");
|
|
47295
48767
|
layout.legs.forEach((leg, i) => {
|
|
47296
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);
|
|
47297
48770
|
if (leg.arrow) {
|
|
47298
48771
|
const id = `dgmo-map-arrow-${i}`;
|
|
47299
48772
|
const s = arrowSize(leg.width);
|
|
@@ -47301,25 +48774,38 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47301
48774
|
p.attr("marker-end", `url(#${id})`);
|
|
47302
48775
|
}
|
|
47303
48776
|
if (leg.label !== void 0 && leg.labelX !== void 0) {
|
|
47304
|
-
emitText(
|
|
48777
|
+
const lt = emitText(
|
|
47305
48778
|
gLegs,
|
|
47306
48779
|
leg.labelX,
|
|
47307
48780
|
leg.labelY ?? 0,
|
|
47308
48781
|
leg.label,
|
|
47309
48782
|
"middle",
|
|
47310
|
-
palette.textMuted,
|
|
47311
|
-
haloColor,
|
|
47312
|
-
true,
|
|
48783
|
+
leg.labelColor ?? palette.textMuted,
|
|
48784
|
+
leg.labelHaloColor ?? haloColor,
|
|
48785
|
+
leg.labelHalo ?? true,
|
|
47313
48786
|
LABEL_FONT - 1
|
|
47314
48787
|
);
|
|
48788
|
+
wireSync(lt, leg.lineNumber);
|
|
47315
48789
|
}
|
|
47316
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
|
+
}
|
|
47317
48801
|
const gPois = svg.append("g").attr("class", "dgmo-map-pois");
|
|
47318
48802
|
for (const poi of layout.pois) {
|
|
47319
48803
|
if (poi.isOrigin) {
|
|
47320
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);
|
|
47321
48805
|
}
|
|
47322
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);
|
|
47323
48809
|
if (poi.tags) {
|
|
47324
48810
|
for (const [group, value] of Object.entries(poi.tags)) {
|
|
47325
48811
|
c.attr(`data-tag-${group.toLowerCase()}`, value.toLowerCase());
|
|
@@ -47347,12 +48833,32 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47347
48833
|
}
|
|
47348
48834
|
const gLabels = svg.append("g").attr("class", "dgmo-map-labels");
|
|
47349
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
|
+
}
|
|
47350
48853
|
if (lab.leader) {
|
|
47351
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(
|
|
47352
48855
|
"stroke",
|
|
47353
48856
|
lab.leaderColor ?? mix(palette.textMuted, palette.bg, 60)
|
|
47354
48857
|
).attr("stroke-width", lab.leaderColor ? 1 : 0.75);
|
|
47355
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);
|
|
47356
48862
|
}
|
|
47357
48863
|
const t = emitText(
|
|
47358
48864
|
gLabels,
|
|
@@ -47363,11 +48869,38 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47363
48869
|
lab.color,
|
|
47364
48870
|
lab.haloColor,
|
|
47365
48871
|
lab.halo,
|
|
47366
|
-
LABEL_FONT
|
|
48872
|
+
LABEL_FONT,
|
|
48873
|
+
lab.italic,
|
|
48874
|
+
lab.letterSpacing,
|
|
48875
|
+
lab.lines
|
|
47367
48876
|
);
|
|
47368
48877
|
if (lab.poiId !== void 0) {
|
|
47369
48878
|
t.attr("data-poi", lab.poiId).style("cursor", "default");
|
|
47370
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
|
+
}
|
|
47371
48904
|
}
|
|
47372
48905
|
if (layout.legend) {
|
|
47373
48906
|
const legendY = (layout.title ? TITLE_Y + TITLE_FONT_SIZE : 0) + (layout.subtitle ? TITLE_FONT_SIZE : 0) + 8;
|
|
@@ -47401,10 +48934,10 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47401
48934
|
}
|
|
47402
48935
|
}
|
|
47403
48936
|
if (layout.title) {
|
|
47404
|
-
svg.append("text").attr("x", width / 2).attr("y", TITLE_Y).attr("text-anchor", "middle").attr("font-size", TITLE_FONT_SIZE).attr("font-weight", TITLE_FONT_WEIGHT).attr("fill", palette.text).attr("paint-order", "stroke fill").attr("stroke", palette.bg).attr("stroke-width", 4).attr("stroke-linejoin", "round").attr("stroke-opacity", 0.7).text(layout.title);
|
|
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);
|
|
47405
48938
|
}
|
|
47406
48939
|
if (layout.subtitle) {
|
|
47407
|
-
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);
|
|
47408
48941
|
}
|
|
47409
48942
|
if (layout.caption) {
|
|
47410
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);
|
|
@@ -47413,10 +48946,21 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47413
48946
|
function renderMapForExport(container, resolved, data, palette, isDark, exportDims) {
|
|
47414
48947
|
renderMap(container, resolved, data, palette, isDark, void 0, exportDims);
|
|
47415
48948
|
}
|
|
47416
|
-
function emitText(g, x, y, text, anchor, color, halo, withHalo, fontSize) {
|
|
47417
|
-
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);
|
|
47418
48962
|
if (withHalo) {
|
|
47419
|
-
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);
|
|
47420
48964
|
}
|
|
47421
48965
|
return t;
|
|
47422
48966
|
}
|
|
@@ -47434,6 +48978,179 @@ var init_renderer16 = __esm({
|
|
|
47434
48978
|
}
|
|
47435
48979
|
});
|
|
47436
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
|
+
|
|
49031
|
+
// src/map/load-data.ts
|
|
49032
|
+
var load_data_exports = {};
|
|
49033
|
+
__export(load_data_exports, {
|
|
49034
|
+
loadMapData: () => loadMapData
|
|
49035
|
+
});
|
|
49036
|
+
async function loadNodeBuiltins() {
|
|
49037
|
+
const [{ readFile }, { fileURLToPath }, { dirname, resolve }] = await Promise.all([
|
|
49038
|
+
import("fs/promises"),
|
|
49039
|
+
import("url"),
|
|
49040
|
+
import("path")
|
|
49041
|
+
]);
|
|
49042
|
+
return { readFile, fileURLToPath, dirname, resolve };
|
|
49043
|
+
}
|
|
49044
|
+
async function readJson(nb, dir, name) {
|
|
49045
|
+
return JSON.parse(await nb.readFile(nb.resolve(dir, name), "utf8"));
|
|
49046
|
+
}
|
|
49047
|
+
async function firstExistingDir(nb, baseDir) {
|
|
49048
|
+
for (const rel of CANDIDATE_DIRS) {
|
|
49049
|
+
const dir = nb.resolve(baseDir, rel);
|
|
49050
|
+
try {
|
|
49051
|
+
await nb.readFile(nb.resolve(dir, FILES.gazetteer), "utf8");
|
|
49052
|
+
return dir;
|
|
49053
|
+
} catch {
|
|
49054
|
+
}
|
|
49055
|
+
}
|
|
49056
|
+
throw new Error(
|
|
49057
|
+
`map data assets not found near ${baseDir} (looked in ${CANDIDATE_DIRS.join(", ")}). Run \`pnpm build:map-data\` and \`pnpm build\`.`
|
|
49058
|
+
);
|
|
49059
|
+
}
|
|
49060
|
+
function validate(data) {
|
|
49061
|
+
const topoOk = (t) => !!t && t.type === "Topology" && !!t.objects;
|
|
49062
|
+
if (!topoOk(data.worldCoarse) || !topoOk(data.worldDetail) || !topoOk(data.usStates) || !data.gazetteer || !Array.isArray(data.gazetteer.cities) || !data.gazetteer.byName) {
|
|
49063
|
+
throw new Error("map data assets are malformed (failed shape validation)");
|
|
49064
|
+
}
|
|
49065
|
+
return data;
|
|
49066
|
+
}
|
|
49067
|
+
function moduleBaseDir(nb) {
|
|
49068
|
+
try {
|
|
49069
|
+
const url = import_meta.url;
|
|
49070
|
+
if (url) return nb.dirname(nb.fileURLToPath(url));
|
|
49071
|
+
} catch {
|
|
49072
|
+
}
|
|
49073
|
+
if (typeof __dirname !== "undefined") return __dirname;
|
|
49074
|
+
return process.cwd();
|
|
49075
|
+
}
|
|
49076
|
+
function loadMapData() {
|
|
49077
|
+
cache ??= (async () => {
|
|
49078
|
+
const nb = await loadNodeBuiltins();
|
|
49079
|
+
const dir = await firstExistingDir(nb, moduleBaseDir(nb));
|
|
49080
|
+
const [
|
|
49081
|
+
worldCoarse,
|
|
49082
|
+
worldDetail,
|
|
49083
|
+
usStates,
|
|
49084
|
+
lakes,
|
|
49085
|
+
rivers,
|
|
49086
|
+
mountainRanges,
|
|
49087
|
+
naLand,
|
|
49088
|
+
naLakes,
|
|
49089
|
+
waterBodies,
|
|
49090
|
+
gazetteer
|
|
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.
|
|
49096
|
+
readJson(nb, dir, FILES.worldCoarse),
|
|
49097
|
+
readJson(nb, dir, FILES.worldDetail),
|
|
49098
|
+
readJson(nb, dir, FILES.usStates),
|
|
49099
|
+
// Lakes/rivers/mountain/NA/water assets are optional — older bundles may predate them.
|
|
49100
|
+
readJson(nb, dir, FILES.lakes).catch(() => void 0),
|
|
49101
|
+
readJson(nb, dir, FILES.rivers).catch(() => void 0),
|
|
49102
|
+
readJson(nb, dir, FILES.mountainRanges).catch(
|
|
49103
|
+
() => void 0
|
|
49104
|
+
),
|
|
49105
|
+
readJson(nb, dir, FILES.naLand).catch(() => void 0),
|
|
49106
|
+
readJson(nb, dir, FILES.naLakes).catch(() => void 0),
|
|
49107
|
+
readJson(nb, dir, FILES.waterBodies).catch(() => void 0),
|
|
49108
|
+
readJson(nb, dir, FILES.gazetteer)
|
|
49109
|
+
]);
|
|
49110
|
+
return validate({
|
|
49111
|
+
worldCoarse,
|
|
49112
|
+
worldDetail,
|
|
49113
|
+
usStates,
|
|
49114
|
+
gazetteer,
|
|
49115
|
+
...lakes && { lakes },
|
|
49116
|
+
...rivers && { rivers },
|
|
49117
|
+
...mountainRanges && { mountainRanges },
|
|
49118
|
+
...naLand && { naLand },
|
|
49119
|
+
...naLakes && { naLakes },
|
|
49120
|
+
...waterBodies && { waterBodies }
|
|
49121
|
+
});
|
|
49122
|
+
})().catch((e) => {
|
|
49123
|
+
cache = void 0;
|
|
49124
|
+
throw e;
|
|
49125
|
+
});
|
|
49126
|
+
return cache;
|
|
49127
|
+
}
|
|
49128
|
+
var import_meta, FILES, CANDIDATE_DIRS, cache;
|
|
49129
|
+
var init_load_data = __esm({
|
|
49130
|
+
"src/map/load-data.ts"() {
|
|
49131
|
+
"use strict";
|
|
49132
|
+
import_meta = {};
|
|
49133
|
+
FILES = {
|
|
49134
|
+
worldCoarse: "world-coarse.json",
|
|
49135
|
+
worldDetail: "world-detail.json",
|
|
49136
|
+
usStates: "us-states.json",
|
|
49137
|
+
lakes: "lakes.json",
|
|
49138
|
+
rivers: "rivers.json",
|
|
49139
|
+
mountainRanges: "mountain-ranges.json",
|
|
49140
|
+
naLand: "na-land.json",
|
|
49141
|
+
naLakes: "na-lakes.json",
|
|
49142
|
+
waterBodies: "water-bodies.json",
|
|
49143
|
+
gazetteer: "gazetteer.json"
|
|
49144
|
+
};
|
|
49145
|
+
CANDIDATE_DIRS = [
|
|
49146
|
+
"./data",
|
|
49147
|
+
"./map-data",
|
|
49148
|
+
"../map-data",
|
|
49149
|
+
"../src/map/data"
|
|
49150
|
+
];
|
|
49151
|
+
}
|
|
49152
|
+
});
|
|
49153
|
+
|
|
47437
49154
|
// src/pyramid/renderer.ts
|
|
47438
49155
|
var renderer_exports17 = {};
|
|
47439
49156
|
__export(renderer_exports17, {
|
|
@@ -49435,8 +51152,8 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
|
|
|
49435
51152
|
const lines = splitParticipantLabel(p.label, LABEL_MAX_CHARS);
|
|
49436
51153
|
if (lines.length === 0) continue;
|
|
49437
51154
|
const widest = Math.max(...lines.map((l) => l.length));
|
|
49438
|
-
const
|
|
49439
|
-
uniformBoxWidth = Math.max(uniformBoxWidth,
|
|
51155
|
+
const labelWidth2 = widest * LABEL_CHAR_WIDTH + 10;
|
|
51156
|
+
uniformBoxWidth = Math.max(uniformBoxWidth, labelWidth2);
|
|
49440
51157
|
}
|
|
49441
51158
|
uniformBoxWidth = Math.min(MAX_BOX_WIDTH, uniformBoxWidth);
|
|
49442
51159
|
const effectiveGap = Math.max(PARTICIPANT_GAP, uniformBoxWidth + 30);
|
|
@@ -52131,15 +53848,15 @@ function renderArcDiagram(container, parsed, palette, _isDark, onClickItem, expo
|
|
|
52131
53848
|
textColor,
|
|
52132
53849
|
onClickItem
|
|
52133
53850
|
);
|
|
52134
|
-
const
|
|
52135
|
-
for (const node of nodes)
|
|
53851
|
+
const neighbors2 = /* @__PURE__ */ new Map();
|
|
53852
|
+
for (const node of nodes) neighbors2.set(node, /* @__PURE__ */ new Set());
|
|
52136
53853
|
for (const link of links) {
|
|
52137
|
-
|
|
52138
|
-
|
|
53854
|
+
neighbors2.get(link.source).add(link.target);
|
|
53855
|
+
neighbors2.get(link.target).add(link.source);
|
|
52139
53856
|
}
|
|
52140
53857
|
const FADE_OPACITY3 = 0.1;
|
|
52141
53858
|
function handleMouseEnter(hovered) {
|
|
52142
|
-
const connected =
|
|
53859
|
+
const connected = neighbors2.get(hovered);
|
|
52143
53860
|
g.selectAll(".arc-link").each(function() {
|
|
52144
53861
|
const el = d3Selection23.select(this);
|
|
52145
53862
|
const src = el.attr("data-source");
|
|
@@ -54074,7 +55791,7 @@ function renderVenn(container, parsed, palette, _isDark, onClickItem, exportDims
|
|
|
54074
55791
|
8,
|
|
54075
55792
|
Math.floor(OVERLAP_WRAP_TARGET_W / OVERLAP_CH_W)
|
|
54076
55793
|
);
|
|
54077
|
-
function
|
|
55794
|
+
function wrapLabel3(text, maxChars) {
|
|
54078
55795
|
const words = text.split(/\s+/).filter(Boolean);
|
|
54079
55796
|
const lines = [];
|
|
54080
55797
|
let cur = "";
|
|
@@ -54120,7 +55837,7 @@ function renderVenn(container, parsed, palette, _isDark, onClickItem, exportDims
|
|
|
54120
55837
|
if (!ov.label) continue;
|
|
54121
55838
|
const idxs = ov.sets.map((s) => vennSets.findIndex((vs) => vs.name === s));
|
|
54122
55839
|
if (idxs.some((idx) => idx < 0)) continue;
|
|
54123
|
-
const lines =
|
|
55840
|
+
const lines = wrapLabel3(ov.label, MAX_WRAP_CHARS);
|
|
54124
55841
|
wrappedOverlapLabels.set(ov, lines);
|
|
54125
55842
|
const dir = predictOverlapDirRaw(idxs);
|
|
54126
55843
|
const longest = lines.reduce((m, l) => Math.max(m, l.length), 0);
|
|
@@ -55557,25 +57274,29 @@ async function renderForExport(content, theme, palette, viewState, options) {
|
|
|
55557
57274
|
if (detectedType === "map") {
|
|
55558
57275
|
const { parseMap: parseMap2 } = await Promise.resolve().then(() => (init_parser12(), parser_exports11));
|
|
55559
57276
|
const { resolveMap: resolveMap2 } = await Promise.resolve().then(() => (init_resolver2(), resolver_exports));
|
|
55560
|
-
const { loadMapData: loadMapData2 } = await Promise.resolve().then(() => (init_load_data(), load_data_exports));
|
|
55561
57277
|
const { renderMapForExport: renderMapForExport2 } = await Promise.resolve().then(() => (init_renderer16(), renderer_exports16));
|
|
57278
|
+
const { mapExportDimensions: mapExportDimensions2 } = await Promise.resolve().then(() => (init_dimensions(), dimensions_exports));
|
|
55562
57279
|
const effectivePalette2 = await resolveExportPalette(theme, palette);
|
|
55563
57280
|
const mapParsed = parseMap2(content);
|
|
55564
|
-
let mapData;
|
|
55565
|
-
|
|
55566
|
-
|
|
55567
|
-
|
|
55568
|
-
|
|
57281
|
+
let mapData = options?.mapData;
|
|
57282
|
+
if (!mapData) {
|
|
57283
|
+
const { loadMapData: loadMapData2 } = await Promise.resolve().then(() => (init_load_data(), load_data_exports));
|
|
57284
|
+
try {
|
|
57285
|
+
mapData = await loadMapData2();
|
|
57286
|
+
} catch {
|
|
57287
|
+
return "";
|
|
57288
|
+
}
|
|
55569
57289
|
}
|
|
55570
57290
|
const mapResolved = resolveMap2(mapParsed, mapData);
|
|
55571
|
-
const
|
|
57291
|
+
const dims2 = mapExportDimensions2(mapResolved, mapData, EXPORT_WIDTH);
|
|
57292
|
+
const container2 = createExportContainer(dims2.width, dims2.height);
|
|
55572
57293
|
renderMapForExport2(
|
|
55573
57294
|
container2,
|
|
55574
57295
|
mapResolved,
|
|
55575
57296
|
mapData,
|
|
55576
57297
|
effectivePalette2,
|
|
55577
57298
|
theme === "dark",
|
|
55578
|
-
|
|
57299
|
+
dims2
|
|
55579
57300
|
);
|
|
55580
57301
|
return finalizeSvgExport(container2, theme, effectivePalette2);
|
|
55581
57302
|
}
|
|
@@ -56436,7 +58157,8 @@ async function render(content, options) {
|
|
|
56436
58157
|
...options?.c4Container !== void 0 && {
|
|
56437
58158
|
c4Container: options.c4Container
|
|
56438
58159
|
},
|
|
56439
|
-
...options?.tagGroup !== void 0 && { tagGroup: options.tagGroup }
|
|
58160
|
+
...options?.tagGroup !== void 0 && { tagGroup: options.tagGroup },
|
|
58161
|
+
...options?.mapData !== void 0 && { mapData: options.mapData }
|
|
56440
58162
|
});
|
|
56441
58163
|
if (chartType === "map") {
|
|
56442
58164
|
try {
|
|
@@ -56447,7 +58169,7 @@ async function render(content, options) {
|
|
|
56447
58169
|
Promise.resolve().then(() => (init_load_data(), load_data_exports))
|
|
56448
58170
|
]
|
|
56449
58171
|
);
|
|
56450
|
-
const data = await loadMapData2();
|
|
58172
|
+
const data = options?.mapData ?? await loadMapData2();
|
|
56451
58173
|
diagnostics = [...resolveMap2(parseMap2(content), data).diagnostics];
|
|
56452
58174
|
} catch {
|
|
56453
58175
|
}
|
|
@@ -56615,21 +58337,20 @@ var DIRECTIVE_KEYWORDS = /* @__PURE__ */ new Set([
|
|
|
56615
58337
|
// Sequence
|
|
56616
58338
|
"activations",
|
|
56617
58339
|
"no-activations",
|
|
56618
|
-
// Map (§24B) directives
|
|
56619
|
-
"region",
|
|
56620
|
-
"projection",
|
|
58340
|
+
// Map (§24B) directives — cosmetics on by default, bare `no-*` opt-outs
|
|
56621
58341
|
"region-metric",
|
|
56622
58342
|
"poi-metric",
|
|
56623
58343
|
"flow-metric",
|
|
56624
|
-
"
|
|
56625
|
-
"
|
|
56626
|
-
"default-country",
|
|
56627
|
-
"default-state",
|
|
56628
|
-
"no-legend",
|
|
56629
|
-
"muted",
|
|
56630
|
-
"natural",
|
|
56631
|
-
"subtitle",
|
|
58344
|
+
"locale",
|
|
58345
|
+
"active-tag",
|
|
56632
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",
|
|
56633
58354
|
"poi",
|
|
56634
58355
|
"route",
|
|
56635
58356
|
// Data charts
|
|
@@ -56922,7 +58643,11 @@ var ATTRIBUTE_KEYS = /* @__PURE__ */ new Set([
|
|
|
56922
58643
|
"collapsed",
|
|
56923
58644
|
"tech",
|
|
56924
58645
|
"span",
|
|
56925
|
-
"split"
|
|
58646
|
+
"split",
|
|
58647
|
+
// Map (§24B) reserved keys
|
|
58648
|
+
"value",
|
|
58649
|
+
"label",
|
|
58650
|
+
"style"
|
|
56926
58651
|
]);
|
|
56927
58652
|
function applyAttributeKeys(tokens) {
|
|
56928
58653
|
for (let i = 0; i < tokens.length - 1; i++) {
|
|
@@ -57295,7 +59020,7 @@ pre.dgmo, code.language-dgmo, pre > code.language-dgmo,
|
|
|
57295
59020
|
|
|
57296
59021
|
// src/auto/index.ts
|
|
57297
59022
|
init_safe_href();
|
|
57298
|
-
var VERSION = "0.
|
|
59023
|
+
var VERSION = "0.22.0";
|
|
57299
59024
|
var DEFAULTS = {
|
|
57300
59025
|
theme: "auto",
|
|
57301
59026
|
palette: "nord",
|