@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/index.js
CHANGED
|
@@ -91,18 +91,18 @@ function computeQuadrantPointLabels(points, chartBounds, obstacles, pointRadius,
|
|
|
91
91
|
const results = [];
|
|
92
92
|
for (let i = 0; i < points.length; i++) {
|
|
93
93
|
const pt = points[i];
|
|
94
|
-
const
|
|
94
|
+
const labelWidth2 = pt.label.length * fontSize * CHAR_WIDTH_RATIO + 8;
|
|
95
95
|
let best = null;
|
|
96
96
|
const directions = [
|
|
97
97
|
{
|
|
98
98
|
// Above
|
|
99
99
|
gen: (offset) => {
|
|
100
|
-
const lx = pt.cx -
|
|
100
|
+
const lx = pt.cx - labelWidth2 / 2;
|
|
101
101
|
const ly = pt.cy - offset - labelHeight;
|
|
102
|
-
if (ly < chartBounds.top || lx < chartBounds.left || lx +
|
|
102
|
+
if (ly < chartBounds.top || lx < chartBounds.left || lx + labelWidth2 > chartBounds.right)
|
|
103
103
|
return null;
|
|
104
104
|
return {
|
|
105
|
-
rect: { x: lx, y: ly, w:
|
|
105
|
+
rect: { x: lx, y: ly, w: labelWidth2, h: labelHeight },
|
|
106
106
|
textX: pt.cx,
|
|
107
107
|
textY: ly + labelHeight / 2,
|
|
108
108
|
anchor: "middle"
|
|
@@ -112,12 +112,12 @@ function computeQuadrantPointLabels(points, chartBounds, obstacles, pointRadius,
|
|
|
112
112
|
{
|
|
113
113
|
// Below
|
|
114
114
|
gen: (offset) => {
|
|
115
|
-
const lx = pt.cx -
|
|
115
|
+
const lx = pt.cx - labelWidth2 / 2;
|
|
116
116
|
const ly = pt.cy + offset;
|
|
117
|
-
if (ly + labelHeight > chartBounds.bottom || lx < chartBounds.left || lx +
|
|
117
|
+
if (ly + labelHeight > chartBounds.bottom || lx < chartBounds.left || lx + labelWidth2 > chartBounds.right)
|
|
118
118
|
return null;
|
|
119
119
|
return {
|
|
120
|
-
rect: { x: lx, y: ly, w:
|
|
120
|
+
rect: { x: lx, y: ly, w: labelWidth2, h: labelHeight },
|
|
121
121
|
textX: pt.cx,
|
|
122
122
|
textY: ly + labelHeight / 2,
|
|
123
123
|
anchor: "middle"
|
|
@@ -129,10 +129,10 @@ function computeQuadrantPointLabels(points, chartBounds, obstacles, pointRadius,
|
|
|
129
129
|
gen: (offset) => {
|
|
130
130
|
const lx = pt.cx + offset;
|
|
131
131
|
const ly = pt.cy - labelHeight / 2;
|
|
132
|
-
if (lx +
|
|
132
|
+
if (lx + labelWidth2 > chartBounds.right || ly < chartBounds.top || ly + labelHeight > chartBounds.bottom)
|
|
133
133
|
return null;
|
|
134
134
|
return {
|
|
135
|
-
rect: { x: lx, y: ly, w:
|
|
135
|
+
rect: { x: lx, y: ly, w: labelWidth2, h: labelHeight },
|
|
136
136
|
textX: lx,
|
|
137
137
|
textY: pt.cy,
|
|
138
138
|
anchor: "start"
|
|
@@ -142,13 +142,13 @@ function computeQuadrantPointLabels(points, chartBounds, obstacles, pointRadius,
|
|
|
142
142
|
{
|
|
143
143
|
// Left
|
|
144
144
|
gen: (offset) => {
|
|
145
|
-
const lx = pt.cx - offset -
|
|
145
|
+
const lx = pt.cx - offset - labelWidth2;
|
|
146
146
|
const ly = pt.cy - labelHeight / 2;
|
|
147
147
|
if (lx < chartBounds.left || ly < chartBounds.top || ly + labelHeight > chartBounds.bottom)
|
|
148
148
|
return null;
|
|
149
149
|
return {
|
|
150
|
-
rect: { x: lx, y: ly, w:
|
|
151
|
-
textX: lx +
|
|
150
|
+
rect: { x: lx, y: ly, w: labelWidth2, h: labelHeight },
|
|
151
|
+
textX: lx + labelWidth2,
|
|
152
152
|
textY: pt.cy,
|
|
153
153
|
anchor: "end"
|
|
154
154
|
};
|
|
@@ -198,10 +198,10 @@ function computeQuadrantPointLabels(points, chartBounds, obstacles, pointRadius,
|
|
|
198
198
|
}
|
|
199
199
|
}
|
|
200
200
|
if (!best) {
|
|
201
|
-
const lx = pt.cx -
|
|
201
|
+
const lx = pt.cx - labelWidth2 / 2;
|
|
202
202
|
const ly = pt.cy - minGap - labelHeight;
|
|
203
203
|
best = {
|
|
204
|
-
rect: { x: lx, y: ly, w:
|
|
204
|
+
rect: { x: lx, y: ly, w: labelWidth2, h: labelHeight },
|
|
205
205
|
textX: pt.cx,
|
|
206
206
|
textY: ly + labelHeight / 2,
|
|
207
207
|
anchor: "middle",
|
|
@@ -836,6 +836,9 @@ var init_reserved_key_registry = __esm({
|
|
|
836
836
|
"value",
|
|
837
837
|
"label",
|
|
838
838
|
"style"
|
|
839
|
+
// `surface:` was removed in the 2026-06-02 defaults-on review — it is no longer
|
|
840
|
+
// a recognized metadata key (the route/edge surface feature was cut; §24B.7).
|
|
841
|
+
// A stray `surface: water` is no longer captured as a reserved key.
|
|
839
842
|
]);
|
|
840
843
|
ORG_REGISTRY = staticRegistry([
|
|
841
844
|
"color",
|
|
@@ -1898,77 +1901,266 @@ function getSegmentColors(palette, count) {
|
|
|
1898
1901
|
(_, i) => hslToHex(Math.round((startHue + i * step) % 360), avgS, avgL)
|
|
1899
1902
|
);
|
|
1900
1903
|
}
|
|
1904
|
+
function politicalTints(palette, count, isDark) {
|
|
1905
|
+
if (count <= 0) return [];
|
|
1906
|
+
const base = isDark ? palette.surface : palette.bg;
|
|
1907
|
+
const c = palette.colors;
|
|
1908
|
+
const swatches = [
|
|
1909
|
+
.../* @__PURE__ */ new Set([
|
|
1910
|
+
c.green,
|
|
1911
|
+
c.yellow,
|
|
1912
|
+
c.orange,
|
|
1913
|
+
c.purple,
|
|
1914
|
+
c.red,
|
|
1915
|
+
c.teal,
|
|
1916
|
+
c.cyan,
|
|
1917
|
+
c.blue
|
|
1918
|
+
])
|
|
1919
|
+
];
|
|
1920
|
+
const bands = isDark ? POLITICAL_TINT_BANDS.dark : POLITICAL_TINT_BANDS.light;
|
|
1921
|
+
const out = [];
|
|
1922
|
+
for (const pct of bands) {
|
|
1923
|
+
if (out.length >= count) break;
|
|
1924
|
+
for (const s of swatches) out.push(mix(s, base, pct));
|
|
1925
|
+
}
|
|
1926
|
+
return out.slice(0, count);
|
|
1927
|
+
}
|
|
1928
|
+
var POLITICAL_TINT_BANDS;
|
|
1901
1929
|
var init_color_utils = __esm({
|
|
1902
1930
|
"src/palettes/color-utils.ts"() {
|
|
1903
1931
|
"use strict";
|
|
1932
|
+
POLITICAL_TINT_BANDS = {
|
|
1933
|
+
light: [32, 48, 64, 80],
|
|
1934
|
+
dark: [44, 58, 72, 86]
|
|
1935
|
+
};
|
|
1904
1936
|
}
|
|
1905
1937
|
});
|
|
1906
1938
|
|
|
1907
|
-
// src/palettes/
|
|
1908
|
-
var
|
|
1909
|
-
var
|
|
1910
|
-
"src/palettes/
|
|
1939
|
+
// src/palettes/atlas.ts
|
|
1940
|
+
var atlasPalette;
|
|
1941
|
+
var init_atlas = __esm({
|
|
1942
|
+
"src/palettes/atlas.ts"() {
|
|
1911
1943
|
"use strict";
|
|
1912
1944
|
init_registry();
|
|
1913
|
-
|
|
1914
|
-
id: "
|
|
1915
|
-
name: "
|
|
1945
|
+
atlasPalette = {
|
|
1946
|
+
id: "atlas",
|
|
1947
|
+
name: "Atlas",
|
|
1916
1948
|
light: {
|
|
1917
|
-
bg: "#
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1949
|
+
bg: "#f3ead3",
|
|
1950
|
+
// warm manila / parchment
|
|
1951
|
+
surface: "#ece0c0",
|
|
1952
|
+
// deeper paper (cards, panels)
|
|
1953
|
+
overlay: "#e8dab8",
|
|
1954
|
+
// popovers, dropdowns
|
|
1955
|
+
border: "#bcaa86",
|
|
1956
|
+
// muted sepia rule line
|
|
1957
|
+
text: "#463a26",
|
|
1958
|
+
// aged sepia-brown ink
|
|
1959
|
+
textMuted: "#7a6a4f",
|
|
1960
|
+
// faded annotation ink
|
|
1961
|
+
textOnFillLight: "#f7f1de",
|
|
1962
|
+
// parchment (light text on dark fills)
|
|
1963
|
+
textOnFillDark: "#3a2e1c",
|
|
1964
|
+
// deep ink (dark text on light fills)
|
|
1965
|
+
primary: "#5b7a99",
|
|
1966
|
+
// pull-down map ocean (steel-blue)
|
|
1967
|
+
secondary: "#7e9a6f",
|
|
1968
|
+
// lowland sage / celadon
|
|
1969
|
+
accent: "#b07f7c",
|
|
1970
|
+
// dusty rose
|
|
1971
|
+
destructive: "#b25a45",
|
|
1972
|
+
// brick / terracotta
|
|
1929
1973
|
colors: {
|
|
1930
|
-
red: "#
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1974
|
+
red: "#bf6a52",
|
|
1975
|
+
// terracotta brick
|
|
1976
|
+
orange: "#cf9a5c",
|
|
1977
|
+
// map tan / ochre
|
|
1978
|
+
yellow: "#cdb35e",
|
|
1979
|
+
// straw / muted lemon
|
|
1980
|
+
green: "#7e9a6f",
|
|
1981
|
+
// sage / celadon lowland
|
|
1982
|
+
blue: "#5b7a99",
|
|
1983
|
+
// steel-blue ocean
|
|
1984
|
+
purple: "#9a7fa6",
|
|
1985
|
+
// dusty lilac / mauve
|
|
1986
|
+
teal: "#6fa094",
|
|
1987
|
+
// muted seafoam
|
|
1988
|
+
cyan: "#79a7b5",
|
|
1989
|
+
// shallow-water blue
|
|
1990
|
+
gray: "#8a7d68",
|
|
1991
|
+
// warm taupe
|
|
1992
|
+
black: "#463a26",
|
|
1993
|
+
// ink
|
|
1994
|
+
white: "#ece0c0"
|
|
1995
|
+
// paper
|
|
1941
1996
|
}
|
|
1942
1997
|
},
|
|
1943
1998
|
dark: {
|
|
1944
|
-
bg: "#
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1999
|
+
bg: "#1e2a33",
|
|
2000
|
+
// deep map ocean (night globe)
|
|
2001
|
+
surface: "#27353f",
|
|
2002
|
+
// raised ocean
|
|
2003
|
+
overlay: "#2e3d48",
|
|
2004
|
+
// popovers, dropdowns
|
|
2005
|
+
border: "#3d4f5c",
|
|
2006
|
+
// depth-contour line
|
|
2007
|
+
text: "#e8dcc0",
|
|
2008
|
+
// parchment ink, inverted
|
|
2009
|
+
textMuted: "#a89a7d",
|
|
2010
|
+
// faded label
|
|
2011
|
+
textOnFillLight: "#f7f1de",
|
|
2012
|
+
// parchment
|
|
2013
|
+
textOnFillDark: "#1a242c",
|
|
2014
|
+
// deep ocean ink
|
|
2015
|
+
primary: "#7ba0bf",
|
|
2016
|
+
// brighter ocean
|
|
2017
|
+
secondary: "#9bb588",
|
|
2018
|
+
// sage, lifted
|
|
2019
|
+
accent: "#cf9a96",
|
|
2020
|
+
// dusty rose, lifted
|
|
2021
|
+
destructive: "#c9745c",
|
|
2022
|
+
// brick, lifted
|
|
1956
2023
|
colors: {
|
|
1957
|
-
red: "#
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
2024
|
+
red: "#cf7a60",
|
|
2025
|
+
// terracotta
|
|
2026
|
+
orange: "#d9a96a",
|
|
2027
|
+
// tan / ochre
|
|
2028
|
+
yellow: "#d8c074",
|
|
2029
|
+
// straw
|
|
2030
|
+
green: "#9bb588",
|
|
2031
|
+
// sage lowland
|
|
2032
|
+
blue: "#7ba0bf",
|
|
2033
|
+
// ocean
|
|
2034
|
+
purple: "#b59ac0",
|
|
2035
|
+
// lilac / mauve
|
|
2036
|
+
teal: "#85b3a6",
|
|
2037
|
+
// seafoam
|
|
2038
|
+
cyan: "#92bccb",
|
|
2039
|
+
// shallow-water blue
|
|
2040
|
+
gray: "#9a8d76",
|
|
2041
|
+
// warm taupe
|
|
2042
|
+
black: "#27353f",
|
|
2043
|
+
// raised ocean
|
|
2044
|
+
white: "#e8dcc0"
|
|
2045
|
+
// parchment
|
|
1968
2046
|
}
|
|
1969
2047
|
}
|
|
1970
2048
|
};
|
|
1971
|
-
registerPalette(
|
|
2049
|
+
registerPalette(atlasPalette);
|
|
2050
|
+
}
|
|
2051
|
+
});
|
|
2052
|
+
|
|
2053
|
+
// src/palettes/blueprint.ts
|
|
2054
|
+
var blueprintPalette;
|
|
2055
|
+
var init_blueprint = __esm({
|
|
2056
|
+
"src/palettes/blueprint.ts"() {
|
|
2057
|
+
"use strict";
|
|
2058
|
+
init_registry();
|
|
2059
|
+
blueprintPalette = {
|
|
2060
|
+
id: "blueprint",
|
|
2061
|
+
name: "Blueprint",
|
|
2062
|
+
light: {
|
|
2063
|
+
bg: "#f4f8fb",
|
|
2064
|
+
// pale drafting white (faint cyan)
|
|
2065
|
+
surface: "#e6eef4",
|
|
2066
|
+
// drafting panel
|
|
2067
|
+
overlay: "#dde9f1",
|
|
2068
|
+
// popovers, dropdowns
|
|
2069
|
+
border: "#aac3d6",
|
|
2070
|
+
// pale blue grid line
|
|
2071
|
+
text: "#123a5e",
|
|
2072
|
+
// blueprint navy ink
|
|
2073
|
+
textMuted: "#4f7390",
|
|
2074
|
+
// faint draft note
|
|
2075
|
+
textOnFillLight: "#f4f8fb",
|
|
2076
|
+
// drafting white
|
|
2077
|
+
textOnFillDark: "#0c2f4d",
|
|
2078
|
+
// deep blueprint navy
|
|
2079
|
+
primary: "#1f5e8c",
|
|
2080
|
+
// blueprint blue
|
|
2081
|
+
secondary: "#5b7d96",
|
|
2082
|
+
// steel
|
|
2083
|
+
accent: "#b08a3e",
|
|
2084
|
+
// draftsman's ochre highlight
|
|
2085
|
+
destructive: "#c0504d",
|
|
2086
|
+
// correction red
|
|
2087
|
+
colors: {
|
|
2088
|
+
red: "#c25a4e",
|
|
2089
|
+
// correction red
|
|
2090
|
+
orange: "#c2823e",
|
|
2091
|
+
// ochre
|
|
2092
|
+
yellow: "#c2a843",
|
|
2093
|
+
// pencil gold
|
|
2094
|
+
green: "#4f8a6b",
|
|
2095
|
+
// drafting green
|
|
2096
|
+
blue: "#1f5e8c",
|
|
2097
|
+
// blueprint blue
|
|
2098
|
+
purple: "#6f5e96",
|
|
2099
|
+
// indigo pencil
|
|
2100
|
+
teal: "#3a8a8a",
|
|
2101
|
+
// teal
|
|
2102
|
+
cyan: "#3f8fb5",
|
|
2103
|
+
// cyan
|
|
2104
|
+
gray: "#7e8e98",
|
|
2105
|
+
// graphite
|
|
2106
|
+
black: "#123a5e",
|
|
2107
|
+
// navy ink
|
|
2108
|
+
white: "#e6eef4"
|
|
2109
|
+
// panel
|
|
2110
|
+
}
|
|
2111
|
+
},
|
|
2112
|
+
dark: {
|
|
2113
|
+
bg: "#103a5e",
|
|
2114
|
+
// deep blueprint blue (cyanotype ground)
|
|
2115
|
+
surface: "#16466e",
|
|
2116
|
+
// raised sheet
|
|
2117
|
+
overlay: "#1c5180",
|
|
2118
|
+
// popovers, dropdowns
|
|
2119
|
+
border: "#3a6f96",
|
|
2120
|
+
// grid line
|
|
2121
|
+
text: "#eaf2f8",
|
|
2122
|
+
// chalk white
|
|
2123
|
+
textMuted: "#9fc0d6",
|
|
2124
|
+
// faint chalk note
|
|
2125
|
+
textOnFillLight: "#eaf2f8",
|
|
2126
|
+
// chalk white
|
|
2127
|
+
textOnFillDark: "#0c2f4d",
|
|
2128
|
+
// deep blueprint navy
|
|
2129
|
+
primary: "#7fb8d8",
|
|
2130
|
+
// chalk cyan
|
|
2131
|
+
secondary: "#9fb8c8",
|
|
2132
|
+
// pale steel
|
|
2133
|
+
accent: "#d8c27a",
|
|
2134
|
+
// chalk amber
|
|
2135
|
+
destructive: "#e08a7a",
|
|
2136
|
+
// chalk correction red
|
|
2137
|
+
colors: {
|
|
2138
|
+
red: "#e0907e",
|
|
2139
|
+
// chalk red
|
|
2140
|
+
orange: "#e0ab78",
|
|
2141
|
+
// chalk amber
|
|
2142
|
+
yellow: "#e3d089",
|
|
2143
|
+
// chalk gold
|
|
2144
|
+
green: "#93c79e",
|
|
2145
|
+
// chalk green
|
|
2146
|
+
blue: "#8ec3e0",
|
|
2147
|
+
// chalk cyan-blue
|
|
2148
|
+
purple: "#b6a6d8",
|
|
2149
|
+
// chalk indigo
|
|
2150
|
+
teal: "#84c7c2",
|
|
2151
|
+
// chalk teal
|
|
2152
|
+
cyan: "#9fd6e0",
|
|
2153
|
+
// chalk cyan
|
|
2154
|
+
gray: "#aebecb",
|
|
2155
|
+
// chalk graphite
|
|
2156
|
+
black: "#16466e",
|
|
2157
|
+
// raised sheet
|
|
2158
|
+
white: "#eaf2f8"
|
|
2159
|
+
// chalk white
|
|
2160
|
+
}
|
|
2161
|
+
}
|
|
2162
|
+
};
|
|
2163
|
+
registerPalette(blueprintPalette);
|
|
1972
2164
|
}
|
|
1973
2165
|
});
|
|
1974
2166
|
|
|
@@ -2465,6 +2657,120 @@ var init_rose_pine = __esm({
|
|
|
2465
2657
|
}
|
|
2466
2658
|
});
|
|
2467
2659
|
|
|
2660
|
+
// src/palettes/slate.ts
|
|
2661
|
+
var slatePalette;
|
|
2662
|
+
var init_slate = __esm({
|
|
2663
|
+
"src/palettes/slate.ts"() {
|
|
2664
|
+
"use strict";
|
|
2665
|
+
init_registry();
|
|
2666
|
+
slatePalette = {
|
|
2667
|
+
id: "slate",
|
|
2668
|
+
name: "Slate",
|
|
2669
|
+
light: {
|
|
2670
|
+
bg: "#ffffff",
|
|
2671
|
+
// clean slide white
|
|
2672
|
+
surface: "#f3f5f8",
|
|
2673
|
+
// light cool-gray panel
|
|
2674
|
+
overlay: "#eaeef3",
|
|
2675
|
+
// popovers, dropdowns
|
|
2676
|
+
border: "#d4dae1",
|
|
2677
|
+
// hairline rule
|
|
2678
|
+
text: "#1f2933",
|
|
2679
|
+
// near-black slate (softer than pure black)
|
|
2680
|
+
textMuted: "#5b6672",
|
|
2681
|
+
// secondary label
|
|
2682
|
+
textOnFillLight: "#ffffff",
|
|
2683
|
+
// light text on dark fills
|
|
2684
|
+
textOnFillDark: "#1f2933",
|
|
2685
|
+
// dark text on light fills
|
|
2686
|
+
primary: "#3b6ea5",
|
|
2687
|
+
// confident corporate blue
|
|
2688
|
+
secondary: "#5b6672",
|
|
2689
|
+
// slate gray
|
|
2690
|
+
accent: "#3a9188",
|
|
2691
|
+
// muted teal accent
|
|
2692
|
+
destructive: "#c0504d",
|
|
2693
|
+
// brick red
|
|
2694
|
+
colors: {
|
|
2695
|
+
red: "#c0504d",
|
|
2696
|
+
// brick
|
|
2697
|
+
orange: "#cc7a33",
|
|
2698
|
+
// muted amber
|
|
2699
|
+
yellow: "#c9a227",
|
|
2700
|
+
// gold (not neon)
|
|
2701
|
+
green: "#5b9357",
|
|
2702
|
+
// forest / sage
|
|
2703
|
+
blue: "#3b6ea5",
|
|
2704
|
+
// corporate blue
|
|
2705
|
+
purple: "#7d5ba6",
|
|
2706
|
+
// muted violet
|
|
2707
|
+
teal: "#3a9188",
|
|
2708
|
+
// teal
|
|
2709
|
+
cyan: "#4f96c4",
|
|
2710
|
+
// steel cyan
|
|
2711
|
+
gray: "#7e8a97",
|
|
2712
|
+
// cool gray
|
|
2713
|
+
black: "#1f2933",
|
|
2714
|
+
// slate ink
|
|
2715
|
+
white: "#f3f5f8"
|
|
2716
|
+
// panel
|
|
2717
|
+
}
|
|
2718
|
+
},
|
|
2719
|
+
dark: {
|
|
2720
|
+
bg: "#161b22",
|
|
2721
|
+
// deep slate (keynote dark)
|
|
2722
|
+
surface: "#202833",
|
|
2723
|
+
// raised panel
|
|
2724
|
+
overlay: "#29323e",
|
|
2725
|
+
// popovers, dropdowns
|
|
2726
|
+
border: "#38424f",
|
|
2727
|
+
// divider
|
|
2728
|
+
text: "#e6eaef",
|
|
2729
|
+
// off-white
|
|
2730
|
+
textMuted: "#9aa5b1",
|
|
2731
|
+
// secondary label
|
|
2732
|
+
textOnFillLight: "#ffffff",
|
|
2733
|
+
// light text on dark fills
|
|
2734
|
+
textOnFillDark: "#161b22",
|
|
2735
|
+
// dark text on light fills
|
|
2736
|
+
primary: "#5b9bd5",
|
|
2737
|
+
// lifted corporate blue
|
|
2738
|
+
secondary: "#8593a3",
|
|
2739
|
+
// slate gray, lifted
|
|
2740
|
+
accent: "#45b3a3",
|
|
2741
|
+
// teal, lifted
|
|
2742
|
+
destructive: "#e07b6e",
|
|
2743
|
+
// brick, lifted
|
|
2744
|
+
colors: {
|
|
2745
|
+
red: "#e07b6e",
|
|
2746
|
+
// brick
|
|
2747
|
+
orange: "#e0975a",
|
|
2748
|
+
// amber
|
|
2749
|
+
yellow: "#d9bd5a",
|
|
2750
|
+
// gold
|
|
2751
|
+
green: "#74b56e",
|
|
2752
|
+
// forest / sage
|
|
2753
|
+
blue: "#5b9bd5",
|
|
2754
|
+
// corporate blue
|
|
2755
|
+
purple: "#a585c9",
|
|
2756
|
+
// violet
|
|
2757
|
+
teal: "#45b3a3",
|
|
2758
|
+
// teal
|
|
2759
|
+
cyan: "#62b0d9",
|
|
2760
|
+
// steel cyan
|
|
2761
|
+
gray: "#95a1ae",
|
|
2762
|
+
// cool gray
|
|
2763
|
+
black: "#202833",
|
|
2764
|
+
// raised panel
|
|
2765
|
+
white: "#e6eaef"
|
|
2766
|
+
// off-white
|
|
2767
|
+
}
|
|
2768
|
+
}
|
|
2769
|
+
};
|
|
2770
|
+
registerPalette(slatePalette);
|
|
2771
|
+
}
|
|
2772
|
+
});
|
|
2773
|
+
|
|
2468
2774
|
// src/palettes/solarized.ts
|
|
2469
2775
|
var solarizedPalette;
|
|
2470
2776
|
var init_solarized = __esm({
|
|
@@ -2560,6 +2866,120 @@ var init_solarized = __esm({
|
|
|
2560
2866
|
}
|
|
2561
2867
|
});
|
|
2562
2868
|
|
|
2869
|
+
// src/palettes/tidewater.ts
|
|
2870
|
+
var tidewaterPalette;
|
|
2871
|
+
var init_tidewater = __esm({
|
|
2872
|
+
"src/palettes/tidewater.ts"() {
|
|
2873
|
+
"use strict";
|
|
2874
|
+
init_registry();
|
|
2875
|
+
tidewaterPalette = {
|
|
2876
|
+
id: "tidewater",
|
|
2877
|
+
name: "Tidewater",
|
|
2878
|
+
light: {
|
|
2879
|
+
bg: "#eceff0",
|
|
2880
|
+
// weathered sea-mist paper
|
|
2881
|
+
surface: "#e0e4e3",
|
|
2882
|
+
// worn deck panel
|
|
2883
|
+
overlay: "#dadfdf",
|
|
2884
|
+
// popovers, dropdowns
|
|
2885
|
+
border: "#a9b2b3",
|
|
2886
|
+
// muted slate rule
|
|
2887
|
+
text: "#18313f",
|
|
2888
|
+
// ship's-log navy ink
|
|
2889
|
+
textMuted: "#51636b",
|
|
2890
|
+
// faded log entry
|
|
2891
|
+
textOnFillLight: "#f3f5f3",
|
|
2892
|
+
// weathered white
|
|
2893
|
+
textOnFillDark: "#162c38",
|
|
2894
|
+
// deep navy
|
|
2895
|
+
primary: "#1f4e6b",
|
|
2896
|
+
// deep-sea navy
|
|
2897
|
+
secondary: "#b08a4f",
|
|
2898
|
+
// rope / manila tan
|
|
2899
|
+
accent: "#c69a3e",
|
|
2900
|
+
// brass
|
|
2901
|
+
destructive: "#c1433a",
|
|
2902
|
+
// signal-flag red
|
|
2903
|
+
colors: {
|
|
2904
|
+
red: "#c1433a",
|
|
2905
|
+
// signal-flag red
|
|
2906
|
+
orange: "#cc7a38",
|
|
2907
|
+
// weathered amber
|
|
2908
|
+
yellow: "#d6bf5a",
|
|
2909
|
+
// brass gold
|
|
2910
|
+
green: "#4f8a6b",
|
|
2911
|
+
// sea-glass green
|
|
2912
|
+
blue: "#1f4e6b",
|
|
2913
|
+
// deep-sea navy
|
|
2914
|
+
purple: "#6a5a8c",
|
|
2915
|
+
// twilight harbor
|
|
2916
|
+
teal: "#3d8c8c",
|
|
2917
|
+
// sea-glass teal
|
|
2918
|
+
cyan: "#4f9bb5",
|
|
2919
|
+
// shallow water
|
|
2920
|
+
gray: "#8a8d86",
|
|
2921
|
+
// driftwood gray
|
|
2922
|
+
black: "#18313f",
|
|
2923
|
+
// navy ink
|
|
2924
|
+
white: "#e0e4e3"
|
|
2925
|
+
// deck panel
|
|
2926
|
+
}
|
|
2927
|
+
},
|
|
2928
|
+
dark: {
|
|
2929
|
+
bg: "#0f2230",
|
|
2930
|
+
// night-harbor deep sea
|
|
2931
|
+
surface: "#16303f",
|
|
2932
|
+
// raised hull
|
|
2933
|
+
overlay: "#1d3a4a",
|
|
2934
|
+
// popovers, dropdowns
|
|
2935
|
+
border: "#2c4856",
|
|
2936
|
+
// rigging line
|
|
2937
|
+
text: "#e6ebe8",
|
|
2938
|
+
// weathered white
|
|
2939
|
+
textMuted: "#9aaab0",
|
|
2940
|
+
// faded label
|
|
2941
|
+
textOnFillLight: "#f3f5f3",
|
|
2942
|
+
// weathered white
|
|
2943
|
+
textOnFillDark: "#0f2230",
|
|
2944
|
+
// deep sea
|
|
2945
|
+
primary: "#4f9bc4",
|
|
2946
|
+
// lifted sea blue
|
|
2947
|
+
secondary: "#c9a46a",
|
|
2948
|
+
// rope tan, lifted
|
|
2949
|
+
accent: "#d9b25a",
|
|
2950
|
+
// brass, lifted
|
|
2951
|
+
destructive: "#e06a5e",
|
|
2952
|
+
// signal red, lifted
|
|
2953
|
+
colors: {
|
|
2954
|
+
red: "#e06a5e",
|
|
2955
|
+
// signal-flag red
|
|
2956
|
+
orange: "#df9a52",
|
|
2957
|
+
// amber
|
|
2958
|
+
yellow: "#e0c662",
|
|
2959
|
+
// brass gold
|
|
2960
|
+
green: "#6fb58c",
|
|
2961
|
+
// sea-glass green
|
|
2962
|
+
blue: "#4f9bc4",
|
|
2963
|
+
// sea blue
|
|
2964
|
+
purple: "#9486bf",
|
|
2965
|
+
// twilight harbor
|
|
2966
|
+
teal: "#5cb0ac",
|
|
2967
|
+
// sea-glass teal
|
|
2968
|
+
cyan: "#62b4cf",
|
|
2969
|
+
// shallow water
|
|
2970
|
+
gray: "#9aa39c",
|
|
2971
|
+
// driftwood gray
|
|
2972
|
+
black: "#16303f",
|
|
2973
|
+
// raised hull
|
|
2974
|
+
white: "#e6ebe8"
|
|
2975
|
+
// weathered white
|
|
2976
|
+
}
|
|
2977
|
+
}
|
|
2978
|
+
};
|
|
2979
|
+
registerPalette(tidewaterPalette);
|
|
2980
|
+
}
|
|
2981
|
+
});
|
|
2982
|
+
|
|
2563
2983
|
// src/palettes/tokyo-night.ts
|
|
2564
2984
|
var tokyoNightPalette;
|
|
2565
2985
|
var init_tokyo_night = __esm({
|
|
@@ -2835,7 +3255,8 @@ var init_monokai = __esm({
|
|
|
2835
3255
|
// src/palettes/index.ts
|
|
2836
3256
|
var palettes_exports = {};
|
|
2837
3257
|
__export(palettes_exports, {
|
|
2838
|
-
|
|
3258
|
+
atlasPalette: () => atlasPalette,
|
|
3259
|
+
blueprintPalette: () => blueprintPalette,
|
|
2839
3260
|
catppuccinPalette: () => catppuccinPalette,
|
|
2840
3261
|
contrastText: () => contrastText,
|
|
2841
3262
|
draculaPalette: () => draculaPalette,
|
|
@@ -2856,7 +3277,9 @@ __export(palettes_exports, {
|
|
|
2856
3277
|
rosePinePalette: () => rosePinePalette,
|
|
2857
3278
|
shade: () => shade,
|
|
2858
3279
|
shapeFill: () => shapeFill,
|
|
3280
|
+
slatePalette: () => slatePalette,
|
|
2859
3281
|
solarizedPalette: () => solarizedPalette,
|
|
3282
|
+
tidewaterPalette: () => tidewaterPalette,
|
|
2860
3283
|
tint: () => tint,
|
|
2861
3284
|
tokyoNightPalette: () => tokyoNightPalette
|
|
2862
3285
|
});
|
|
@@ -2866,17 +3289,21 @@ var init_palettes = __esm({
|
|
|
2866
3289
|
"use strict";
|
|
2867
3290
|
init_registry();
|
|
2868
3291
|
init_color_utils();
|
|
2869
|
-
|
|
3292
|
+
init_atlas();
|
|
3293
|
+
init_blueprint();
|
|
2870
3294
|
init_catppuccin();
|
|
2871
3295
|
init_gruvbox();
|
|
2872
3296
|
init_nord();
|
|
2873
3297
|
init_one_dark();
|
|
2874
3298
|
init_rose_pine();
|
|
3299
|
+
init_slate();
|
|
2875
3300
|
init_solarized();
|
|
3301
|
+
init_tidewater();
|
|
2876
3302
|
init_tokyo_night();
|
|
2877
3303
|
init_dracula();
|
|
2878
3304
|
init_monokai();
|
|
2879
|
-
|
|
3305
|
+
init_atlas();
|
|
3306
|
+
init_blueprint();
|
|
2880
3307
|
init_catppuccin();
|
|
2881
3308
|
init_dracula();
|
|
2882
3309
|
init_gruvbox();
|
|
@@ -2884,9 +3311,15 @@ var init_palettes = __esm({
|
|
|
2884
3311
|
init_nord();
|
|
2885
3312
|
init_one_dark();
|
|
2886
3313
|
init_rose_pine();
|
|
3314
|
+
init_slate();
|
|
2887
3315
|
init_solarized();
|
|
3316
|
+
init_tidewater();
|
|
2888
3317
|
init_tokyo_night();
|
|
2889
3318
|
palettes = {
|
|
3319
|
+
atlas: atlasPalette,
|
|
3320
|
+
blueprint: blueprintPalette,
|
|
3321
|
+
slate: slatePalette,
|
|
3322
|
+
tidewater: tidewaterPalette,
|
|
2890
3323
|
nord: nordPalette,
|
|
2891
3324
|
catppuccin: catppuccinPalette,
|
|
2892
3325
|
solarized: solarizedPalette,
|
|
@@ -2895,8 +3328,7 @@ var init_palettes = __esm({
|
|
|
2895
3328
|
oneDark: oneDarkPalette,
|
|
2896
3329
|
rosePine: rosePinePalette,
|
|
2897
3330
|
dracula: draculaPalette,
|
|
2898
|
-
monokai: monokaiPalette
|
|
2899
|
-
bold: boldPalette
|
|
3331
|
+
monokai: monokaiPalette
|
|
2900
3332
|
};
|
|
2901
3333
|
}
|
|
2902
3334
|
});
|
|
@@ -3406,6 +3838,9 @@ function controlsGroupCapsuleWidth(toggles) {
|
|
|
3406
3838
|
}
|
|
3407
3839
|
return w;
|
|
3408
3840
|
}
|
|
3841
|
+
function isAppHostedControls(config, isExport) {
|
|
3842
|
+
return !isExport && config.controlsHost === "app" && !!config.controlsGroup && config.controlsGroup.toggles.length > 0;
|
|
3843
|
+
}
|
|
3409
3844
|
function buildControlsGroupLayout(config, state) {
|
|
3410
3845
|
const cg = config.controlsGroup;
|
|
3411
3846
|
if (!cg || cg.toggles.length === 0) return void 0;
|
|
@@ -3459,6 +3894,7 @@ function buildControlsGroupLayout(config, state) {
|
|
|
3459
3894
|
function computeLegendLayout(config, state, containerWidth) {
|
|
3460
3895
|
const { groups, controls: configControls, mode } = config;
|
|
3461
3896
|
const isExport = mode === "export";
|
|
3897
|
+
const gated = isAppHostedControls(config, isExport);
|
|
3462
3898
|
const activeGroupName = state.activeGroup?.toLowerCase() ?? null;
|
|
3463
3899
|
if (isExport && !activeGroupName) {
|
|
3464
3900
|
return {
|
|
@@ -3469,7 +3905,7 @@ function computeLegendLayout(config, state, containerWidth) {
|
|
|
3469
3905
|
pills: []
|
|
3470
3906
|
};
|
|
3471
3907
|
}
|
|
3472
|
-
const controlsGroupLayout = isExport ? void 0 : buildControlsGroupLayout(config, state);
|
|
3908
|
+
const controlsGroupLayout = isExport || gated ? void 0 : buildControlsGroupLayout(config, state);
|
|
3473
3909
|
const visibleGroups = config.showEmptyGroups ? groups : groups.filter((g) => g.entries.length > 0 || !!g.gradient);
|
|
3474
3910
|
if (visibleGroups.length === 0 && (!configControls || configControls.length === 0) && !controlsGroupLayout) {
|
|
3475
3911
|
return {
|
|
@@ -8371,8 +8807,8 @@ function computeScatterLabelGraphics(points, chartBounds, fontSize, symbolSize,
|
|
|
8371
8807
|
const pt = points[i];
|
|
8372
8808
|
const ptSize = pt.size ?? symbolSize;
|
|
8373
8809
|
const minGap = ptSize / 2 + 4;
|
|
8374
|
-
const
|
|
8375
|
-
const labelX = pt.px -
|
|
8810
|
+
const labelWidth2 = pt.name.length * fontSize * 0.6 + 8;
|
|
8811
|
+
const labelX = pt.px - labelWidth2 / 2;
|
|
8376
8812
|
let bestLabelY = 0;
|
|
8377
8813
|
let bestOffset = Infinity;
|
|
8378
8814
|
let placed = false;
|
|
@@ -8384,7 +8820,7 @@ function computeScatterLabelGraphics(points, chartBounds, fontSize, symbolSize,
|
|
|
8384
8820
|
const candidate = {
|
|
8385
8821
|
x: labelX,
|
|
8386
8822
|
y: labelY,
|
|
8387
|
-
w:
|
|
8823
|
+
w: labelWidth2,
|
|
8388
8824
|
h: labelHeight
|
|
8389
8825
|
};
|
|
8390
8826
|
let collision = false;
|
|
@@ -8426,7 +8862,7 @@ function computeScatterLabelGraphics(points, chartBounds, fontSize, symbolSize,
|
|
|
8426
8862
|
const labelRect = {
|
|
8427
8863
|
x: labelX,
|
|
8428
8864
|
y: bestLabelY,
|
|
8429
|
-
w:
|
|
8865
|
+
w: labelWidth2,
|
|
8430
8866
|
h: labelHeight
|
|
8431
8867
|
};
|
|
8432
8868
|
placedLabels.push(labelRect);
|
|
@@ -8462,7 +8898,7 @@ function computeScatterLabelGraphics(points, chartBounds, fontSize, symbolSize,
|
|
|
8462
8898
|
shape: {
|
|
8463
8899
|
x: labelX - bgPad,
|
|
8464
8900
|
y: bestLabelY - bgPad,
|
|
8465
|
-
width:
|
|
8901
|
+
width: labelWidth2 + bgPad * 2,
|
|
8466
8902
|
height: labelHeight + bgPad * 2
|
|
8467
8903
|
},
|
|
8468
8904
|
style: { fill: bg },
|
|
@@ -15898,10 +16334,6 @@ function parseMap(content) {
|
|
|
15898
16334
|
handleTag(trimmed, lineNumber);
|
|
15899
16335
|
continue;
|
|
15900
16336
|
}
|
|
15901
|
-
if ((firstWord === "muted" || firstWord === "natural") && trimmed === firstWord) {
|
|
15902
|
-
handleDirective(firstWord, "", lineNumber);
|
|
15903
|
-
continue;
|
|
15904
|
-
}
|
|
15905
16337
|
if (DIRECTIVE_SET.has(firstWord) && !trimmed.slice(firstWord.length).trimStart().startsWith(":")) {
|
|
15906
16338
|
handleDirective(
|
|
15907
16339
|
firstWord,
|
|
@@ -15948,28 +16380,13 @@ function parseMap(content) {
|
|
|
15948
16380
|
pushWarning(line12, `Duplicate directive "${key}" \u2014 last value wins.`);
|
|
15949
16381
|
};
|
|
15950
16382
|
switch (key) {
|
|
15951
|
-
case "region":
|
|
15952
|
-
dup(d.region);
|
|
15953
|
-
d.region = value;
|
|
15954
|
-
break;
|
|
15955
|
-
case "projection":
|
|
15956
|
-
dup(d.projection);
|
|
15957
|
-
if (value && ![
|
|
15958
|
-
"equirectangular",
|
|
15959
|
-
"natural-earth",
|
|
15960
|
-
"albers-usa",
|
|
15961
|
-
"mercator"
|
|
15962
|
-
].includes(value))
|
|
15963
|
-
pushWarning(
|
|
15964
|
-
line12,
|
|
15965
|
-
`Unknown projection "${value}" (expected equirectangular | natural-earth | albers-usa | mercator).`
|
|
15966
|
-
);
|
|
15967
|
-
d.projection = value;
|
|
15968
|
-
break;
|
|
15969
|
-
case "region-metric":
|
|
16383
|
+
case "region-metric": {
|
|
15970
16384
|
dup(d.regionMetric);
|
|
15971
|
-
|
|
16385
|
+
const { label: rmLabel, colorName: rmColor } = peelTrailingColorName(value);
|
|
16386
|
+
d.regionMetric = rmLabel;
|
|
16387
|
+
if (rmColor) d.regionMetricColor = rmColor;
|
|
15972
16388
|
break;
|
|
16389
|
+
}
|
|
15973
16390
|
case "poi-metric":
|
|
15974
16391
|
dup(d.poiMetric);
|
|
15975
16392
|
d.poiMetric = value;
|
|
@@ -15978,85 +16395,43 @@ function parseMap(content) {
|
|
|
15978
16395
|
dup(d.flowMetric);
|
|
15979
16396
|
d.flowMetric = value;
|
|
15980
16397
|
break;
|
|
15981
|
-
case "
|
|
15982
|
-
dup(d.
|
|
15983
|
-
|
|
15984
|
-
const s = parseScale(value, line12);
|
|
15985
|
-
if (s) d.scale = s;
|
|
15986
|
-
}
|
|
15987
|
-
break;
|
|
15988
|
-
case "region-labels":
|
|
15989
|
-
dup(d.regionLabels);
|
|
15990
|
-
if (value && !["full", "abbrev", "off"].includes(value))
|
|
15991
|
-
pushWarning(
|
|
15992
|
-
line12,
|
|
15993
|
-
`Unknown region-labels "${value}" (expected full | abbrev | off).`
|
|
15994
|
-
);
|
|
15995
|
-
d.regionLabels = value;
|
|
15996
|
-
break;
|
|
15997
|
-
case "poi-labels":
|
|
15998
|
-
dup(d.poiLabels);
|
|
15999
|
-
if (value && !["off", "auto", "all"].includes(value))
|
|
16000
|
-
pushWarning(
|
|
16001
|
-
line12,
|
|
16002
|
-
`Unknown poi-labels "${value}" (expected off | auto | all).`
|
|
16003
|
-
);
|
|
16004
|
-
d.poiLabels = value;
|
|
16005
|
-
break;
|
|
16006
|
-
case "default-country":
|
|
16007
|
-
dup(d.defaultCountry);
|
|
16008
|
-
d.defaultCountry = value;
|
|
16009
|
-
break;
|
|
16010
|
-
case "default-state":
|
|
16011
|
-
dup(d.defaultState);
|
|
16012
|
-
d.defaultState = value;
|
|
16398
|
+
case "locale":
|
|
16399
|
+
dup(d.locale);
|
|
16400
|
+
d.locale = value;
|
|
16013
16401
|
break;
|
|
16014
16402
|
case "active-tag":
|
|
16015
16403
|
dup(d.activeTag);
|
|
16016
16404
|
d.activeTag = value;
|
|
16017
16405
|
break;
|
|
16406
|
+
case "caption":
|
|
16407
|
+
dup(d.caption);
|
|
16408
|
+
d.caption = value;
|
|
16409
|
+
break;
|
|
16410
|
+
// ── Cosmetic `no-*` opt-outs: bare flags, idempotent (mirror `no-legend`,
|
|
16411
|
+
// no dup warning); each defaults the feature ON when absent. ──
|
|
16018
16412
|
case "no-legend":
|
|
16019
16413
|
d.noLegend = true;
|
|
16020
16414
|
break;
|
|
16021
|
-
case "
|
|
16022
|
-
|
|
16023
|
-
if (d.basemapStyle !== void 0 && d.basemapStyle !== key)
|
|
16024
|
-
pushWarning(
|
|
16025
|
-
line12,
|
|
16026
|
-
`Conflicting basemap dress \u2014 "${d.basemapStyle}" then "${key}"; last wins.`
|
|
16027
|
-
);
|
|
16028
|
-
d.basemapStyle = key;
|
|
16415
|
+
case "no-coastline":
|
|
16416
|
+
d.noCoastline = true;
|
|
16029
16417
|
break;
|
|
16030
|
-
case "
|
|
16031
|
-
|
|
16032
|
-
d.subtitle = value;
|
|
16418
|
+
case "no-relief":
|
|
16419
|
+
d.noRelief = true;
|
|
16033
16420
|
break;
|
|
16034
|
-
case "
|
|
16035
|
-
|
|
16036
|
-
|
|
16421
|
+
case "no-context-labels":
|
|
16422
|
+
d.noContextLabels = true;
|
|
16423
|
+
break;
|
|
16424
|
+
case "no-region-labels":
|
|
16425
|
+
d.noRegionLabels = true;
|
|
16426
|
+
break;
|
|
16427
|
+
case "no-poi-labels":
|
|
16428
|
+
d.noPoiLabels = true;
|
|
16429
|
+
break;
|
|
16430
|
+
case "no-colorize":
|
|
16431
|
+
d.noColorize = true;
|
|
16037
16432
|
break;
|
|
16038
16433
|
}
|
|
16039
16434
|
}
|
|
16040
|
-
function parseScale(value, line12) {
|
|
16041
|
-
const toks = value.split(/\s+/).filter(Boolean);
|
|
16042
|
-
const min = Number(toks[0]);
|
|
16043
|
-
const max = Number(toks[1]);
|
|
16044
|
-
if (!Number.isFinite(min) || !Number.isFinite(max)) {
|
|
16045
|
-
pushError(line12, `scale requires numeric <min> <max> (got "${value}").`);
|
|
16046
|
-
return null;
|
|
16047
|
-
}
|
|
16048
|
-
const scale = { min, max };
|
|
16049
|
-
if (toks[2] === "center") {
|
|
16050
|
-
const c = Number(toks[3]);
|
|
16051
|
-
if (Number.isFinite(c)) scale.center = c;
|
|
16052
|
-
else
|
|
16053
|
-
pushError(
|
|
16054
|
-
line12,
|
|
16055
|
-
`scale center requires a number (got "${toks[3] ?? ""}").`
|
|
16056
|
-
);
|
|
16057
|
-
}
|
|
16058
|
-
return scale;
|
|
16059
|
-
}
|
|
16060
16435
|
function handleTag(trimmed, line12) {
|
|
16061
16436
|
const m = matchTagBlockHeading(trimmed);
|
|
16062
16437
|
if (!m) {
|
|
@@ -16130,6 +16505,7 @@ function parseMap(content) {
|
|
|
16130
16505
|
};
|
|
16131
16506
|
if (regionScope !== void 0) region.scope = regionScope;
|
|
16132
16507
|
if (valueNum !== void 0) region.value = valueNum;
|
|
16508
|
+
if (split.color) region.color = split.color;
|
|
16133
16509
|
regions.push(region);
|
|
16134
16510
|
}
|
|
16135
16511
|
function handlePoi(rest, line12, indent) {
|
|
@@ -16154,6 +16530,7 @@ function parseMap(content) {
|
|
|
16154
16530
|
const poi = { pos, tags, meta, lineNumber: line12 };
|
|
16155
16531
|
if (split.alias) poi.alias = split.alias;
|
|
16156
16532
|
if (label !== void 0) poi.label = label;
|
|
16533
|
+
if (split.color) poi.color = split.color;
|
|
16157
16534
|
pois.push(poi);
|
|
16158
16535
|
open.poi = { poi, indent };
|
|
16159
16536
|
}
|
|
@@ -16254,13 +16631,15 @@ function parseMap(content) {
|
|
|
16254
16631
|
pushError(line12, `Edge has an empty endpoint: "${trimmed}".`);
|
|
16255
16632
|
continue;
|
|
16256
16633
|
}
|
|
16257
|
-
const
|
|
16634
|
+
const isLast = k === links.length - 1;
|
|
16635
|
+
const meta = isLast ? lastSplit.meta : {};
|
|
16636
|
+
const style = links[k].style === "arc" ? "arc" : "straight";
|
|
16258
16637
|
edges.push({
|
|
16259
16638
|
from,
|
|
16260
16639
|
to,
|
|
16261
16640
|
...links[k].label !== void 0 && { label: links[k].label },
|
|
16262
16641
|
directed: links[k].directed,
|
|
16263
|
-
style
|
|
16642
|
+
style,
|
|
16264
16643
|
meta,
|
|
16265
16644
|
lineNumber: line12
|
|
16266
16645
|
});
|
|
@@ -16346,20 +16725,19 @@ var init_parser12 = __esm({
|
|
|
16346
16725
|
LEG_ARROW_RE = /^(-[^>]*?->|->|~[^>]*?~>|~>|--)\s+(.+)$/;
|
|
16347
16726
|
AT_RE = /(^|[\s,])at\s*:/i;
|
|
16348
16727
|
DIRECTIVE_SET = /* @__PURE__ */ new Set([
|
|
16349
|
-
"region",
|
|
16350
|
-
"projection",
|
|
16351
16728
|
"region-metric",
|
|
16352
16729
|
"poi-metric",
|
|
16353
16730
|
"flow-metric",
|
|
16354
|
-
"
|
|
16355
|
-
"region-labels",
|
|
16356
|
-
"poi-labels",
|
|
16357
|
-
"default-country",
|
|
16358
|
-
"default-state",
|
|
16731
|
+
"locale",
|
|
16359
16732
|
"active-tag",
|
|
16733
|
+
"caption",
|
|
16360
16734
|
"no-legend",
|
|
16361
|
-
"
|
|
16362
|
-
"
|
|
16735
|
+
"no-coastline",
|
|
16736
|
+
"no-relief",
|
|
16737
|
+
"no-context-labels",
|
|
16738
|
+
"no-region-labels",
|
|
16739
|
+
"no-poi-labels",
|
|
16740
|
+
"no-colorize"
|
|
16363
16741
|
]);
|
|
16364
16742
|
}
|
|
16365
16743
|
});
|
|
@@ -24281,8 +24659,8 @@ function renderKanban(container, parsed, palette, isDark, options) {
|
|
|
24281
24659
|
let metaY = separatorY + sCardSeparatorGap + sCardMetaFontSize;
|
|
24282
24660
|
for (const meta of tagMeta) {
|
|
24283
24661
|
cg.append("text").attr("x", cx + sCardPaddingX).attr("y", metaY).attr("font-size", sCardMetaFontSize).attr("fill", onCardText).text(`${meta.label}: `);
|
|
24284
|
-
const
|
|
24285
|
-
cg.append("text").attr("x", cx + sCardPaddingX +
|
|
24662
|
+
const labelWidth2 = (meta.label.length + 2) * sCardMetaFontSize * 0.6;
|
|
24663
|
+
cg.append("text").attr("x", cx + sCardPaddingX + labelWidth2).attr("y", metaY).attr("font-size", sCardMetaFontSize).attr("fill", onCardText).text(meta.value);
|
|
24286
24664
|
metaY += sCardMetaLineHeight;
|
|
24287
24665
|
}
|
|
24288
24666
|
for (const detail of card.details) {
|
|
@@ -24626,8 +25004,8 @@ function renderSwimlaneCard(parent, cardLayout, tagGroups, activeTagGroup, palet
|
|
|
24626
25004
|
let metaY = separatorY + sCardSeparatorGap + sCardMetaFontSize;
|
|
24627
25005
|
for (const meta of tagMeta) {
|
|
24628
25006
|
cg.append("text").attr("x", cx + sCardPaddingX).attr("y", metaY).attr("font-size", sCardMetaFontSize).attr("fill", palette.textMuted).text(`${meta.label}: `);
|
|
24629
|
-
const
|
|
24630
|
-
cg.append("text").attr("x", cx + sCardPaddingX +
|
|
25007
|
+
const labelWidth2 = (meta.label.length + 2) * sCardMetaFontSize * 0.6;
|
|
25008
|
+
cg.append("text").attr("x", cx + sCardPaddingX + labelWidth2).attr("y", metaY).attr("font-size", sCardMetaFontSize).attr("fill", onCardText).text(meta.value);
|
|
24631
25009
|
metaY += sCardMetaLineHeight;
|
|
24632
25010
|
}
|
|
24633
25011
|
for (const detail of card.details) {
|
|
@@ -25461,8 +25839,8 @@ function classifyEREntities(tables, relationships) {
|
|
|
25461
25839
|
}
|
|
25462
25840
|
}
|
|
25463
25841
|
const mmParticipants = /* @__PURE__ */ new Set();
|
|
25464
|
-
for (const [id,
|
|
25465
|
-
if (
|
|
25842
|
+
for (const [id, neighbors2] of tableStarNeighbors) {
|
|
25843
|
+
if (neighbors2.size >= 2) mmParticipants.add(id);
|
|
25466
25844
|
}
|
|
25467
25845
|
const indegreeValues = Object.values(indegreeMap);
|
|
25468
25846
|
const mean = indegreeValues.reduce((a, b) => a + b, 0) / indegreeValues.length;
|
|
@@ -26135,7 +26513,8 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26135
26513
|
controlsExpanded,
|
|
26136
26514
|
onToggleDescriptions,
|
|
26137
26515
|
onToggleControlsExpand,
|
|
26138
|
-
exportMode = false
|
|
26516
|
+
exportMode = false,
|
|
26517
|
+
controlsHost
|
|
26139
26518
|
} = options ?? {};
|
|
26140
26519
|
d3Selection6.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
26141
26520
|
const width = exportDims?.width ?? container.clientWidth;
|
|
@@ -26153,7 +26532,11 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26153
26532
|
const sGroupLabelZone = sctx.structural(GROUP_LABEL_ZONE);
|
|
26154
26533
|
const sTitleFontSize = sctx.text(TITLE_FONT_SIZE);
|
|
26155
26534
|
const sTitleY = sctx.structural(TITLE_Y);
|
|
26156
|
-
const
|
|
26535
|
+
const reserveHasDescriptions = parsed.nodes.some(
|
|
26536
|
+
(n) => n.description && n.description.length > 0
|
|
26537
|
+
);
|
|
26538
|
+
const willRenderLegend = parsed.tagGroups.length > 0 || reserveHasDescriptions && controlsHost !== "app";
|
|
26539
|
+
const sLegendHeight = willRenderLegend ? sctx.structural(
|
|
26157
26540
|
getMaxLegendReservedHeight(
|
|
26158
26541
|
{
|
|
26159
26542
|
groups: parsed.tagGroups,
|
|
@@ -26162,7 +26545,7 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26162
26545
|
},
|
|
26163
26546
|
width
|
|
26164
26547
|
)
|
|
26165
|
-
);
|
|
26548
|
+
) : 0;
|
|
26166
26549
|
const activeGroup = resolveActiveTagGroup(
|
|
26167
26550
|
parsed.tagGroups,
|
|
26168
26551
|
parsed.options["active-tag"],
|
|
@@ -26477,10 +26860,10 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26477
26860
|
const hasDescriptions = parsed.nodes.some(
|
|
26478
26861
|
(n) => n.description && n.description.length > 0
|
|
26479
26862
|
);
|
|
26480
|
-
const hasLegend = parsed.tagGroups.length > 0 || hasDescriptions;
|
|
26863
|
+
const hasLegend = parsed.tagGroups.length > 0 || hasDescriptions && controlsHost !== "app";
|
|
26481
26864
|
if (hasLegend) {
|
|
26482
26865
|
let controlsGroup;
|
|
26483
|
-
if (hasDescriptions && onToggleDescriptions) {
|
|
26866
|
+
if (hasDescriptions && (onToggleDescriptions || controlsHost === "app")) {
|
|
26484
26867
|
controlsGroup = {
|
|
26485
26868
|
toggles: [
|
|
26486
26869
|
{
|
|
@@ -26498,7 +26881,14 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26498
26881
|
groups: parsed.tagGroups,
|
|
26499
26882
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
26500
26883
|
mode: exportMode ? "export" : "preview",
|
|
26501
|
-
|
|
26884
|
+
// Keep inactive sibling tag groups visible as collapsed pills so the user
|
|
26885
|
+
// can click one to flip the active colouring dimension (preview only —
|
|
26886
|
+
// export shows just the active group). Without this, declaring a second
|
|
26887
|
+
// tag group (e.g. Team) leaves it invisible whenever another group is
|
|
26888
|
+
// active. The app's BoxesAndLinesPreview already wires pill clicks.
|
|
26889
|
+
showInactivePills: true,
|
|
26890
|
+
...controlsGroup !== void 0 && { controlsGroup },
|
|
26891
|
+
...controlsHost !== void 0 && { controlsHost }
|
|
26502
26892
|
};
|
|
26503
26893
|
const legendState = {
|
|
26504
26894
|
activeGroup,
|
|
@@ -27745,8 +28135,9 @@ function renderMindmap(container, parsed, layout, palette, isDark, onClickItem,
|
|
|
27745
28135
|
const containerHeight = exportDims?.height ?? (container.getBoundingClientRect().height || 600);
|
|
27746
28136
|
d3Selection7.select(container).selectAll("*").remove();
|
|
27747
28137
|
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);
|
|
28138
|
+
const appHosted = options?.controlsHost === "app";
|
|
27748
28139
|
const hasControls = !!options?.onToggleColorByDepth || !!options?.onToggleDescriptions;
|
|
27749
|
-
const hasLegend = parsed.tagGroups.length > 0 || hasControls;
|
|
28140
|
+
const hasLegend = parsed.tagGroups.length > 0 || hasControls && !appHosted;
|
|
27750
28141
|
const fixedLegend = !isExport && hasLegend;
|
|
27751
28142
|
const legendReserve = fixedLegend ? getMaxLegendReservedHeight(
|
|
27752
28143
|
{
|
|
@@ -27840,7 +28231,10 @@ function renderMindmap(container, parsed, layout, palette, isDark, onClickItem,
|
|
|
27840
28231
|
}),
|
|
27841
28232
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
27842
28233
|
mode: options?.exportMode ? "export" : "preview",
|
|
27843
|
-
...controlsToggles !== void 0 && { controlsGroup: controlsToggles }
|
|
28234
|
+
...controlsToggles !== void 0 && { controlsGroup: controlsToggles },
|
|
28235
|
+
...options?.controlsHost !== void 0 && {
|
|
28236
|
+
controlsHost: options.controlsHost
|
|
28237
|
+
}
|
|
27844
28238
|
};
|
|
27845
28239
|
const legendState = {
|
|
27846
28240
|
activeGroup: options?.colorByDepth ? null : activeTagGroup !== void 0 ? activeTagGroup : parsed.options["active-tag"] ?? null,
|
|
@@ -28283,8 +28677,8 @@ function computeFieldAlignX(children) {
|
|
|
28283
28677
|
for (const child of children) {
|
|
28284
28678
|
if (child.metadata["_labelField"] === "true" && child.children.length >= 2) {
|
|
28285
28679
|
const labelEl = child.children[0];
|
|
28286
|
-
const
|
|
28287
|
-
maxLabelWidth = Math.max(maxLabelWidth,
|
|
28680
|
+
const labelWidth2 = labelEl.label.length * CHAR_WIDTH5;
|
|
28681
|
+
maxLabelWidth = Math.max(maxLabelWidth, labelWidth2);
|
|
28288
28682
|
labelFieldCount++;
|
|
28289
28683
|
}
|
|
28290
28684
|
}
|
|
@@ -33249,7 +33643,7 @@ function hasRoles(node) {
|
|
|
33249
33643
|
function computeNodeWidth2(node, expanded, options) {
|
|
33250
33644
|
const badgeVal = node.computedConcurrentInvocations === 0 && node.computedInstances > 1 ? node.computedInstances : 0;
|
|
33251
33645
|
const badgeLen = badgeVal > 0 ? `${badgeVal}x`.length + 2 : 0;
|
|
33252
|
-
const
|
|
33646
|
+
const labelWidth2 = (node.label.length + badgeLen) * CHAR_WIDTH7 + PADDING_X3;
|
|
33253
33647
|
const allKeys = [];
|
|
33254
33648
|
if (node.computedRps > 0) allKeys.push("RPS");
|
|
33255
33649
|
if (expanded) {
|
|
@@ -33293,7 +33687,7 @@ function computeNodeWidth2(node, expanded, options) {
|
|
|
33293
33687
|
allKeys.push("overflow");
|
|
33294
33688
|
}
|
|
33295
33689
|
}
|
|
33296
|
-
if (allKeys.length === 0) return Math.max(MIN_NODE_WIDTH2,
|
|
33690
|
+
if (allKeys.length === 0) return Math.max(MIN_NODE_WIDTH2, labelWidth2);
|
|
33297
33691
|
const maxKeyLen = Math.max(...allKeys.map((k) => k.length));
|
|
33298
33692
|
let maxRowWidth = 0;
|
|
33299
33693
|
if (node.computedRps > 0) {
|
|
@@ -33381,7 +33775,7 @@ function computeNodeWidth2(node, expanded, options) {
|
|
|
33381
33775
|
truncated.length * META_CHAR_WIDTH3 + PADDING_X3
|
|
33382
33776
|
);
|
|
33383
33777
|
}
|
|
33384
|
-
return Math.max(MIN_NODE_WIDTH2,
|
|
33778
|
+
return Math.max(MIN_NODE_WIDTH2, labelWidth2, maxRowWidth + 20, descWidth);
|
|
33385
33779
|
}
|
|
33386
33780
|
function computeNodeHeight2(node, expanded, options) {
|
|
33387
33781
|
const propCount = countDisplayProps(node, expanded, options);
|
|
@@ -34931,8 +35325,9 @@ function computeInfraLegendGroups(nodes, tagGroups, palette, edges) {
|
|
|
34931
35325
|
}
|
|
34932
35326
|
return groups;
|
|
34933
35327
|
}
|
|
34934
|
-
function renderLegend3(rootSvg, legendGroups, totalWidth, legendY, palette, isDark, activeGroup, playback, exportMode = false) {
|
|
35328
|
+
function renderLegend3(rootSvg, legendGroups, totalWidth, legendY, palette, isDark, activeGroup, playback, exportMode = false, controlsHost) {
|
|
34935
35329
|
if (legendGroups.length === 0 && !playback) return;
|
|
35330
|
+
const appHostedPlayback = controlsHost === "app" && !!playback;
|
|
34936
35331
|
const legendG = rootSvg.append("g").attr("transform", `translate(0, ${legendY})`);
|
|
34937
35332
|
if (activeGroup) {
|
|
34938
35333
|
legendG.attr("data-legend-active", activeGroup.toLowerCase());
|
|
@@ -34941,14 +35336,29 @@ function renderLegend3(rootSvg, legendGroups, totalWidth, legendY, palette, isDa
|
|
|
34941
35336
|
name: g.name,
|
|
34942
35337
|
entries: g.entries.map((e) => ({ value: e.value, color: e.color }))
|
|
34943
35338
|
}));
|
|
34944
|
-
if (playback) {
|
|
35339
|
+
if (playback && !appHostedPlayback) {
|
|
34945
35340
|
allGroups.push({ name: "Playback", entries: [] });
|
|
34946
35341
|
}
|
|
34947
35342
|
const legendConfig = {
|
|
34948
35343
|
groups: allGroups,
|
|
34949
35344
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
34950
35345
|
mode: exportMode ? "export" : "preview",
|
|
34951
|
-
showEmptyGroups: true
|
|
35346
|
+
showEmptyGroups: true,
|
|
35347
|
+
...appHostedPlayback && {
|
|
35348
|
+
controlsHost: "app",
|
|
35349
|
+
controlsGroup: {
|
|
35350
|
+
toggles: [
|
|
35351
|
+
{
|
|
35352
|
+
id: "playback",
|
|
35353
|
+
type: "toggle",
|
|
35354
|
+
label: "Playback",
|
|
35355
|
+
active: true,
|
|
35356
|
+
onToggle: () => {
|
|
35357
|
+
}
|
|
35358
|
+
}
|
|
35359
|
+
]
|
|
35360
|
+
}
|
|
35361
|
+
}
|
|
34952
35362
|
};
|
|
34953
35363
|
const legendState = { activeGroup };
|
|
34954
35364
|
renderLegendD3(
|
|
@@ -34999,8 +35409,9 @@ function renderLegend3(rootSvg, legendGroups, totalWidth, legendY, palette, isDa
|
|
|
34999
35409
|
}
|
|
35000
35410
|
}
|
|
35001
35411
|
}
|
|
35002
|
-
function renderInfra(container, layout, palette, isDark, title, titleLineNumber, tagGroups, activeGroup, animate, playback, expandedNodeIds, exportMode, collapsedNodes) {
|
|
35412
|
+
function renderInfra(container, layout, palette, isDark, title, titleLineNumber, tagGroups, activeGroup, animate, playback, expandedNodeIds, exportMode, collapsedNodes, controlsHost) {
|
|
35003
35413
|
d3Selection11.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
35414
|
+
const appHostedPlayback = controlsHost === "app" && !!playback;
|
|
35004
35415
|
const ctx = ScaleContext.identity();
|
|
35005
35416
|
const sc = buildScaledConstants(ctx);
|
|
35006
35417
|
const legendGroups = computeInfraLegendGroups(
|
|
@@ -35009,7 +35420,7 @@ function renderInfra(container, layout, palette, isDark, title, titleLineNumber,
|
|
|
35009
35420
|
palette,
|
|
35010
35421
|
layout.edges
|
|
35011
35422
|
);
|
|
35012
|
-
const hasLegend = legendGroups.length > 0 || !!playback;
|
|
35423
|
+
const hasLegend = legendGroups.length > 0 || !!playback && !appHostedPlayback;
|
|
35013
35424
|
const fixedLegend = !exportMode && hasLegend;
|
|
35014
35425
|
const legendDynamicH = hasLegend ? getMaxLegendReservedHeight(
|
|
35015
35426
|
{
|
|
@@ -35153,7 +35564,8 @@ function renderInfra(container, layout, palette, isDark, title, titleLineNumber,
|
|
|
35153
35564
|
isDark,
|
|
35154
35565
|
activeGroup ?? null,
|
|
35155
35566
|
playback ?? void 0,
|
|
35156
|
-
exportMode
|
|
35567
|
+
exportMode,
|
|
35568
|
+
controlsHost
|
|
35157
35569
|
);
|
|
35158
35570
|
legendSvg.selectAll(".infra-legend-group").style("pointer-events", "auto");
|
|
35159
35571
|
} else {
|
|
@@ -35166,7 +35578,8 @@ function renderInfra(container, layout, palette, isDark, title, titleLineNumber,
|
|
|
35166
35578
|
isDark,
|
|
35167
35579
|
activeGroup ?? null,
|
|
35168
35580
|
playback ?? void 0,
|
|
35169
|
-
exportMode
|
|
35581
|
+
exportMode,
|
|
35582
|
+
controlsHost
|
|
35170
35583
|
);
|
|
35171
35584
|
}
|
|
35172
35585
|
}
|
|
@@ -42800,6 +43213,9 @@ function renderTechRadar(container, parsed, palette, isDark, onClickItem, export
|
|
|
42800
43213
|
onToggle: (active) => options.onToggleListing(active)
|
|
42801
43214
|
}
|
|
42802
43215
|
]
|
|
43216
|
+
},
|
|
43217
|
+
...options.controlsHost !== void 0 && {
|
|
43218
|
+
controlsHost: options.controlsHost
|
|
42803
43219
|
}
|
|
42804
43220
|
};
|
|
42805
43221
|
const legendState = {
|
|
@@ -44622,7 +45038,7 @@ function computeCycleLayout(parsed, options) {
|
|
|
44622
45038
|
const circleNodes = parsed.options["circle-nodes"] === "true";
|
|
44623
45039
|
const nodeDims = parsed.nodes.map((node) => {
|
|
44624
45040
|
const hasDesc = !hideDescriptions && node.description.length > 0;
|
|
44625
|
-
const
|
|
45041
|
+
const labelWidth2 = Math.max(
|
|
44626
45042
|
MIN_NODE_WIDTH4,
|
|
44627
45043
|
node.label.length * LABEL_CHAR_W + NODE_PAD_X * 2
|
|
44628
45044
|
);
|
|
@@ -44631,12 +45047,12 @@ function computeCycleLayout(parsed, options) {
|
|
|
44631
45047
|
}
|
|
44632
45048
|
if (!hasDesc) {
|
|
44633
45049
|
return {
|
|
44634
|
-
width: Math.min(MAX_NODE_WIDTH3,
|
|
45050
|
+
width: Math.min(MAX_NODE_WIDTH3, labelWidth2),
|
|
44635
45051
|
height: PLAIN_NODE_HEIGHT,
|
|
44636
45052
|
wrappedDesc: []
|
|
44637
45053
|
};
|
|
44638
45054
|
}
|
|
44639
|
-
return chooseDescribedRectDims(node.description,
|
|
45055
|
+
return chooseDescribedRectDims(node.description, labelWidth2);
|
|
44640
45056
|
});
|
|
44641
45057
|
if (circleNodes) {
|
|
44642
45058
|
const maxDiam = Math.max(...nodeDims.map((d) => d.width));
|
|
@@ -44832,10 +45248,10 @@ function computeCycleLayout(parsed, options) {
|
|
|
44832
45248
|
scale
|
|
44833
45249
|
};
|
|
44834
45250
|
}
|
|
44835
|
-
function chooseDescribedRectDims(description,
|
|
45251
|
+
function chooseDescribedRectDims(description, labelWidth2) {
|
|
44836
45252
|
const minW = Math.min(
|
|
44837
45253
|
MAX_NODE_WIDTH3,
|
|
44838
|
-
Math.max(MIN_NODE_WIDTH4,
|
|
45254
|
+
Math.max(MIN_NODE_WIDTH4, labelWidth2, DESC_MIN_WIDTH)
|
|
44839
45255
|
);
|
|
44840
45256
|
let best = null;
|
|
44841
45257
|
let bestScore = Infinity;
|
|
@@ -45264,7 +45680,8 @@ function renderCycle(container, parsed, palette, isDark, onClickItem, exportDims
|
|
|
45264
45680
|
const hideDescriptions = (renderOptions?.hideDescriptions ?? false) || parsed.options["no-descriptions"] === "true" || viewState?.hd === true;
|
|
45265
45681
|
const showDescriptions = !hideDescriptions;
|
|
45266
45682
|
const hasDescriptions = parsed.nodes.some((n) => n.description.length > 0) || parsed.edges.some((e) => e.description.length > 0);
|
|
45267
|
-
const
|
|
45683
|
+
const appHostedControls = renderOptions?.controlsHost === "app";
|
|
45684
|
+
const hasLegend = !appHostedControls && hasDescriptions && !!renderOptions?.onToggleDescriptions;
|
|
45268
45685
|
const showTitle = !!parsed.title && parsed.options["no-title"] !== "on";
|
|
45269
45686
|
const legendOffset = hasLegend ? sLegendHeight : 0;
|
|
45270
45687
|
const layoutHeight = height - (showTitle ? sTitleAreaHeight : 0) - legendOffset;
|
|
@@ -45301,7 +45718,10 @@ function renderCycle(container, parsed, palette, isDark, onClickItem, exportDims
|
|
|
45301
45718
|
groups: [],
|
|
45302
45719
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
45303
45720
|
mode: renderOptions?.exportMode ? "export" : "preview",
|
|
45304
|
-
controlsGroup
|
|
45721
|
+
controlsGroup,
|
|
45722
|
+
...renderOptions?.controlsHost !== void 0 && {
|
|
45723
|
+
controlsHost: renderOptions.controlsHost
|
|
45724
|
+
}
|
|
45305
45725
|
};
|
|
45306
45726
|
const legendState = {
|
|
45307
45727
|
activeGroup: null,
|
|
@@ -45555,8 +45975,8 @@ var init_renderer15 = __esm({
|
|
|
45555
45975
|
});
|
|
45556
45976
|
|
|
45557
45977
|
// src/map/geo.ts
|
|
45558
|
-
import { feature } from "topojson-client";
|
|
45559
|
-
import { geoBounds } from "d3-geo";
|
|
45978
|
+
import { feature, neighbors } from "topojson-client";
|
|
45979
|
+
import { geoBounds, geoArea } from "d3-geo";
|
|
45560
45980
|
function geomObject(topo) {
|
|
45561
45981
|
const key = Object.keys(topo.objects)[0];
|
|
45562
45982
|
return topo.objects[key];
|
|
@@ -45573,6 +45993,107 @@ function featureIndex(topo) {
|
|
|
45573
45993
|
}
|
|
45574
45994
|
return idx;
|
|
45575
45995
|
}
|
|
45996
|
+
function buildAdjacency(topo) {
|
|
45997
|
+
const cached = adjacencyCache.get(topo);
|
|
45998
|
+
if (cached) return cached;
|
|
45999
|
+
const geometries = geomObject(topo).geometries;
|
|
46000
|
+
const nb = neighbors(geometries);
|
|
46001
|
+
const sets = /* @__PURE__ */ new Map();
|
|
46002
|
+
geometries.forEach((g, i) => {
|
|
46003
|
+
if (!g.type || g.type === "null") return;
|
|
46004
|
+
let set = sets.get(g.id);
|
|
46005
|
+
if (!set) {
|
|
46006
|
+
set = /* @__PURE__ */ new Set();
|
|
46007
|
+
sets.set(g.id, set);
|
|
46008
|
+
}
|
|
46009
|
+
for (const j of nb[i] ?? []) {
|
|
46010
|
+
const nid = geometries[j]?.id;
|
|
46011
|
+
if (nid && nid !== g.id) set.add(nid);
|
|
46012
|
+
}
|
|
46013
|
+
});
|
|
46014
|
+
const out = /* @__PURE__ */ new Map();
|
|
46015
|
+
for (const [iso, set] of sets) out.set(iso, [...set].sort());
|
|
46016
|
+
adjacencyCache.set(topo, out);
|
|
46017
|
+
return out;
|
|
46018
|
+
}
|
|
46019
|
+
function decodeFeatures(topo) {
|
|
46020
|
+
return geomObject(topo).geometries.map((g) => {
|
|
46021
|
+
const f = feature(topo, g);
|
|
46022
|
+
return {
|
|
46023
|
+
type: "Feature",
|
|
46024
|
+
id: g.id,
|
|
46025
|
+
properties: g.properties,
|
|
46026
|
+
geometry: f.geometry
|
|
46027
|
+
};
|
|
46028
|
+
});
|
|
46029
|
+
}
|
|
46030
|
+
function pointInRing(lon, lat, ring) {
|
|
46031
|
+
let inside = false;
|
|
46032
|
+
for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
|
|
46033
|
+
const xi = ring[i][0];
|
|
46034
|
+
const yi = ring[i][1];
|
|
46035
|
+
const xj = ring[j][0];
|
|
46036
|
+
const yj = ring[j][1];
|
|
46037
|
+
const intersect = yi > lat !== yj > lat && lon < (xj - xi) * (lat - yi) / (yj - yi) + xi;
|
|
46038
|
+
if (intersect) inside = !inside;
|
|
46039
|
+
}
|
|
46040
|
+
return inside;
|
|
46041
|
+
}
|
|
46042
|
+
function pointOnRingEdge(lon, lat, ring) {
|
|
46043
|
+
for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
|
|
46044
|
+
const xi = ring[i][0];
|
|
46045
|
+
const yi = ring[i][1];
|
|
46046
|
+
const xj = ring[j][0];
|
|
46047
|
+
const yj = ring[j][1];
|
|
46048
|
+
if (lon < Math.min(xi, xj) - EDGE_EPS || lon > Math.max(xi, xj) + EDGE_EPS)
|
|
46049
|
+
continue;
|
|
46050
|
+
if (lat < Math.min(yi, yj) - EDGE_EPS || lat > Math.max(yi, yj) + EDGE_EPS)
|
|
46051
|
+
continue;
|
|
46052
|
+
const cross = (xj - xi) * (lat - yi) - (yj - yi) * (lon - xi);
|
|
46053
|
+
if (Math.abs(cross) <= EDGE_EPS) return true;
|
|
46054
|
+
}
|
|
46055
|
+
return false;
|
|
46056
|
+
}
|
|
46057
|
+
function pointInGeometry(geometry, lon, lat) {
|
|
46058
|
+
const g = geometry;
|
|
46059
|
+
if (!g) return false;
|
|
46060
|
+
const polys = g.type === "Polygon" ? [g.coordinates] : g.type === "MultiPolygon" ? g.coordinates : [];
|
|
46061
|
+
for (const rings of polys) {
|
|
46062
|
+
if (!rings.length) continue;
|
|
46063
|
+
if (pointOnRingEdge(lon, lat, rings[0])) return true;
|
|
46064
|
+
if (!pointInRing(lon, lat, rings[0])) continue;
|
|
46065
|
+
let inHole = false;
|
|
46066
|
+
for (let h = 1; h < rings.length; h++) {
|
|
46067
|
+
if (pointInRing(lon, lat, rings[h]) && !pointOnRingEdge(lon, lat, rings[h])) {
|
|
46068
|
+
inHole = true;
|
|
46069
|
+
break;
|
|
46070
|
+
}
|
|
46071
|
+
}
|
|
46072
|
+
if (!inHole) return true;
|
|
46073
|
+
}
|
|
46074
|
+
return false;
|
|
46075
|
+
}
|
|
46076
|
+
function regionAt(lonLat, countries, states) {
|
|
46077
|
+
const lon = lonLat[0];
|
|
46078
|
+
const lat = lonLat[1];
|
|
46079
|
+
let country = null;
|
|
46080
|
+
for (const f of countries) {
|
|
46081
|
+
if (pointInGeometry(f.geometry, lon, lat)) {
|
|
46082
|
+
country = { iso: f.id, name: f.properties.name };
|
|
46083
|
+
break;
|
|
46084
|
+
}
|
|
46085
|
+
}
|
|
46086
|
+
let state = null;
|
|
46087
|
+
if (country?.iso === "US" && states) {
|
|
46088
|
+
for (const f of states) {
|
|
46089
|
+
if (pointInGeometry(f.geometry, lon, lat)) {
|
|
46090
|
+
state = { iso: f.id, name: f.properties.name };
|
|
46091
|
+
break;
|
|
46092
|
+
}
|
|
46093
|
+
}
|
|
46094
|
+
}
|
|
46095
|
+
return { country, state };
|
|
46096
|
+
}
|
|
45576
46097
|
function featureBbox(topo, geomId) {
|
|
45577
46098
|
const geom = geomObject(topo).geometries.find((g) => g.id === geomId);
|
|
45578
46099
|
if (!geom) return null;
|
|
@@ -45584,6 +46105,74 @@ function featureBbox(topo, geomId) {
|
|
|
45584
46105
|
[b[1][0], b[1][1]]
|
|
45585
46106
|
];
|
|
45586
46107
|
}
|
|
46108
|
+
function explodePolygons(gj) {
|
|
46109
|
+
const g = gj.geometry ?? gj;
|
|
46110
|
+
const t = g.type;
|
|
46111
|
+
const coords = g.coordinates;
|
|
46112
|
+
if (t === "Polygon") {
|
|
46113
|
+
return [
|
|
46114
|
+
{ type: "Feature", geometry: { type: "Polygon", coordinates: coords } }
|
|
46115
|
+
];
|
|
46116
|
+
}
|
|
46117
|
+
if (t === "MultiPolygon") {
|
|
46118
|
+
return coords.map((rings) => ({
|
|
46119
|
+
type: "Feature",
|
|
46120
|
+
geometry: { type: "Polygon", coordinates: rings }
|
|
46121
|
+
}));
|
|
46122
|
+
}
|
|
46123
|
+
return [];
|
|
46124
|
+
}
|
|
46125
|
+
function bboxGap(a, b) {
|
|
46126
|
+
const lonGap = Math.max(0, a[0][0] - b[1][0], b[0][0] - a[1][0]);
|
|
46127
|
+
const latGap = Math.max(0, a[0][1] - b[1][1], b[0][1] - a[1][1]);
|
|
46128
|
+
return Math.max(lonGap, latGap);
|
|
46129
|
+
}
|
|
46130
|
+
function featureBboxPrimary(topo, geomId) {
|
|
46131
|
+
const geom = geomObject(topo).geometries.find((g) => g.id === geomId);
|
|
46132
|
+
if (!geom) return null;
|
|
46133
|
+
const gj = feature(topo, geom);
|
|
46134
|
+
const parts = explodePolygons(gj);
|
|
46135
|
+
if (parts.length <= 1) return featureBbox(topo, geomId);
|
|
46136
|
+
const polys = parts.map((p) => {
|
|
46137
|
+
const b = geoBounds(p);
|
|
46138
|
+
if (!b || !Number.isFinite(b[0][0])) return null;
|
|
46139
|
+
const wraps = b[1][0] < b[0][0];
|
|
46140
|
+
const bbox = [
|
|
46141
|
+
[b[0][0], b[0][1]],
|
|
46142
|
+
[b[1][0], b[1][1]]
|
|
46143
|
+
];
|
|
46144
|
+
return { bbox, area: geoArea(p), wraps };
|
|
46145
|
+
}).filter(
|
|
46146
|
+
(p) => p !== null
|
|
46147
|
+
);
|
|
46148
|
+
if (polys.length <= 1 || polys.some((p) => p.wraps))
|
|
46149
|
+
return featureBbox(topo, geomId);
|
|
46150
|
+
const maxArea = Math.max(...polys.map((p) => p.area));
|
|
46151
|
+
const anchor = polys.find((p) => p.area === maxArea);
|
|
46152
|
+
const cluster = [
|
|
46153
|
+
[anchor.bbox[0][0], anchor.bbox[0][1]],
|
|
46154
|
+
[anchor.bbox[1][0], anchor.bbox[1][1]]
|
|
46155
|
+
];
|
|
46156
|
+
const remaining = polys.filter((p) => p !== anchor);
|
|
46157
|
+
let added = true;
|
|
46158
|
+
while (added) {
|
|
46159
|
+
added = false;
|
|
46160
|
+
for (let i = remaining.length - 1; i >= 0; i--) {
|
|
46161
|
+
const p = remaining[i];
|
|
46162
|
+
const near = bboxGap(p.bbox, cluster) <= DETACH_GAP_DEG;
|
|
46163
|
+
const large = p.area >= DETACH_AREA_FRAC * maxArea;
|
|
46164
|
+
if (near || large) {
|
|
46165
|
+
cluster[0][0] = Math.min(cluster[0][0], p.bbox[0][0]);
|
|
46166
|
+
cluster[0][1] = Math.min(cluster[0][1], p.bbox[0][1]);
|
|
46167
|
+
cluster[1][0] = Math.max(cluster[1][0], p.bbox[1][0]);
|
|
46168
|
+
cluster[1][1] = Math.max(cluster[1][1], p.bbox[1][1]);
|
|
46169
|
+
remaining.splice(i, 1);
|
|
46170
|
+
added = true;
|
|
46171
|
+
}
|
|
46172
|
+
}
|
|
46173
|
+
}
|
|
46174
|
+
return cluster;
|
|
46175
|
+
}
|
|
45587
46176
|
function unionExtent(boxes, points) {
|
|
45588
46177
|
const lats = [];
|
|
45589
46178
|
const lons = [];
|
|
@@ -45622,11 +46211,15 @@ function unionLongitudes(lons) {
|
|
|
45622
46211
|
}
|
|
45623
46212
|
return { west: pts[gapIdx], east: pts[gapIdx - 1] + 360 };
|
|
45624
46213
|
}
|
|
45625
|
-
var fold;
|
|
46214
|
+
var fold, adjacencyCache, EDGE_EPS, DETACH_GAP_DEG, DETACH_AREA_FRAC;
|
|
45626
46215
|
var init_geo = __esm({
|
|
45627
46216
|
"src/map/geo.ts"() {
|
|
45628
46217
|
"use strict";
|
|
45629
46218
|
fold = (s) => s.normalize("NFD").replace(/\p{Diacritic}/gu, "").toLowerCase().trim();
|
|
46219
|
+
adjacencyCache = /* @__PURE__ */ new WeakMap();
|
|
46220
|
+
EDGE_EPS = 1e-9;
|
|
46221
|
+
DETACH_GAP_DEG = 10;
|
|
46222
|
+
DETACH_AREA_FRAC = 0.25;
|
|
45630
46223
|
}
|
|
45631
46224
|
});
|
|
45632
46225
|
|
|
@@ -45644,6 +46237,12 @@ function looksUS(lat, lon) {
|
|
|
45644
46237
|
if (lat < 15 || lat > 72) return false;
|
|
45645
46238
|
return lon >= -180 && lon <= -64 || lon >= 172;
|
|
45646
46239
|
}
|
|
46240
|
+
function looksNorthAmericaNeighbor(lat, lon) {
|
|
46241
|
+
return lat >= 14 && lat <= 72 && lon >= -141 && lon <= -52;
|
|
46242
|
+
}
|
|
46243
|
+
function isWholeSphere(bb) {
|
|
46244
|
+
return bb[0][0] <= -179 && bb[1][0] >= 179 && bb[0][1] <= -89 && bb[1][1] >= 89;
|
|
46245
|
+
}
|
|
45647
46246
|
function resolveMap(parsed, data) {
|
|
45648
46247
|
const diagnostics = [...parsed.diagnostics];
|
|
45649
46248
|
const err = (line12, message, code) => {
|
|
@@ -45654,9 +46253,6 @@ function resolveMap(parsed, data) {
|
|
|
45654
46253
|
};
|
|
45655
46254
|
const result = {
|
|
45656
46255
|
title: parsed.title,
|
|
45657
|
-
...parsed.directives.subtitle !== void 0 && {
|
|
45658
|
-
subtitle: parsed.directives.subtitle
|
|
45659
|
-
},
|
|
45660
46256
|
...parsed.directives.caption !== void 0 && {
|
|
45661
46257
|
caption: parsed.directives.caption
|
|
45662
46258
|
},
|
|
@@ -45666,7 +46262,7 @@ function resolveMap(parsed, data) {
|
|
|
45666
46262
|
// renderer's job (step 4) — the resolver only carries `tags` + `tagGroups`
|
|
45667
46263
|
// through; it never resolves a tag value to a palette color (#10).
|
|
45668
46264
|
directives: { ...parsed.directives },
|
|
45669
|
-
basemaps: { world: "
|
|
46265
|
+
basemaps: { world: "detail", subdivisions: [] },
|
|
45670
46266
|
regions: [],
|
|
45671
46267
|
pois: [],
|
|
45672
46268
|
edges: [],
|
|
@@ -45675,7 +46271,8 @@ function resolveMap(parsed, data) {
|
|
|
45675
46271
|
[-180, -85],
|
|
45676
46272
|
[180, 85]
|
|
45677
46273
|
],
|
|
45678
|
-
projection: "
|
|
46274
|
+
projection: "equirectangular",
|
|
46275
|
+
poiFrameContainers: [],
|
|
45679
46276
|
diagnostics,
|
|
45680
46277
|
error: parsed.error
|
|
45681
46278
|
};
|
|
@@ -45685,7 +46282,10 @@ function resolveMap(parsed, data) {
|
|
|
45685
46282
|
...[...countryIndex.values()].map((v) => v.name),
|
|
45686
46283
|
...[...usStateIndex.values()].map((v) => v.name)
|
|
45687
46284
|
];
|
|
45688
|
-
const
|
|
46285
|
+
const localeRaw = parsed.directives.locale?.toUpperCase();
|
|
46286
|
+
const localeCountry = localeRaw ? localeRaw.split("-")[0] : void 0;
|
|
46287
|
+
const localeSubdivision = localeRaw && /^[A-Z]{2}-/.test(localeRaw) ? localeRaw : void 0;
|
|
46288
|
+
const usScoped = localeCountry === "US" || parsed.regions.some((r) => {
|
|
45689
46289
|
const f = fold(r.name);
|
|
45690
46290
|
return usStateIndex.has(f) && !countryIndex.has(f);
|
|
45691
46291
|
}) || parsed.regions.some(
|
|
@@ -45730,12 +46330,12 @@ function resolveMap(parsed, data) {
|
|
|
45730
46330
|
chosen = { ...inState, layer: "us-state" };
|
|
45731
46331
|
} else {
|
|
45732
46332
|
chosen = { ...inCountry, layer: "country" };
|
|
46333
|
+
warn(
|
|
46334
|
+
r.lineNumber,
|
|
46335
|
+
`"${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}").`,
|
|
46336
|
+
"W_MAP_REGION_AMBIGUOUS"
|
|
46337
|
+
);
|
|
45733
46338
|
}
|
|
45734
|
-
warn(
|
|
45735
|
-
r.lineNumber,
|
|
45736
|
-
`"${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}").`,
|
|
45737
|
-
"W_MAP_REGION_AMBIGUOUS"
|
|
45738
|
-
);
|
|
45739
46339
|
} else if (inState) {
|
|
45740
46340
|
chosen = { ...inState, layer: "us-state" };
|
|
45741
46341
|
} else if (inCountry) {
|
|
@@ -45759,6 +46359,7 @@ function resolveMap(parsed, data) {
|
|
|
45759
46359
|
name: chosen.name,
|
|
45760
46360
|
layer: chosen.layer,
|
|
45761
46361
|
...r.value !== void 0 && { value: r.value },
|
|
46362
|
+
...r.color !== void 0 && { color: r.color },
|
|
45762
46363
|
tags: r.tags,
|
|
45763
46364
|
meta: r.meta,
|
|
45764
46365
|
lineNumber: r.lineNumber
|
|
@@ -45835,7 +46436,7 @@ function resolveMap(parsed, data) {
|
|
|
45835
46436
|
if (!scope)
|
|
45836
46437
|
warn(
|
|
45837
46438
|
line12,
|
|
45838
|
-
`"${name}" is ambiguous \u2014 resolved to the most-populous match.`,
|
|
46439
|
+
`"${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.`,
|
|
45839
46440
|
"W_MAP_AMBIGUOUS_NAME"
|
|
45840
46441
|
);
|
|
45841
46442
|
}
|
|
@@ -45848,17 +46449,21 @@ function resolveMap(parsed, data) {
|
|
|
45848
46449
|
return fold(pos.name);
|
|
45849
46450
|
};
|
|
45850
46451
|
const poiCountries = [];
|
|
45851
|
-
let
|
|
46452
|
+
let anyUsPoi = false;
|
|
46453
|
+
let anyNonNaPoi = false;
|
|
45852
46454
|
const noteCountry = (iso) => {
|
|
45853
46455
|
if (iso) {
|
|
45854
46456
|
poiCountries.push(iso);
|
|
45855
|
-
if (iso
|
|
46457
|
+
if (iso === "US") anyUsPoi = true;
|
|
46458
|
+
if (iso !== "US" && iso !== "CA" && iso !== "MX") anyNonNaPoi = true;
|
|
45856
46459
|
}
|
|
45857
46460
|
};
|
|
45858
46461
|
const deferred = [];
|
|
45859
46462
|
for (const p of parsed.pois) {
|
|
45860
46463
|
if (p.pos.kind === "coords") {
|
|
45861
|
-
if (
|
|
46464
|
+
if (looksUS(p.pos.lat, p.pos.lon)) anyUsPoi = true;
|
|
46465
|
+
else if (!looksNorthAmericaNeighbor(p.pos.lat, p.pos.lon))
|
|
46466
|
+
anyNonNaPoi = true;
|
|
45862
46467
|
addResolvedPoi(p.pos.lat, p.pos.lon, p);
|
|
45863
46468
|
continue;
|
|
45864
46469
|
}
|
|
@@ -45876,14 +46481,15 @@ function resolveMap(parsed, data) {
|
|
|
45876
46481
|
deferred.push(p);
|
|
45877
46482
|
}
|
|
45878
46483
|
}
|
|
45879
|
-
const inferredCountry =
|
|
46484
|
+
const inferredCountry = localeCountry ?? mostCommonCountry(regions, poiCountries) ?? void 0;
|
|
46485
|
+
const inferredScope = localeSubdivision ?? inferredCountry;
|
|
45880
46486
|
for (const p of deferred) {
|
|
45881
46487
|
if (p.pos.kind !== "name") continue;
|
|
45882
46488
|
const got = lookupName(
|
|
45883
46489
|
p.pos.name,
|
|
45884
46490
|
p.pos.scope,
|
|
45885
46491
|
p.lineNumber,
|
|
45886
|
-
|
|
46492
|
+
inferredScope,
|
|
45887
46493
|
true
|
|
45888
46494
|
);
|
|
45889
46495
|
if (got.kind === "ok") {
|
|
@@ -45900,6 +46506,7 @@ function resolveMap(parsed, data) {
|
|
|
45900
46506
|
lat,
|
|
45901
46507
|
lon,
|
|
45902
46508
|
...p.label !== void 0 && { label: p.label },
|
|
46509
|
+
...p.color !== void 0 && { color: p.color },
|
|
45903
46510
|
tags: p.tags,
|
|
45904
46511
|
meta: p.meta,
|
|
45905
46512
|
lineNumber: p.lineNumber
|
|
@@ -45952,7 +46559,8 @@ function resolveMap(parsed, data) {
|
|
|
45952
46559
|
const meta = sizeValue !== void 0 ? { value: sizeValue } : {};
|
|
45953
46560
|
if (pos.kind === "coords") {
|
|
45954
46561
|
const id = alias ? fold(alias) : `@${pos.lat},${pos.lon}`;
|
|
45955
|
-
if (
|
|
46562
|
+
if (looksUS(pos.lat, pos.lon)) anyUsPoi = true;
|
|
46563
|
+
else if (!looksNorthAmericaNeighbor(pos.lat, pos.lon)) anyNonNaPoi = true;
|
|
45956
46564
|
if (!registry.has(id)) {
|
|
45957
46565
|
registerPoi(
|
|
45958
46566
|
id,
|
|
@@ -45975,7 +46583,7 @@ function resolveMap(parsed, data) {
|
|
|
45975
46583
|
if (registry.has(f)) return f;
|
|
45976
46584
|
const aliased = declaredByName.get(f);
|
|
45977
46585
|
if (aliased) return aliased;
|
|
45978
|
-
const got = lookupName(pos.name, pos.scope, line12,
|
|
46586
|
+
const got = lookupName(pos.name, pos.scope, line12, inferredScope, true);
|
|
45979
46587
|
if (got.kind !== "ok") return null;
|
|
45980
46588
|
noteCountry(got.iso);
|
|
45981
46589
|
registerPoi(
|
|
@@ -46032,9 +46640,12 @@ function resolveMap(parsed, data) {
|
|
|
46032
46640
|
}
|
|
46033
46641
|
routes.push({ stopIds, legs, lineNumber: rt.lineNumber });
|
|
46034
46642
|
}
|
|
46643
|
+
const hasUsContent = usSubdivisionReferenced || anyUsPoi || localeCountry === "US";
|
|
46644
|
+
const usOriented = !anyNonNaPoi && !regions.some(
|
|
46645
|
+
(r) => r.layer === "country" && !["US", "CA", "MX"].includes(r.iso)
|
|
46646
|
+
) && hasUsContent;
|
|
46035
46647
|
const subdivisions = [];
|
|
46036
|
-
if (usSubdivisionReferenced ||
|
|
46037
|
-
subdivisions.push("us-states");
|
|
46648
|
+
if (usSubdivisionReferenced || usOriented) subdivisions.push("us-states");
|
|
46038
46649
|
const regionBoxes = [];
|
|
46039
46650
|
for (const ref of referencedRegionIds) {
|
|
46040
46651
|
const bb = featureBbox(data.usStates, ref.id);
|
|
@@ -46042,7 +46653,7 @@ function resolveMap(parsed, data) {
|
|
|
46042
46653
|
}
|
|
46043
46654
|
for (const r of regions) {
|
|
46044
46655
|
if (r.layer === "country") {
|
|
46045
|
-
const bb =
|
|
46656
|
+
const bb = featureBboxPrimary(data.worldCoarse, r.iso);
|
|
46046
46657
|
if (bb) regionBoxes.push(bb);
|
|
46047
46658
|
}
|
|
46048
46659
|
}
|
|
@@ -46052,23 +46663,56 @@ function resolveMap(parsed, data) {
|
|
|
46052
46663
|
[-180, -85],
|
|
46053
46664
|
[180, 85]
|
|
46054
46665
|
];
|
|
46055
|
-
|
|
46666
|
+
const basePad = regions.length > 0 ? REGION_PAD_FRACTION : PAD_FRACTION;
|
|
46667
|
+
let extent2 = unioned ? pad(unioned, basePad) : DEFAULT_EXTENT;
|
|
46668
|
+
const isPoiOnly = pois.length > 0 && regions.length === 0;
|
|
46669
|
+
const containerRegionIds = [];
|
|
46670
|
+
if (isPoiOnly) {
|
|
46671
|
+
const countries = decodeFeatures(data.worldDetail);
|
|
46672
|
+
const states = decodeFeatures(data.usStates);
|
|
46673
|
+
const seen = /* @__PURE__ */ new Set();
|
|
46674
|
+
const containerBoxes = [];
|
|
46675
|
+
for (const p of pois) {
|
|
46676
|
+
const { country, state } = regionAt([p.lon, p.lat], countries, states);
|
|
46677
|
+
const id = state?.iso ?? country?.iso;
|
|
46678
|
+
if (!id || seen.has(id)) continue;
|
|
46679
|
+
seen.add(id);
|
|
46680
|
+
containerRegionIds.push(id);
|
|
46681
|
+
const bb = state ? featureBbox(data.usStates, id) : featureBboxPrimary(data.worldCoarse, id);
|
|
46682
|
+
if (bb && !isWholeSphere(bb)) containerBoxes.push(bb);
|
|
46683
|
+
}
|
|
46684
|
+
const containerUnion = unionExtent(containerBoxes, points);
|
|
46685
|
+
if (containerUnion) extent2 = pad(containerUnion, PAD_FRACTION);
|
|
46686
|
+
}
|
|
46687
|
+
if (isPoiOnly) {
|
|
46688
|
+
const cx = (extent2[0][0] + extent2[1][0]) / 2;
|
|
46689
|
+
const cy = (extent2[0][1] + extent2[1][1]) / 2;
|
|
46690
|
+
const lon = extent2[1][0] - extent2[0][0];
|
|
46691
|
+
const lat = extent2[1][1] - extent2[0][1];
|
|
46692
|
+
const longer = Math.max(lon, lat);
|
|
46693
|
+
if (longer > 0 && longer < POI_ZOOM_FLOOR_DEG) {
|
|
46694
|
+
const k = POI_ZOOM_FLOOR_DEG / longer;
|
|
46695
|
+
const halfLon = lon * k / 2;
|
|
46696
|
+
const halfLat = lat * k / 2;
|
|
46697
|
+
extent2 = [
|
|
46698
|
+
[cx - halfLon, cy - halfLat],
|
|
46699
|
+
[cx + halfLon, cy + halfLat]
|
|
46700
|
+
];
|
|
46701
|
+
}
|
|
46702
|
+
}
|
|
46056
46703
|
const lonSpan = extent2[1][0] - extent2[0][0];
|
|
46057
46704
|
const latSpan = extent2[1][1] - extent2[0][1];
|
|
46058
46705
|
const span = Math.max(lonSpan, latSpan);
|
|
46059
|
-
const
|
|
46706
|
+
const maxAbsLat = Math.max(Math.abs(extent2[0][1]), Math.abs(extent2[1][1]));
|
|
46060
46707
|
let projection;
|
|
46061
|
-
|
|
46062
|
-
|
|
46063
|
-
|
|
46064
|
-
} else if (usDominant) {
|
|
46708
|
+
if (isPoiOnly && usOriented && lonSpan < US_NATIONAL_LON_SPAN) {
|
|
46709
|
+
projection = "mercator";
|
|
46710
|
+
} else if (usOriented) {
|
|
46065
46711
|
projection = "albers-usa";
|
|
46066
|
-
} else if (span > WORLD_SPAN) {
|
|
46712
|
+
} else if (span > WORLD_SPAN || maxAbsLat > MERCATOR_MAX_LAT) {
|
|
46067
46713
|
projection = "equirectangular";
|
|
46068
|
-
} else if (span < MERCATOR_MAX_SPAN) {
|
|
46069
|
-
projection = "mercator";
|
|
46070
46714
|
} else {
|
|
46071
|
-
projection = "
|
|
46715
|
+
projection = "mercator";
|
|
46072
46716
|
}
|
|
46073
46717
|
if (lonSpan >= 180) {
|
|
46074
46718
|
extent2 = [
|
|
@@ -46081,11 +46725,20 @@ function resolveMap(parsed, data) {
|
|
|
46081
46725
|
result.edges = edges;
|
|
46082
46726
|
result.routes = routes;
|
|
46083
46727
|
result.basemaps = {
|
|
46084
|
-
|
|
46728
|
+
// Tier is intentionally pinned to detail (50m) at ALL scales. Diagrammo maps
|
|
46729
|
+
// are presentational (palette tints, relief hachures, POI hubs), not
|
|
46730
|
+
// survey-grade — recognizability > generalization: 110m coarse drops the
|
|
46731
|
+
// Italian boot to a stump at world scale. `WORLD_SPAN` lives on only for the
|
|
46732
|
+
// projection decision (the `usOriented`/`span > WORLD_SPAN` chain above); it
|
|
46733
|
+
// no longer gates basemap resolution.
|
|
46734
|
+
// `worldCoarse` is still loaded — it's the authoritative name/bbox index
|
|
46735
|
+
// (featureIndex, featureBboxPrimary), not dead code.
|
|
46736
|
+
world: "detail",
|
|
46085
46737
|
subdivisions
|
|
46086
46738
|
};
|
|
46087
46739
|
result.extent = extent2;
|
|
46088
46740
|
result.projection = projection;
|
|
46741
|
+
result.poiFrameContainers = containerRegionIds;
|
|
46089
46742
|
result.error = parsed.error ?? firstError(diagnostics);
|
|
46090
46743
|
return result;
|
|
46091
46744
|
}
|
|
@@ -46122,17 +46775,20 @@ function firstError(diags) {
|
|
|
46122
46775
|
const e = diags.find((d) => d.severity === "error");
|
|
46123
46776
|
return e ? formatDgmoError(e) : null;
|
|
46124
46777
|
}
|
|
46125
|
-
var WORLD_SPAN,
|
|
46778
|
+
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;
|
|
46126
46779
|
var init_resolver2 = __esm({
|
|
46127
46780
|
"src/map/resolver.ts"() {
|
|
46128
46781
|
"use strict";
|
|
46129
46782
|
init_diagnostics();
|
|
46130
46783
|
init_geo();
|
|
46131
46784
|
WORLD_SPAN = 90;
|
|
46132
|
-
|
|
46785
|
+
MERCATOR_MAX_LAT = 80;
|
|
46133
46786
|
PAD_FRACTION = 0.05;
|
|
46787
|
+
REGION_PAD_FRACTION = 0.12;
|
|
46134
46788
|
WORLD_LAT_SOUTH = -58;
|
|
46135
46789
|
WORLD_LAT_NORTH = 78;
|
|
46790
|
+
POI_ZOOM_FLOOR_DEG = 7;
|
|
46791
|
+
US_NATIONAL_LON_SPAN = 48;
|
|
46136
46792
|
REGION_ALIASES = {
|
|
46137
46793
|
// Common everyday names → the Natural-Earth display name actually shipped.
|
|
46138
46794
|
"united states": "united states of america",
|
|
@@ -46210,111 +46866,269 @@ var init_resolver2 = __esm({
|
|
|
46210
46866
|
}
|
|
46211
46867
|
});
|
|
46212
46868
|
|
|
46213
|
-
// src/map/
|
|
46214
|
-
|
|
46215
|
-
|
|
46216
|
-
|
|
46869
|
+
// src/map/colorize.ts
|
|
46870
|
+
function assignColors(isos, adjacency) {
|
|
46871
|
+
const sorted = [...isos].sort();
|
|
46872
|
+
const byIso = /* @__PURE__ */ new Map();
|
|
46873
|
+
let maxIndex = -1;
|
|
46874
|
+
for (const iso of sorted) {
|
|
46875
|
+
const taken = /* @__PURE__ */ new Set();
|
|
46876
|
+
for (const n of adjacency.get(iso) ?? []) {
|
|
46877
|
+
const c = byIso.get(n);
|
|
46878
|
+
if (c !== void 0) taken.add(c);
|
|
46879
|
+
}
|
|
46880
|
+
let h = 0;
|
|
46881
|
+
while (taken.has(h)) h++;
|
|
46882
|
+
byIso.set(iso, h);
|
|
46883
|
+
if (h > maxIndex) maxIndex = h;
|
|
46884
|
+
}
|
|
46885
|
+
return { byIso, huesNeeded: maxIndex + 1 };
|
|
46886
|
+
}
|
|
46887
|
+
var init_colorize = __esm({
|
|
46888
|
+
"src/map/colorize.ts"() {
|
|
46889
|
+
"use strict";
|
|
46890
|
+
}
|
|
46217
46891
|
});
|
|
46218
|
-
|
|
46219
|
-
|
|
46220
|
-
|
|
46221
|
-
|
|
46222
|
-
|
|
46223
|
-
|
|
46224
|
-
return
|
|
46225
|
-
}
|
|
46226
|
-
|
|
46227
|
-
|
|
46228
|
-
|
|
46229
|
-
|
|
46230
|
-
|
|
46231
|
-
|
|
46232
|
-
|
|
46233
|
-
|
|
46234
|
-
|
|
46235
|
-
|
|
46892
|
+
|
|
46893
|
+
// src/map/context-labels.ts
|
|
46894
|
+
function tierBand(maxSpanDeg) {
|
|
46895
|
+
if (maxSpanDeg >= 90) return "world";
|
|
46896
|
+
if (maxSpanDeg >= 20) return "continental";
|
|
46897
|
+
if (maxSpanDeg >= 5) return "regional";
|
|
46898
|
+
return "local";
|
|
46899
|
+
}
|
|
46900
|
+
function labelBudget(width, height, band) {
|
|
46901
|
+
const bandCap = {
|
|
46902
|
+
world: 6,
|
|
46903
|
+
continental: 5,
|
|
46904
|
+
regional: 4,
|
|
46905
|
+
local: 3
|
|
46906
|
+
};
|
|
46907
|
+
const area2 = Math.floor(Math.sqrt(Math.max(0, width * height)) / 150);
|
|
46908
|
+
return Math.max(0, Math.min(area2, bandCap[band]));
|
|
46909
|
+
}
|
|
46910
|
+
function waterEligible(tier, kind, band) {
|
|
46911
|
+
switch (band) {
|
|
46912
|
+
case "world":
|
|
46913
|
+
return tier <= 1 && (kind === "ocean" || kind === "sea");
|
|
46914
|
+
case "continental":
|
|
46915
|
+
return tier <= 2;
|
|
46916
|
+
case "regional":
|
|
46917
|
+
return tier <= 3;
|
|
46918
|
+
case "local":
|
|
46919
|
+
return tier <= 4;
|
|
46920
|
+
}
|
|
46921
|
+
}
|
|
46922
|
+
function insideViewport(p, width, height) {
|
|
46923
|
+
return !!p && Number.isFinite(p[0]) && Number.isFinite(p[1]) && p[0] >= 0 && p[0] <= width && p[1] >= 0 && p[1] <= height;
|
|
46924
|
+
}
|
|
46925
|
+
function labelWidth(text, letterSpacing) {
|
|
46926
|
+
const spacing = letterSpacing > 0 ? Math.max(0, text.length - 1) * letterSpacing : 0;
|
|
46927
|
+
return measureLegendText(text, FONT) + spacing + 2 * PADX;
|
|
46928
|
+
}
|
|
46929
|
+
function wrapLabel2(text, letterSpacing) {
|
|
46930
|
+
const words = text.split(/\s+/).filter(Boolean);
|
|
46931
|
+
if (words.length <= 1) return [text];
|
|
46932
|
+
const maxLines = words.length >= 4 ? 3 : 2;
|
|
46933
|
+
const n = words.length;
|
|
46934
|
+
let best = null;
|
|
46935
|
+
for (let mask = 0; mask < 1 << n - 1; mask++) {
|
|
46936
|
+
const lines = [];
|
|
46937
|
+
let cur = [words[0]];
|
|
46938
|
+
for (let i = 1; i < n; i++) {
|
|
46939
|
+
if (mask & 1 << i - 1) {
|
|
46940
|
+
lines.push(cur.join(" "));
|
|
46941
|
+
cur = [words[i]];
|
|
46942
|
+
} else cur.push(words[i]);
|
|
46236
46943
|
}
|
|
46944
|
+
lines.push(cur.join(" "));
|
|
46945
|
+
if (lines.length > maxLines) continue;
|
|
46946
|
+
const cost = Math.round(
|
|
46947
|
+
Math.max(...lines.map((l) => labelWidth(l, letterSpacing)))
|
|
46948
|
+
);
|
|
46949
|
+
const head = labelWidth(lines[0], letterSpacing);
|
|
46950
|
+
if (!best || cost < best.cost || cost === best.cost && lines.length < best.lines.length || cost === best.cost && lines.length === best.lines.length && head > best.head)
|
|
46951
|
+
best = { lines, cost, head };
|
|
46237
46952
|
}
|
|
46238
|
-
|
|
46239
|
-
`map data assets not found near ${baseDir} (looked in ${CANDIDATE_DIRS.join(", ")}). Run \`pnpm build:map-data\` and \`pnpm build\`.`
|
|
46240
|
-
);
|
|
46953
|
+
return best?.lines ?? [text];
|
|
46241
46954
|
}
|
|
46242
|
-
function
|
|
46243
|
-
const
|
|
46244
|
-
|
|
46245
|
-
|
|
46246
|
-
}
|
|
46247
|
-
return data;
|
|
46955
|
+
function rectAround(cx, cy, lines, letterSpacing) {
|
|
46956
|
+
const w = Math.max(...lines.map((l) => labelWidth(l, letterSpacing)));
|
|
46957
|
+
const h = (lines.length - 1) * LINE_HEIGHT + FONT + 2 * PADY;
|
|
46958
|
+
return { x: cx - w / 2, y: cy - h / 2, w, h };
|
|
46248
46959
|
}
|
|
46249
|
-
function
|
|
46250
|
-
|
|
46251
|
-
const url = import.meta.url;
|
|
46252
|
-
if (url) return nb.dirname(nb.fileURLToPath(url));
|
|
46253
|
-
} catch {
|
|
46254
|
-
}
|
|
46255
|
-
if (typeof __dirname !== "undefined") return __dirname;
|
|
46256
|
-
return process.cwd();
|
|
46960
|
+
function rectFits(r, width, height) {
|
|
46961
|
+
return r.x >= 0 && r.y >= 0 && r.x + r.w <= width && r.y + r.h <= height;
|
|
46257
46962
|
}
|
|
46258
|
-
function
|
|
46259
|
-
|
|
46260
|
-
|
|
46261
|
-
|
|
46262
|
-
|
|
46263
|
-
|
|
46264
|
-
|
|
46265
|
-
|
|
46266
|
-
|
|
46267
|
-
|
|
46268
|
-
|
|
46269
|
-
|
|
46270
|
-
|
|
46271
|
-
|
|
46272
|
-
|
|
46273
|
-
|
|
46274
|
-
|
|
46275
|
-
|
|
46276
|
-
|
|
46277
|
-
|
|
46278
|
-
|
|
46279
|
-
|
|
46280
|
-
|
|
46281
|
-
|
|
46282
|
-
|
|
46283
|
-
|
|
46284
|
-
|
|
46285
|
-
|
|
46286
|
-
|
|
46287
|
-
|
|
46288
|
-
|
|
46289
|
-
|
|
46290
|
-
|
|
46963
|
+
function overlapsPadded(a, b, pad2) {
|
|
46964
|
+
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;
|
|
46965
|
+
}
|
|
46966
|
+
function placeContextLabels(args) {
|
|
46967
|
+
const {
|
|
46968
|
+
projection,
|
|
46969
|
+
dLonSpan,
|
|
46970
|
+
dLatSpan,
|
|
46971
|
+
width,
|
|
46972
|
+
height,
|
|
46973
|
+
waterBodies,
|
|
46974
|
+
countries,
|
|
46975
|
+
palette,
|
|
46976
|
+
project,
|
|
46977
|
+
collides,
|
|
46978
|
+
overLand
|
|
46979
|
+
} = args;
|
|
46980
|
+
void projection;
|
|
46981
|
+
const band = tierBand(Math.max(dLonSpan, dLatSpan));
|
|
46982
|
+
const budget = labelBudget(width, height, band);
|
|
46983
|
+
if (budget <= 0) return [];
|
|
46984
|
+
const waterColor = mix(palette.colors.blue, palette.textMuted, 50);
|
|
46985
|
+
const countryColor = palette.textMuted;
|
|
46986
|
+
const haloColor = palette.bg;
|
|
46987
|
+
const candidates = [];
|
|
46988
|
+
const center = [width / 2, height / 2];
|
|
46989
|
+
for (const e of waterBodies?.entries ?? []) {
|
|
46990
|
+
const [lat, lon, name, tier, kind, alt] = e;
|
|
46991
|
+
if (!waterEligible(tier, kind, band)) continue;
|
|
46992
|
+
const wlines = wrapLabel2(name, WATER_LETTER_SPACING);
|
|
46993
|
+
const anchorsLngLat = [[lon, lat]];
|
|
46994
|
+
for (const a of alt ?? []) anchorsLngLat.push([a[1], a[0]]);
|
|
46995
|
+
let best = null;
|
|
46996
|
+
let bestD = Infinity;
|
|
46997
|
+
let nearestProj = null;
|
|
46998
|
+
let nearestProjD = Infinity;
|
|
46999
|
+
for (const [aLon, aLat] of anchorsLngLat) {
|
|
47000
|
+
const p = project(aLon, aLat);
|
|
47001
|
+
if (!p || !Number.isFinite(p[0]) || !Number.isFinite(p[1])) continue;
|
|
47002
|
+
const d = (p[0] - center[0]) ** 2 + (p[1] - center[1]) ** 2;
|
|
47003
|
+
if (d < nearestProjD) {
|
|
47004
|
+
nearestProjD = d;
|
|
47005
|
+
nearestProj = p;
|
|
47006
|
+
}
|
|
47007
|
+
if (!insideViewport(p, width, height)) continue;
|
|
47008
|
+
if (d < bestD) {
|
|
47009
|
+
bestD = d;
|
|
47010
|
+
best = p;
|
|
47011
|
+
}
|
|
47012
|
+
}
|
|
47013
|
+
if (!best && tier === 0 && nearestProj) {
|
|
47014
|
+
const overX = Math.max(0, -nearestProj[0], nearestProj[0] - width);
|
|
47015
|
+
const overY = Math.max(0, -nearestProj[1], nearestProj[1] - height);
|
|
47016
|
+
if (overX <= width * EDGE_CLAMP_OVERSHOOT && overY <= height * EDGE_CLAMP_OVERSHOOT) {
|
|
47017
|
+
const halfW = Math.max(...wlines.map((l) => labelWidth(l, WATER_LETTER_SPACING))) / 2;
|
|
47018
|
+
const halfH = ((wlines.length - 1) * LINE_HEIGHT + FONT + 2 * PADY) / 2;
|
|
47019
|
+
const m = EDGE_CLAMP_MARGIN;
|
|
47020
|
+
best = [
|
|
47021
|
+
Math.min(Math.max(nearestProj[0], halfW + m), width - halfW - m),
|
|
47022
|
+
Math.min(Math.max(nearestProj[1], halfH + m), height - halfH - m)
|
|
47023
|
+
];
|
|
47024
|
+
}
|
|
47025
|
+
}
|
|
47026
|
+
if (!best) continue;
|
|
47027
|
+
candidates.push({
|
|
47028
|
+
text: name,
|
|
47029
|
+
lines: wlines,
|
|
47030
|
+
cx: best[0],
|
|
47031
|
+
cy: best[1],
|
|
47032
|
+
italic: true,
|
|
47033
|
+
letterSpacing: WATER_LETTER_SPACING,
|
|
47034
|
+
color: waterColor,
|
|
47035
|
+
// Water before any country (×1000), then by tier, then kind, then name.
|
|
47036
|
+
sort: tier * 10 + KIND_ORDER[kind]
|
|
46291
47037
|
});
|
|
46292
|
-
}
|
|
46293
|
-
|
|
46294
|
-
|
|
46295
|
-
|
|
46296
|
-
|
|
47038
|
+
}
|
|
47039
|
+
const ranked = countries.map((c) => {
|
|
47040
|
+
const [x0, y0, x1, y1] = c.bbox;
|
|
47041
|
+
const w = x1 - x0;
|
|
47042
|
+
const h = y1 - y0;
|
|
47043
|
+
return { c, w, h, area: w * h };
|
|
47044
|
+
}).filter((r) => Number.isFinite(r.area) && r.area > 0).sort((a, b) => b.area - a.area);
|
|
47045
|
+
let ci = 0;
|
|
47046
|
+
for (const r of ranked) {
|
|
47047
|
+
const { c, w, h } = r;
|
|
47048
|
+
if (w > width * 0.66 || h > height * 0.66) continue;
|
|
47049
|
+
if (!insideViewport(c.anchor, width, height)) continue;
|
|
47050
|
+
const text = c.name;
|
|
47051
|
+
const tw = labelWidth(text, 0);
|
|
47052
|
+
if (tw > w || FONT + 2 * PADY > h) continue;
|
|
47053
|
+
candidates.push({
|
|
47054
|
+
text,
|
|
47055
|
+
lines: [text],
|
|
47056
|
+
cx: c.anchor[0],
|
|
47057
|
+
cy: c.anchor[1],
|
|
47058
|
+
italic: false,
|
|
47059
|
+
letterSpacing: 0,
|
|
47060
|
+
color: countryColor,
|
|
47061
|
+
// Always after every water body (+1e6); larger area = earlier.
|
|
47062
|
+
sort: 1e6 + ci++
|
|
47063
|
+
});
|
|
47064
|
+
}
|
|
47065
|
+
candidates.sort((a, b) => a.sort - b.sort);
|
|
47066
|
+
const placed = [];
|
|
47067
|
+
const placedRects = [];
|
|
47068
|
+
for (const cand of candidates) {
|
|
47069
|
+
if (placed.length >= budget) break;
|
|
47070
|
+
const rect = rectAround(cand.cx, cand.cy, cand.lines, cand.letterSpacing);
|
|
47071
|
+
if (!rectFits(rect, width, height)) continue;
|
|
47072
|
+
if (cand.italic && overLand) {
|
|
47073
|
+
const inset = 2;
|
|
47074
|
+
const top = cand.cy - (cand.lines.length - 1) / 2 * LINE_HEIGHT;
|
|
47075
|
+
const touchesLand = cand.lines.some((line12, li) => {
|
|
47076
|
+
const lw = labelWidth(line12, cand.letterSpacing);
|
|
47077
|
+
const x0 = cand.cx - lw / 2 + inset;
|
|
47078
|
+
const x1 = cand.cx + lw / 2 - inset;
|
|
47079
|
+
const xs = [x0, (x0 + cand.cx) / 2, cand.cx, (cand.cx + x1) / 2, x1];
|
|
47080
|
+
const base = top + li * LINE_HEIGHT;
|
|
47081
|
+
return [base, base - FONT * 0.4, base - FONT * 0.8].some(
|
|
47082
|
+
(y) => xs.some((x) => overLand(x, y))
|
|
47083
|
+
);
|
|
47084
|
+
});
|
|
47085
|
+
if (touchesLand) continue;
|
|
47086
|
+
}
|
|
47087
|
+
if (collides(rect)) continue;
|
|
47088
|
+
if (placedRects.some((r) => overlapsPadded(rect, r, CONTEXT_PAD))) continue;
|
|
47089
|
+
placedRects.push(rect);
|
|
47090
|
+
placed.push({
|
|
47091
|
+
x: cand.cx,
|
|
47092
|
+
y: cand.cy,
|
|
47093
|
+
text: cand.text,
|
|
47094
|
+
anchor: "middle",
|
|
47095
|
+
color: cand.color,
|
|
47096
|
+
// No halo: the bg-coloured outline reads as a ghost box behind the text
|
|
47097
|
+
// over the tinted water/land. Context labels are muted enough to sit
|
|
47098
|
+
// cleanly on the basemap without one.
|
|
47099
|
+
halo: false,
|
|
47100
|
+
haloColor,
|
|
47101
|
+
italic: cand.italic,
|
|
47102
|
+
letterSpacing: cand.letterSpacing,
|
|
47103
|
+
...cand.lines.length > 1 ? { lines: cand.lines } : {},
|
|
47104
|
+
lineNumber: 0
|
|
47105
|
+
});
|
|
47106
|
+
}
|
|
47107
|
+
return placed;
|
|
46297
47108
|
}
|
|
46298
|
-
var
|
|
46299
|
-
var
|
|
46300
|
-
"src/map/
|
|
47109
|
+
var FONT, LINE_HEIGHT, PADX, PADY, WATER_LETTER_SPACING, CONTEXT_PAD, EDGE_CLAMP_MARGIN, EDGE_CLAMP_OVERSHOOT, KIND_ORDER;
|
|
47110
|
+
var init_context_labels = __esm({
|
|
47111
|
+
"src/map/context-labels.ts"() {
|
|
46301
47112
|
"use strict";
|
|
46302
|
-
|
|
46303
|
-
|
|
46304
|
-
|
|
46305
|
-
|
|
46306
|
-
|
|
46307
|
-
|
|
46308
|
-
|
|
46309
|
-
|
|
46310
|
-
|
|
47113
|
+
init_color_utils();
|
|
47114
|
+
init_legend_constants();
|
|
47115
|
+
FONT = 11;
|
|
47116
|
+
LINE_HEIGHT = FONT + 2;
|
|
47117
|
+
PADX = 4;
|
|
47118
|
+
PADY = 3;
|
|
47119
|
+
WATER_LETTER_SPACING = 1.5;
|
|
47120
|
+
CONTEXT_PAD = 4;
|
|
47121
|
+
EDGE_CLAMP_MARGIN = 8;
|
|
47122
|
+
EDGE_CLAMP_OVERSHOOT = 0.35;
|
|
47123
|
+
KIND_ORDER = {
|
|
47124
|
+
ocean: 0,
|
|
47125
|
+
sea: 1,
|
|
47126
|
+
gulf: 2,
|
|
47127
|
+
bay: 3,
|
|
47128
|
+
strait: 4,
|
|
47129
|
+
channel: 5,
|
|
47130
|
+
sound: 6
|
|
46311
47131
|
};
|
|
46312
|
-
CANDIDATE_DIRS = [
|
|
46313
|
-
"./data",
|
|
46314
|
-
"./map-data",
|
|
46315
|
-
"../map-data",
|
|
46316
|
-
"../src/map/data"
|
|
46317
|
-
];
|
|
46318
47132
|
}
|
|
46319
47133
|
});
|
|
46320
47134
|
|
|
@@ -46322,6 +47136,7 @@ var init_load_data = __esm({
|
|
|
46322
47136
|
import {
|
|
46323
47137
|
geoPath,
|
|
46324
47138
|
geoNaturalEarth1,
|
|
47139
|
+
geoEqualEarth,
|
|
46325
47140
|
geoEquirectangular,
|
|
46326
47141
|
geoConicEqualArea,
|
|
46327
47142
|
geoMercator,
|
|
@@ -46333,12 +47148,34 @@ function geomObject2(topo) {
|
|
|
46333
47148
|
const key = Object.keys(topo.objects)[0];
|
|
46334
47149
|
return topo.objects[key];
|
|
46335
47150
|
}
|
|
47151
|
+
function mergeFeatures(a, b) {
|
|
47152
|
+
const polysOf = (f) => {
|
|
47153
|
+
const g = f.geometry;
|
|
47154
|
+
if (!g) return null;
|
|
47155
|
+
if (g.type === "Polygon") return [g.coordinates];
|
|
47156
|
+
if (g.type === "MultiPolygon") return g.coordinates;
|
|
47157
|
+
return null;
|
|
47158
|
+
};
|
|
47159
|
+
const pa = polysOf(a);
|
|
47160
|
+
const pb = polysOf(b);
|
|
47161
|
+
if (!pa || !pb) return a;
|
|
47162
|
+
return {
|
|
47163
|
+
...a,
|
|
47164
|
+
geometry: { type: "MultiPolygon", coordinates: [...pa, ...pb] }
|
|
47165
|
+
};
|
|
47166
|
+
}
|
|
46336
47167
|
function decodeLayer(topo) {
|
|
47168
|
+
const cached = decodeCache.get(topo);
|
|
47169
|
+
if (cached) return cached;
|
|
46337
47170
|
const out = /* @__PURE__ */ new Map();
|
|
46338
47171
|
for (const g of geomObject2(topo).geometries) {
|
|
46339
47172
|
const f = feature2(topo, g);
|
|
46340
|
-
|
|
47173
|
+
if (!f.geometry) continue;
|
|
47174
|
+
const tagged = { ...f, id: g.id };
|
|
47175
|
+
const existing = out.get(g.id);
|
|
47176
|
+
out.set(g.id, existing ? mergeFeatures(existing, tagged) : tagged);
|
|
46341
47177
|
}
|
|
47178
|
+
decodeCache.set(topo, out);
|
|
46342
47179
|
return out;
|
|
46343
47180
|
}
|
|
46344
47181
|
function projectionFor(family) {
|
|
@@ -46347,38 +47184,35 @@ function projectionFor(family) {
|
|
|
46347
47184
|
return usConusProjection();
|
|
46348
47185
|
case "mercator":
|
|
46349
47186
|
return geoMercator();
|
|
47187
|
+
case "equal-earth":
|
|
47188
|
+
return geoEqualEarth();
|
|
47189
|
+
case "equirectangular":
|
|
47190
|
+
return geoEquirectangular();
|
|
46350
47191
|
case "natural-earth":
|
|
46351
47192
|
return geoNaturalEarth1();
|
|
46352
|
-
case "equirectangular":
|
|
46353
47193
|
default:
|
|
46354
47194
|
return geoEquirectangular();
|
|
46355
47195
|
}
|
|
46356
47196
|
}
|
|
46357
|
-
function mapBackgroundColor(palette, isDark = false,
|
|
46358
|
-
|
|
46359
|
-
|
|
46360
|
-
|
|
46361
|
-
|
|
46362
|
-
|
|
46363
|
-
);
|
|
46364
|
-
return mix(palette.colors.blue, palette.bg, WATER_TINT);
|
|
47197
|
+
function mapBackgroundColor(palette, isDark = false, _dataActive = false) {
|
|
47198
|
+
return mix(
|
|
47199
|
+
palette.colors.blue,
|
|
47200
|
+
palette.bg,
|
|
47201
|
+
isDark ? WATER_TINT_DARK : WATER_TINT_LIGHT
|
|
47202
|
+
);
|
|
46365
47203
|
}
|
|
46366
|
-
function mapNeutralLandColor(palette, isDark,
|
|
46367
|
-
if (dataActive)
|
|
46368
|
-
return isDark ? mix(palette.colors.gray, palette.bg, MUTED_LAND_DARK) : palette.bg;
|
|
47204
|
+
function mapNeutralLandColor(palette, isDark, _dataActive = false) {
|
|
46369
47205
|
return mix(
|
|
46370
47206
|
palette.colors.green,
|
|
46371
47207
|
palette.bg,
|
|
46372
47208
|
isDark ? LAND_TINT_DARK : LAND_TINT_LIGHT
|
|
46373
47209
|
);
|
|
46374
47210
|
}
|
|
46375
|
-
function
|
|
46376
|
-
const { palette, isDark } = opts;
|
|
46377
|
-
const { width, height } = size;
|
|
47211
|
+
function buildMapProjection(resolved, data) {
|
|
46378
47212
|
const wantsUsStates = resolved.basemaps.subdivisions.includes("us-states");
|
|
46379
|
-
const usCrisp = resolved.projection === "albers-usa" && wantsUsStates && !!data.naLand;
|
|
47213
|
+
const usCrisp = (resolved.projection === "albers-usa" || resolved.projection === "mercator") && wantsUsStates && !!data.naLand;
|
|
46380
47214
|
const worldTopo = usCrisp ? data.worldDetail : resolved.basemaps.world === "detail" ? data.worldDetail : data.worldCoarse;
|
|
46381
|
-
const worldLayer = decodeLayer(worldTopo);
|
|
47215
|
+
const worldLayer = new Map(decodeLayer(worldTopo));
|
|
46382
47216
|
if (usCrisp && data.naLand) {
|
|
46383
47217
|
const [nbW, nbS, nbE, nbN] = [-140, 10, -52, 66];
|
|
46384
47218
|
const crisp = decodeLayer(data.naLand);
|
|
@@ -46387,17 +47221,110 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46387
47221
|
if (!base) continue;
|
|
46388
47222
|
const [[bw, bs], [be, bn]] = geoBounds2(base);
|
|
46389
47223
|
if (bw >= nbW && be <= nbE && bs >= nbS && bn <= nbN)
|
|
46390
|
-
worldLayer.set(iso, cf);
|
|
47224
|
+
worldLayer.set(iso, { ...cf, properties: base.properties });
|
|
46391
47225
|
}
|
|
46392
47226
|
}
|
|
46393
47227
|
const usLayer = wantsUsStates ? decodeLayer(data.usStates) : null;
|
|
47228
|
+
const extentOutline = () => {
|
|
47229
|
+
const [[w, s], [e, n]] = resolved.extent;
|
|
47230
|
+
const N = 16;
|
|
47231
|
+
const coords = [];
|
|
47232
|
+
for (let i = 0; i <= N; i++) {
|
|
47233
|
+
const t = i / N;
|
|
47234
|
+
const lon = w + (e - w) * t;
|
|
47235
|
+
const lat = s + (n - s) * t;
|
|
47236
|
+
coords.push([lon, s], [lon, n], [w, lat], [e, lat]);
|
|
47237
|
+
}
|
|
47238
|
+
return {
|
|
47239
|
+
type: "Feature",
|
|
47240
|
+
properties: {},
|
|
47241
|
+
geometry: { type: "MultiPoint", coordinates: coords }
|
|
47242
|
+
};
|
|
47243
|
+
};
|
|
47244
|
+
let fitFeatures;
|
|
47245
|
+
if (resolved.projection === "albers-usa" && usLayer) {
|
|
47246
|
+
fitFeatures = [...usLayer.entries()].filter(([iso]) => !US_NON_CONUS.has(iso)).map(([, f]) => f);
|
|
47247
|
+
const neighborPoints = resolved.pois.filter((p) => !inAlaska(p.lon, p.lat) && !inHawaii(p.lon, p.lat)).map((p) => [p.lon, p.lat]);
|
|
47248
|
+
if (neighborPoints.length > 0) {
|
|
47249
|
+
fitFeatures.push({
|
|
47250
|
+
type: "Feature",
|
|
47251
|
+
properties: {},
|
|
47252
|
+
geometry: { type: "MultiPoint", coordinates: neighborPoints }
|
|
47253
|
+
});
|
|
47254
|
+
}
|
|
47255
|
+
for (const r of resolved.regions) {
|
|
47256
|
+
if (r.layer === "country" && (r.iso === "CA" || r.iso === "MX")) {
|
|
47257
|
+
const cf = worldLayer.get(r.iso);
|
|
47258
|
+
if (cf) fitFeatures.push(cf);
|
|
47259
|
+
}
|
|
47260
|
+
}
|
|
47261
|
+
} else {
|
|
47262
|
+
fitFeatures = [extentOutline()];
|
|
47263
|
+
}
|
|
47264
|
+
const fitTarget = { type: "FeatureCollection", features: fitFeatures };
|
|
47265
|
+
const projection = projectionFor(resolved.projection);
|
|
47266
|
+
if (resolved.projection !== "albers-usa") {
|
|
47267
|
+
let centerLon = (resolved.extent[0][0] + resolved.extent[1][0]) / 2;
|
|
47268
|
+
if (centerLon > 180) centerLon -= 360;
|
|
47269
|
+
projection.rotate([-centerLon, 0]);
|
|
47270
|
+
}
|
|
47271
|
+
const fitGB = geoBounds2(fitTarget);
|
|
47272
|
+
const fitIsGlobal = fitGB[1][0] - fitGB[0][0] >= 270 || fitGB[1][1] - fitGB[0][1] >= 130;
|
|
47273
|
+
return {
|
|
47274
|
+
projection,
|
|
47275
|
+
fitTarget,
|
|
47276
|
+
fitIsGlobal,
|
|
47277
|
+
worldLayer,
|
|
47278
|
+
usLayer,
|
|
47279
|
+
usCrisp,
|
|
47280
|
+
wantsUsStates,
|
|
47281
|
+
worldTopo
|
|
47282
|
+
};
|
|
47283
|
+
}
|
|
47284
|
+
function parsePathRings(d) {
|
|
47285
|
+
const rings = [];
|
|
47286
|
+
let cur = [];
|
|
47287
|
+
const re = /([MLZ])([^MLZ]*)/g;
|
|
47288
|
+
let m;
|
|
47289
|
+
while (m = re.exec(d)) {
|
|
47290
|
+
if (m[1] === "Z") {
|
|
47291
|
+
if (cur.length) rings.push(cur);
|
|
47292
|
+
cur = [];
|
|
47293
|
+
continue;
|
|
47294
|
+
}
|
|
47295
|
+
if (m[1] === "M" && cur.length) {
|
|
47296
|
+
rings.push(cur);
|
|
47297
|
+
cur = [];
|
|
47298
|
+
}
|
|
47299
|
+
const nums = m[2].split(/[ ,]+/).map(Number);
|
|
47300
|
+
for (let i = 0; i + 1 < nums.length; i += 2) {
|
|
47301
|
+
const x = nums[i];
|
|
47302
|
+
const y = nums[i + 1];
|
|
47303
|
+
if (Number.isFinite(x) && Number.isFinite(y)) cur.push([x, y]);
|
|
47304
|
+
}
|
|
47305
|
+
}
|
|
47306
|
+
if (cur.length) rings.push(cur);
|
|
47307
|
+
return rings;
|
|
47308
|
+
}
|
|
47309
|
+
function layoutMap(resolved, data, size, opts) {
|
|
47310
|
+
const { palette, isDark } = opts;
|
|
47311
|
+
const { width, height } = size;
|
|
47312
|
+
const {
|
|
47313
|
+
projection,
|
|
47314
|
+
fitTarget,
|
|
47315
|
+
fitIsGlobal,
|
|
47316
|
+
worldLayer,
|
|
47317
|
+
usLayer,
|
|
47318
|
+
usCrisp,
|
|
47319
|
+
worldTopo
|
|
47320
|
+
} = buildMapProjection(resolved, data);
|
|
46394
47321
|
const usContext = usLayer !== null;
|
|
46395
47322
|
const regionStroke = isDark ? mix(palette.bg, palette.text, 78) : mix(palette.text, palette.bg, 78);
|
|
46396
47323
|
const values = resolved.regions.filter((r) => r.value !== void 0).map((r) => r.value);
|
|
46397
|
-
const
|
|
46398
|
-
const rampMin =
|
|
46399
|
-
const rampMax =
|
|
46400
|
-
const rampHue = palette.colors.red;
|
|
47324
|
+
const allNonNegative = values.length > 0 && values.every((v) => v >= 0);
|
|
47325
|
+
const rampMin = allNonNegative ? 0 : Math.min(...values);
|
|
47326
|
+
const rampMax = Math.max(...values);
|
|
47327
|
+
const rampHue = resolveColor(resolved.directives.regionMetricColor ?? "", palette) ?? palette.colors.red;
|
|
46401
47328
|
const hasRamp = values.length > 0;
|
|
46402
47329
|
const VALUE_NAME = hasRamp ? resolved.directives.regionMetric?.trim() || "Value" : null;
|
|
46403
47330
|
const matchColorGroup = (v) => {
|
|
@@ -46417,14 +47344,48 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46417
47344
|
activeGroup = VALUE_NAME ?? (resolved.tagGroups.length > 0 ? resolved.tagGroups[0].name : null);
|
|
46418
47345
|
}
|
|
46419
47346
|
const activeIsScore = VALUE_NAME !== null && activeGroup === VALUE_NAME;
|
|
46420
|
-
const mutedBasemap =
|
|
47347
|
+
const mutedBasemap = activeGroup !== null;
|
|
46421
47348
|
const neutralFill = mapNeutralLandColor(palette, isDark, mutedBasemap);
|
|
46422
47349
|
const water = mapBackgroundColor(palette, isDark, mutedBasemap);
|
|
47350
|
+
const lakeStroke = mix(regionStroke, water, 45);
|
|
46423
47351
|
const foreignFill = mix(
|
|
46424
47352
|
palette.colors.gray,
|
|
46425
47353
|
palette.bg,
|
|
46426
47354
|
mutedBasemap ? isDark ? MUTED_FOREIGN_DARK : MUTED_FOREIGN_LIGHT : isDark ? FOREIGN_TINT_DARK : FOREIGN_TINT_LIGHT
|
|
46427
47355
|
);
|
|
47356
|
+
const colorizeActive = resolved.directives.noColorize !== true && !hasRamp && resolved.tagGroups.length === 0;
|
|
47357
|
+
const colorByIso = /* @__PURE__ */ new Map();
|
|
47358
|
+
if (colorizeActive) {
|
|
47359
|
+
const adjacency = /* @__PURE__ */ new Map();
|
|
47360
|
+
const addEdges = (src) => {
|
|
47361
|
+
for (const [iso, ns] of src) {
|
|
47362
|
+
const cur = adjacency.get(iso);
|
|
47363
|
+
if (cur) cur.push(...ns);
|
|
47364
|
+
else adjacency.set(iso, [...ns]);
|
|
47365
|
+
}
|
|
47366
|
+
};
|
|
47367
|
+
addEdges(buildAdjacency(worldTopo));
|
|
47368
|
+
if (usLayer) {
|
|
47369
|
+
addEdges(buildAdjacency(data.usStates));
|
|
47370
|
+
for (const [country, states] of Object.entries(FOREIGN_BORDER)) {
|
|
47371
|
+
const cn = adjacency.get(country);
|
|
47372
|
+
if (!cn) continue;
|
|
47373
|
+
for (const st of states) {
|
|
47374
|
+
const sn = adjacency.get(st);
|
|
47375
|
+
if (!sn) continue;
|
|
47376
|
+
cn.push(st);
|
|
47377
|
+
sn.push(country);
|
|
47378
|
+
}
|
|
47379
|
+
}
|
|
47380
|
+
}
|
|
47381
|
+
const { byIso, huesNeeded } = assignColors(
|
|
47382
|
+
[...adjacency.keys()],
|
|
47383
|
+
adjacency
|
|
47384
|
+
);
|
|
47385
|
+
const tints = politicalTints(palette, huesNeeded, isDark);
|
|
47386
|
+
for (const [iso, idx] of byIso) colorByIso.set(iso, tints[idx]);
|
|
47387
|
+
}
|
|
47388
|
+
const colorizeStroke = (fill2) => mix(fill2, palette.text, 35);
|
|
46428
47389
|
const rampBase = isDark ? mix(palette.surface, palette.text, 28) : palette.bg;
|
|
46429
47390
|
const fillForValue = (s) => {
|
|
46430
47391
|
const t = rampMax > rampMin ? (s - rampMin) / (rampMax - rampMin) : 1;
|
|
@@ -46449,47 +47410,26 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46449
47410
|
isDark ? TAG_TINT_DARK : TAG_TINT_LIGHT
|
|
46450
47411
|
);
|
|
46451
47412
|
};
|
|
47413
|
+
const directFill = (name) => {
|
|
47414
|
+
const hex = name ? resolveColor(name, palette) : null;
|
|
47415
|
+
if (!hex) return null;
|
|
47416
|
+
return mix(hex, palette.bg, isDark ? TAG_TINT_DARK : TAG_TINT_LIGHT);
|
|
47417
|
+
};
|
|
46452
47418
|
const regionFill = (r) => {
|
|
47419
|
+
const direct = directFill(r.color);
|
|
47420
|
+
if (direct) return direct;
|
|
46453
47421
|
if (activeIsScore) {
|
|
46454
47422
|
return r.value !== void 0 ? fillForValue(r.value) : neutralFill;
|
|
46455
47423
|
}
|
|
47424
|
+
if (colorizeActive) return (r.iso && colorByIso.get(r.iso)) ?? neutralFill;
|
|
46456
47425
|
return tagFill(r.tags, activeGroup) ?? neutralFill;
|
|
46457
47426
|
};
|
|
46458
47427
|
const regionById = new Map(resolved.regions.map((r) => [r.iso, r]));
|
|
46459
|
-
const
|
|
46460
|
-
const [[w, s], [e, n]] = resolved.extent;
|
|
46461
|
-
const N = 16;
|
|
46462
|
-
const coords = [];
|
|
46463
|
-
for (let i = 0; i <= N; i++) {
|
|
46464
|
-
const t = i / N;
|
|
46465
|
-
const lon = w + (e - w) * t;
|
|
46466
|
-
const lat = s + (n - s) * t;
|
|
46467
|
-
coords.push([lon, s], [lon, n], [w, lat], [e, lat]);
|
|
46468
|
-
}
|
|
46469
|
-
return {
|
|
46470
|
-
type: "Feature",
|
|
46471
|
-
properties: {},
|
|
46472
|
-
geometry: { type: "MultiPoint", coordinates: coords }
|
|
46473
|
-
};
|
|
46474
|
-
};
|
|
46475
|
-
let fitFeatures;
|
|
46476
|
-
if (resolved.projection === "albers-usa" && usLayer) {
|
|
46477
|
-
fitFeatures = [...usLayer.entries()].filter(([iso]) => !US_NON_CONUS.has(iso)).map(([, f]) => f);
|
|
46478
|
-
} else {
|
|
46479
|
-
fitFeatures = [extentOutline()];
|
|
46480
|
-
}
|
|
46481
|
-
const fitTarget = { type: "FeatureCollection", features: fitFeatures };
|
|
46482
|
-
const projection = projectionFor(resolved.projection);
|
|
46483
|
-
if (resolved.projection !== "albers-usa") {
|
|
46484
|
-
let centerLon = (resolved.extent[0][0] + resolved.extent[1][0]) / 2;
|
|
46485
|
-
if (centerLon > 180) centerLon -= 360;
|
|
46486
|
-
projection.rotate([-centerLon, 0]);
|
|
46487
|
-
}
|
|
46488
|
-
const TITLE_GAP = 16;
|
|
47428
|
+
const TITLE_GAP2 = 16;
|
|
46489
47429
|
let topPad = FIT_PAD;
|
|
46490
47430
|
if (resolved.title && resolved.pois.length > 0) {
|
|
46491
47431
|
const bannerBottom = (resolved.subtitle ? TITLE_Y + TITLE_FONT_SIZE : TITLE_Y) + TITLE_FONT_SIZE / 2;
|
|
46492
|
-
topPad = Math.max(FIT_PAD, bannerBottom +
|
|
47432
|
+
topPad = Math.max(FIT_PAD, bannerBottom + TITLE_GAP2);
|
|
46493
47433
|
}
|
|
46494
47434
|
const fitBox = [
|
|
46495
47435
|
[FIT_PAD, topPad],
|
|
@@ -46499,11 +47439,10 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46499
47439
|
]
|
|
46500
47440
|
];
|
|
46501
47441
|
projection.fitExtent(fitBox, fitTarget);
|
|
46502
|
-
const fitGB = geoBounds2(fitTarget);
|
|
46503
|
-
const fitIsGlobal = fitGB[1][0] - fitGB[0][0] >= 270 || fitGB[1][1] - fitGB[0][1] >= 130;
|
|
46504
47442
|
let path;
|
|
46505
47443
|
let project;
|
|
46506
|
-
|
|
47444
|
+
let stretchParams = null;
|
|
47445
|
+
if (fitIsGlobal && !opts.preferContain) {
|
|
46507
47446
|
const cb = geoPath(projection).bounds(fitTarget);
|
|
46508
47447
|
const bx0 = cb[0][0];
|
|
46509
47448
|
const by0 = cb[0][1];
|
|
@@ -46513,6 +47452,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46513
47452
|
const oy = fitBox[0][1];
|
|
46514
47453
|
const sx = cw > 0 ? (fitBox[1][0] - ox) / cw : 1;
|
|
46515
47454
|
const sy = ch > 0 ? (fitBox[1][1] - oy) / ch : 1;
|
|
47455
|
+
stretchParams = { sx, sy, ox, oy, bx0, by0 };
|
|
46516
47456
|
const stretch = (x, y) => [
|
|
46517
47457
|
ox + (x - bx0) * sx,
|
|
46518
47458
|
oy + (y - by0) * sy
|
|
@@ -46544,7 +47484,9 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46544
47484
|
const insets = [];
|
|
46545
47485
|
const insetRegions = [];
|
|
46546
47486
|
const insetLabelSeeds = [];
|
|
46547
|
-
|
|
47487
|
+
const akRef = resolved.regions.some((r) => r.iso === "US-AK") || resolved.pois.some((p) => inAlaska(p.lon, p.lat));
|
|
47488
|
+
const hiRef = resolved.regions.some((r) => r.iso === "US-HI") || resolved.pois.some((p) => inHawaii(p.lon, p.lat));
|
|
47489
|
+
if (resolved.projection === "albers-usa" && usLayer && (akRef || hiRef)) {
|
|
46548
47490
|
const PAD = 8;
|
|
46549
47491
|
const GAP = 12;
|
|
46550
47492
|
const yB = height - FIT_PAD;
|
|
@@ -46575,38 +47517,14 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46575
47517
|
}
|
|
46576
47518
|
return y;
|
|
46577
47519
|
};
|
|
46578
|
-
const
|
|
47520
|
+
const coastFloor = (x0, xr) => {
|
|
46579
47521
|
const n = 24;
|
|
46580
|
-
const pts = [];
|
|
46581
47522
|
let maxY = -Infinity;
|
|
46582
47523
|
for (let i = 0; i <= n; i++) {
|
|
46583
|
-
const
|
|
46584
|
-
|
|
46585
|
-
|
|
46586
|
-
|
|
46587
|
-
if (y > maxY) maxY = y;
|
|
46588
|
-
}
|
|
46589
|
-
}
|
|
46590
|
-
if (pts.length === 0) return () => yB - height * 0.42;
|
|
46591
|
-
let m = 0;
|
|
46592
|
-
if (pts.length >= 2) {
|
|
46593
|
-
let sx = 0, sy = 0, sxx = 0, sxy = 0;
|
|
46594
|
-
for (const [x, y] of pts) {
|
|
46595
|
-
sx += x;
|
|
46596
|
-
sy += y;
|
|
46597
|
-
sxx += x * x;
|
|
46598
|
-
sxy += x * y;
|
|
46599
|
-
}
|
|
46600
|
-
const den = pts.length * sxx - sx * sx;
|
|
46601
|
-
if (den !== 0) m = (pts.length * sxy - sx * sy) / den;
|
|
46602
|
-
}
|
|
46603
|
-
m = Math.max(-0.35, Math.min(0.35, m));
|
|
46604
|
-
let c = -Infinity;
|
|
46605
|
-
for (const [x, y] of pts) {
|
|
46606
|
-
const need = y - m * x + GAP;
|
|
46607
|
-
if (need > c) c = need;
|
|
46608
|
-
}
|
|
46609
|
-
return (x) => m * x + c;
|
|
47524
|
+
const y = at(x0 + (xr - x0) * i / n);
|
|
47525
|
+
if (y > maxY) maxY = y;
|
|
47526
|
+
}
|
|
47527
|
+
return maxY;
|
|
46610
47528
|
};
|
|
46611
47529
|
const placeInset = (iso, proj, boxX, iwReq) => {
|
|
46612
47530
|
const f = usLayer.get(iso);
|
|
@@ -46615,19 +47533,15 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46615
47533
|
const iw = Math.min(iwReq, width - FIT_PAD - x0 - 2 * PAD);
|
|
46616
47534
|
if (iw < 24) return boxX;
|
|
46617
47535
|
const xr = x0 + iw + 2 * PAD;
|
|
46618
|
-
const
|
|
46619
|
-
const
|
|
46620
|
-
const yR = top(xr);
|
|
47536
|
+
const floor = coastFloor(x0, xr);
|
|
47537
|
+
const topGuess = floor > -Infinity ? floor + GAP : yB - height * 0.42;
|
|
46621
47538
|
proj.fitWidth(iw, f);
|
|
46622
47539
|
const bb = geoPath(proj).bounds(f);
|
|
46623
47540
|
const sh = Number.isFinite(bb[0][0]) ? bb[1][1] - bb[0][1] : iw;
|
|
46624
47541
|
const needH = sh + 2 * PAD;
|
|
46625
|
-
let topFit =
|
|
47542
|
+
let topFit = topGuess;
|
|
46626
47543
|
const bottom = Math.min(topFit + needH, yB);
|
|
46627
47544
|
if (bottom - topFit < needH) topFit = bottom - needH;
|
|
46628
|
-
const lift = topFit - Math.max(yL, yR);
|
|
46629
|
-
const topL = yL + lift;
|
|
46630
|
-
const topR = yR + lift;
|
|
46631
47545
|
proj.fitExtent(
|
|
46632
47546
|
[
|
|
46633
47547
|
[x0 + PAD, topFit + PAD],
|
|
@@ -46637,8 +47551,18 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46637
47551
|
);
|
|
46638
47552
|
const d = geoPath(proj)(f) ?? "";
|
|
46639
47553
|
if (!d) return xr;
|
|
47554
|
+
let contextLand;
|
|
47555
|
+
if (iso === "US-AK") {
|
|
47556
|
+
const can = worldLayer.get("CA");
|
|
47557
|
+
const cd = can ? geoPath(proj)(can) ?? "" : "";
|
|
47558
|
+
if (cd)
|
|
47559
|
+
contextLand = {
|
|
47560
|
+
d: cd,
|
|
47561
|
+
fill: colorizeActive ? colorByIso.get("CA") ?? foreignFill : foreignFill
|
|
47562
|
+
};
|
|
47563
|
+
}
|
|
46640
47564
|
const r = regionById.get(iso);
|
|
46641
|
-
let fill2 = neutralFill;
|
|
47565
|
+
let fill2 = colorizeActive ? colorByIso.get(iso) ?? neutralFill : neutralFill;
|
|
46642
47566
|
let lineNumber = -1;
|
|
46643
47567
|
if (r?.layer === "us-state") {
|
|
46644
47568
|
fill2 = regionFill(r);
|
|
@@ -46646,21 +47570,25 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46646
47570
|
}
|
|
46647
47571
|
insets.push({
|
|
46648
47572
|
x: x0,
|
|
46649
|
-
y:
|
|
47573
|
+
y: topFit,
|
|
46650
47574
|
w: xr - x0,
|
|
46651
|
-
h: bottom -
|
|
47575
|
+
h: bottom - topFit,
|
|
46652
47576
|
points: [
|
|
46653
|
-
[x0,
|
|
46654
|
-
[xr,
|
|
47577
|
+
[x0, topFit],
|
|
47578
|
+
[xr, topFit],
|
|
46655
47579
|
[xr, bottom],
|
|
46656
47580
|
[x0, bottom]
|
|
46657
|
-
]
|
|
47581
|
+
],
|
|
47582
|
+
// The FITTED inset projection (just fit to this box) — captured so the
|
|
47583
|
+
// geo-query can invert pixels inside the frame back to AK/HI coords.
|
|
47584
|
+
projection: proj,
|
|
47585
|
+
...contextLand && { contextLand }
|
|
46658
47586
|
});
|
|
46659
47587
|
insetRegions.push({
|
|
46660
47588
|
id: iso,
|
|
46661
47589
|
d,
|
|
46662
47590
|
fill: fill2,
|
|
46663
|
-
stroke: regionStroke,
|
|
47591
|
+
stroke: colorizeActive ? colorizeStroke(fill2) : regionStroke,
|
|
46664
47592
|
lineNumber,
|
|
46665
47593
|
layer: "us-state",
|
|
46666
47594
|
...r?.value !== void 0 && { value: r.value },
|
|
@@ -46673,13 +47601,16 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46673
47601
|
}
|
|
46674
47602
|
return xr;
|
|
46675
47603
|
};
|
|
46676
|
-
|
|
46677
|
-
|
|
46678
|
-
alaskaProjection(),
|
|
46679
|
-
|
|
46680
|
-
|
|
46681
|
-
|
|
46682
|
-
|
|
47604
|
+
let akRight = FIT_PAD;
|
|
47605
|
+
if (akRef)
|
|
47606
|
+
akRight = placeInset("US-AK", alaskaProjection(), FIT_PAD, width * 0.15);
|
|
47607
|
+
if (hiRef)
|
|
47608
|
+
placeInset(
|
|
47609
|
+
"US-HI",
|
|
47610
|
+
hawaiiProjection(),
|
|
47611
|
+
akRef ? akRight + 24 : FIT_PAD,
|
|
47612
|
+
width * 0.1
|
|
47613
|
+
);
|
|
46683
47614
|
}
|
|
46684
47615
|
const conusFit = resolved.projection === "albers-usa" && !!usLayer;
|
|
46685
47616
|
const classifyExtent = conusFit ? geoBounds2(fitTarget) : resolved.extent;
|
|
@@ -46695,15 +47626,24 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46695
47626
|
};
|
|
46696
47627
|
const ringOverlapsView = (ring) => {
|
|
46697
47628
|
let loMin = Infinity, loMax = -Infinity, rawMin = Infinity, rawMax = -Infinity;
|
|
47629
|
+
const lons = [];
|
|
46698
47630
|
for (const [rawLon] of ring) {
|
|
46699
47631
|
const lon = normLon(rawLon);
|
|
47632
|
+
lons.push(lon);
|
|
46700
47633
|
if (lon < loMin) loMin = lon;
|
|
46701
47634
|
if (lon > loMax) loMax = lon;
|
|
46702
47635
|
if (rawLon < rawMin) rawMin = rawLon;
|
|
46703
47636
|
if (rawLon > rawMax) rawMax = rawLon;
|
|
46704
47637
|
}
|
|
46705
|
-
|
|
46706
|
-
|
|
47638
|
+
lons.sort((a, b) => a - b);
|
|
47639
|
+
let maxGap = 0;
|
|
47640
|
+
for (let i = 1; i < lons.length; i++)
|
|
47641
|
+
maxGap = Math.max(maxGap, lons[i] - lons[i - 1]);
|
|
47642
|
+
if (lons.length > 1)
|
|
47643
|
+
maxGap = Math.max(maxGap, lons[0] + 360 - lons[lons.length - 1]);
|
|
47644
|
+
const occupiedArc = 360 - maxGap;
|
|
47645
|
+
if (occupiedArc > 270) return false;
|
|
47646
|
+
if (rawMax - rawMin > 180 && occupiedArc < 90) return false;
|
|
46707
47647
|
let px0 = Infinity, py0 = Infinity, px1 = -Infinity, py1 = -Infinity, anyFinite = false;
|
|
46708
47648
|
for (const [lon, lat] of ring) {
|
|
46709
47649
|
const p = project(lon, lat);
|
|
@@ -46776,7 +47716,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46776
47716
|
const regions = [];
|
|
46777
47717
|
const pushRegionLayer = (layerFeatures, layerKind, shouldCull) => {
|
|
46778
47718
|
for (const [iso, f] of layerFeatures) {
|
|
46779
|
-
if (layerKind === "us-state" && usContext && INSET_STATES.has(iso))
|
|
47719
|
+
if (layerKind === "us-state" && usContext && resolved.projection === "albers-usa" && INSET_STATES.has(iso))
|
|
46780
47720
|
continue;
|
|
46781
47721
|
if (layerKind === "country" && usContext && iso === "US") continue;
|
|
46782
47722
|
if (layerKind === "country" && iso === "AQ" && !regionById.has("AQ"))
|
|
@@ -46788,7 +47728,8 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46788
47728
|
if (!d) continue;
|
|
46789
47729
|
const isThisLayer = r?.layer === layerKind;
|
|
46790
47730
|
const isForeign = layerKind === "country" && usContext && iso !== "US";
|
|
46791
|
-
|
|
47731
|
+
const baseFill = isForeign ? foreignFill : neutralFill;
|
|
47732
|
+
let fill2 = colorizeActive ? colorByIso.get(iso) ?? baseFill : baseFill;
|
|
46792
47733
|
let label;
|
|
46793
47734
|
let lineNumber = -1;
|
|
46794
47735
|
let layer = "base";
|
|
@@ -46797,12 +47738,14 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46797
47738
|
lineNumber = r.lineNumber;
|
|
46798
47739
|
layer = layerKind;
|
|
46799
47740
|
label = r.name;
|
|
47741
|
+
} else {
|
|
47742
|
+
label = f.properties?.name;
|
|
46800
47743
|
}
|
|
46801
47744
|
regions.push({
|
|
46802
47745
|
id: iso,
|
|
46803
47746
|
d,
|
|
46804
47747
|
fill: fill2,
|
|
46805
|
-
stroke: regionStroke,
|
|
47748
|
+
stroke: colorizeActive ? colorizeStroke(fill2) : regionStroke,
|
|
46806
47749
|
lineNumber,
|
|
46807
47750
|
layer,
|
|
46808
47751
|
...label !== void 0 && { label },
|
|
@@ -46824,13 +47767,88 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46824
47767
|
id: "lake",
|
|
46825
47768
|
d,
|
|
46826
47769
|
fill: water,
|
|
46827
|
-
stroke:
|
|
47770
|
+
stroke: lakeStroke,
|
|
46828
47771
|
lineNumber: -1,
|
|
46829
47772
|
layer: "base"
|
|
46830
47773
|
});
|
|
46831
47774
|
}
|
|
46832
47775
|
}
|
|
46833
|
-
const
|
|
47776
|
+
const pointInRings = (px, py, rings) => {
|
|
47777
|
+
let inside = false;
|
|
47778
|
+
for (const ring of rings) {
|
|
47779
|
+
for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
|
|
47780
|
+
const [xi, yi] = ring[i];
|
|
47781
|
+
const [xj, yj] = ring[j];
|
|
47782
|
+
if (yi > py !== yj > py && px < (xj - xi) * (py - yi) / (yj - yi) + xi)
|
|
47783
|
+
inside = !inside;
|
|
47784
|
+
}
|
|
47785
|
+
}
|
|
47786
|
+
return inside;
|
|
47787
|
+
};
|
|
47788
|
+
const fillHitTargets = [...regions, ...insetRegions].map((r) => ({
|
|
47789
|
+
fill: r.fill,
|
|
47790
|
+
rings: parsePathRings(r.d)
|
|
47791
|
+
}));
|
|
47792
|
+
const fillAt = (x, y) => {
|
|
47793
|
+
let hit = water;
|
|
47794
|
+
for (const t of fillHitTargets)
|
|
47795
|
+
if (pointInRings(x, y, t.rings)) hit = t.fill;
|
|
47796
|
+
return hit;
|
|
47797
|
+
};
|
|
47798
|
+
const labelOnFill = (fill2) => {
|
|
47799
|
+
const color = contrastRatio(fill2, palette.textOnFillDark) >= contrastRatio(fill2, palette.textOnFillLight) ? palette.textOnFillDark : palette.textOnFillLight;
|
|
47800
|
+
const haloColor = color === palette.textOnFillLight ? palette.textOnFillDark : palette.textOnFillLight;
|
|
47801
|
+
return {
|
|
47802
|
+
color,
|
|
47803
|
+
halo: contrastRatio(fill2, color) < REGION_LABEL_HALO_RATIO,
|
|
47804
|
+
haloColor
|
|
47805
|
+
};
|
|
47806
|
+
};
|
|
47807
|
+
const reliefAllowed = resolved.directives.noRelief !== true;
|
|
47808
|
+
const relief = [];
|
|
47809
|
+
let reliefHatch = null;
|
|
47810
|
+
if (reliefAllowed && data.mountainRanges) {
|
|
47811
|
+
for (const [, f] of decodeLayer(data.mountainRanges)) {
|
|
47812
|
+
const viewF = isGlobalView ? dropFrameFillers(f) : cullFeatureToView(f);
|
|
47813
|
+
if (!viewF) continue;
|
|
47814
|
+
const area2 = path.area(viewF);
|
|
47815
|
+
if (!Number.isFinite(area2) || area2 < RELIEF_MIN_AREA) continue;
|
|
47816
|
+
const box = path.bounds(viewF);
|
|
47817
|
+
if (box[1][0] - box[0][0] < RELIEF_MIN_DIM || box[1][1] - box[0][1] < RELIEF_MIN_DIM)
|
|
47818
|
+
continue;
|
|
47819
|
+
const d = path(viewF) ?? "";
|
|
47820
|
+
if (!d) continue;
|
|
47821
|
+
relief.push({ d });
|
|
47822
|
+
}
|
|
47823
|
+
if (relief.length) {
|
|
47824
|
+
const darkTone = isDark ? palette.bg : palette.text;
|
|
47825
|
+
const lightTone = isDark ? palette.text : palette.bg;
|
|
47826
|
+
const reliefLandRef = colorizeActive ? isDark ? palette.surface : palette.bg : neutralFill;
|
|
47827
|
+
const landLum = relativeLuminance(reliefLandRef);
|
|
47828
|
+
const tone = Math.abs(landLum - relativeLuminance(darkTone)) > 0.04 ? darkTone : lightTone;
|
|
47829
|
+
reliefHatch = {
|
|
47830
|
+
color: mix(tone, reliefLandRef, RELIEF_HATCH_STRENGTH),
|
|
47831
|
+
spacing: RELIEF_HATCH_SPACING,
|
|
47832
|
+
width: RELIEF_HATCH_WIDTH
|
|
47833
|
+
};
|
|
47834
|
+
}
|
|
47835
|
+
}
|
|
47836
|
+
let coastlineStyle = null;
|
|
47837
|
+
if (resolved.directives.noCoastline !== true) {
|
|
47838
|
+
const minDim = Math.min(width, height);
|
|
47839
|
+
coastlineStyle = {
|
|
47840
|
+
color: mix(regionStroke, water, COASTLINE_STROKE_MIX),
|
|
47841
|
+
// N equal-width rings: distance steps outward by COASTLINE_STEP; opacity
|
|
47842
|
+
// fades linearly from NEAR (innermost) to FAR (outermost).
|
|
47843
|
+
lines: Array.from({ length: COASTLINE_RING_COUNT }, (_, k) => ({
|
|
47844
|
+
d: (COASTLINE_D0 + k * COASTLINE_STEP) * minDim,
|
|
47845
|
+
thickness: COASTLINE_THICKNESS * minDim,
|
|
47846
|
+
opacity: COASTLINE_OPACITY_NEAR + (COASTLINE_OPACITY_FAR - COASTLINE_OPACITY_NEAR) * k / (COASTLINE_RING_COUNT - 1)
|
|
47847
|
+
})),
|
|
47848
|
+
minExtent: (isGlobalView ? COASTLINE_MIN_EXTENT_GLOBAL : COASTLINE_MIN_EXTENT) * minDim
|
|
47849
|
+
};
|
|
47850
|
+
}
|
|
47851
|
+
const riverColor = mix(palette.colors.blue, water, 32);
|
|
46834
47852
|
const rivers = [];
|
|
46835
47853
|
if (data.rivers) {
|
|
46836
47854
|
for (const [, f] of decodeLayer(data.rivers)) {
|
|
@@ -46851,6 +47869,9 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46851
47869
|
return R_MIN + Math.max(0, Math.min(1, t)) * (R_MAX - R_MIN);
|
|
46852
47870
|
};
|
|
46853
47871
|
const poiFill = (p) => {
|
|
47872
|
+
const directHex = p.color ? resolveColor(p.color, palette) : null;
|
|
47873
|
+
if (directHex)
|
|
47874
|
+
return { fill: directHex, stroke: mix(directHex, palette.text, 18) };
|
|
46854
47875
|
for (const group of resolved.tagGroups) {
|
|
46855
47876
|
const val = p.tags[group.name.toLowerCase()];
|
|
46856
47877
|
if (!val) continue;
|
|
@@ -46883,38 +47904,108 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46883
47904
|
const xy = project(p.lon, p.lat);
|
|
46884
47905
|
if (xy) projected.push({ p, xy });
|
|
46885
47906
|
}
|
|
46886
|
-
const
|
|
47907
|
+
const placePoi = (e, cx, cy, clusterId) => {
|
|
47908
|
+
const { fill: fill2, stroke: stroke2 } = poiFill(e.p);
|
|
47909
|
+
poiScreen.set(e.p.id, { cx, cy, r: radiusFor(e.p) });
|
|
47910
|
+
const num = routeNumberById.get(e.p.id);
|
|
47911
|
+
pois.push({
|
|
47912
|
+
id: e.p.id,
|
|
47913
|
+
cx,
|
|
47914
|
+
cy,
|
|
47915
|
+
r: radiusFor(e.p),
|
|
47916
|
+
fill: fill2,
|
|
47917
|
+
stroke: stroke2,
|
|
47918
|
+
lineNumber: e.p.lineNumber,
|
|
47919
|
+
implicit: !!e.p.implicit,
|
|
47920
|
+
isOrigin: originIds.has(e.p.id),
|
|
47921
|
+
...num !== void 0 && { routeNumber: num },
|
|
47922
|
+
...Object.keys(e.p.tags).length > 0 && { tags: e.p.tags },
|
|
47923
|
+
...clusterId !== void 0 && { clusterId }
|
|
47924
|
+
});
|
|
47925
|
+
};
|
|
47926
|
+
const clusters = [];
|
|
47927
|
+
const connected = /* @__PURE__ */ new Set();
|
|
47928
|
+
for (const e of resolved.edges) {
|
|
47929
|
+
connected.add(e.fromId);
|
|
47930
|
+
connected.add(e.toId);
|
|
47931
|
+
}
|
|
47932
|
+
for (const rt of resolved.routes) {
|
|
47933
|
+
rt.stopIds.forEach((id) => connected.add(id));
|
|
47934
|
+
}
|
|
47935
|
+
const radiusOf = (e) => radiusFor(e.p);
|
|
46887
47936
|
for (const e of projected) {
|
|
46888
|
-
|
|
46889
|
-
|
|
46890
|
-
|
|
46891
|
-
|
|
46892
|
-
|
|
46893
|
-
|
|
46894
|
-
|
|
46895
|
-
|
|
46896
|
-
|
|
46897
|
-
|
|
46898
|
-
|
|
46899
|
-
|
|
46900
|
-
|
|
46901
|
-
|
|
46902
|
-
|
|
46903
|
-
|
|
46904
|
-
|
|
46905
|
-
|
|
46906
|
-
|
|
46907
|
-
|
|
46908
|
-
|
|
46909
|
-
|
|
46910
|
-
|
|
46911
|
-
|
|
46912
|
-
|
|
46913
|
-
|
|
46914
|
-
|
|
46915
|
-
|
|
46916
|
-
|
|
46917
|
-
|
|
47937
|
+
if (connected.has(e.p.id)) placePoi(e, e.xy[0], e.xy[1]);
|
|
47938
|
+
}
|
|
47939
|
+
const groups = [];
|
|
47940
|
+
for (const e of projected) {
|
|
47941
|
+
if (connected.has(e.p.id)) continue;
|
|
47942
|
+
const r = radiusOf(e);
|
|
47943
|
+
const near = groups.find(
|
|
47944
|
+
(g) => g.some(
|
|
47945
|
+
(q) => Math.hypot(q.xy[0] - e.xy[0], q.xy[1] - e.xy[1]) < (r + radiusOf(q)) * STACK_OVERLAP
|
|
47946
|
+
)
|
|
47947
|
+
);
|
|
47948
|
+
if (near) near.push(e);
|
|
47949
|
+
else groups.push([e]);
|
|
47950
|
+
}
|
|
47951
|
+
for (const g of groups) {
|
|
47952
|
+
if (g.length === 1) {
|
|
47953
|
+
placePoi(g[0], g[0].xy[0], g[0].xy[1]);
|
|
47954
|
+
continue;
|
|
47955
|
+
}
|
|
47956
|
+
const clusterId = g[0].p.id;
|
|
47957
|
+
const cx0 = g.reduce((s, e) => s + e.xy[0], 0) / g.length;
|
|
47958
|
+
const cy0 = g.reduce((s, e) => s + e.xy[1], 0) / g.length;
|
|
47959
|
+
const maxR = Math.max(...g.map(radiusOf));
|
|
47960
|
+
const sep = 2 * maxR + STACK_RING_GAP;
|
|
47961
|
+
const ringR = Math.max(
|
|
47962
|
+
COLO_R,
|
|
47963
|
+
sep / (2 * Math.sin(Math.PI / Math.max(g.length, 2)))
|
|
47964
|
+
);
|
|
47965
|
+
const positions = g.map((e, i) => {
|
|
47966
|
+
if (g.length <= STACK_RING_MAX) {
|
|
47967
|
+
const ang2 = -Math.PI / 2 + i * 2 * Math.PI / g.length;
|
|
47968
|
+
return {
|
|
47969
|
+
e,
|
|
47970
|
+
mx: cx0 + Math.cos(ang2) * ringR,
|
|
47971
|
+
my: cy0 + Math.sin(ang2) * ringR
|
|
47972
|
+
};
|
|
47973
|
+
}
|
|
47974
|
+
const ang = i * GOLDEN_ANGLE;
|
|
47975
|
+
const rr = ringR * Math.sqrt((i + 1) / g.length);
|
|
47976
|
+
return { e, mx: cx0 + Math.cos(ang) * rr, my: cy0 + Math.sin(ang) * rr };
|
|
47977
|
+
});
|
|
47978
|
+
let minX = cx0 - maxR;
|
|
47979
|
+
let maxX = cx0 + maxR;
|
|
47980
|
+
let minY = cy0 - maxR;
|
|
47981
|
+
let maxY = cy0 + maxR;
|
|
47982
|
+
for (const { mx, my, e } of positions) {
|
|
47983
|
+
const r = radiusOf(e);
|
|
47984
|
+
minX = Math.min(minX, mx - r);
|
|
47985
|
+
maxX = Math.max(maxX, mx + r);
|
|
47986
|
+
minY = Math.min(minY, my - r);
|
|
47987
|
+
maxY = Math.max(maxY, my + r);
|
|
47988
|
+
}
|
|
47989
|
+
let dx = 0;
|
|
47990
|
+
let dy = 0;
|
|
47991
|
+
if (minX + dx < 2) dx = 2 - minX;
|
|
47992
|
+
if (maxX + dx > width - 2) dx = width - 2 - maxX;
|
|
47993
|
+
if (minY + dy < 2) dy = 2 - minY;
|
|
47994
|
+
if (maxY + dy > height - 2) dy = height - 2 - maxY;
|
|
47995
|
+
const legsOut = [];
|
|
47996
|
+
for (const { e, mx, my } of positions) {
|
|
47997
|
+
const fx = mx + dx;
|
|
47998
|
+
const fy = my + dy;
|
|
47999
|
+
placePoi(e, fx, fy, clusterId);
|
|
48000
|
+
legsOut.push({ x2: fx, y2: fy, color: poiFill(e.p).fill });
|
|
48001
|
+
}
|
|
48002
|
+
clusters.push({
|
|
48003
|
+
id: clusterId,
|
|
48004
|
+
cx: cx0 + dx,
|
|
48005
|
+
cy: cy0 + dy,
|
|
48006
|
+
count: g.length,
|
|
48007
|
+
hitR: ringR + maxR + 6,
|
|
48008
|
+
legs: legsOut
|
|
46918
48009
|
});
|
|
46919
48010
|
}
|
|
46920
48011
|
const legs = [];
|
|
@@ -46964,16 +48055,26 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46964
48055
|
if (!a || !b) continue;
|
|
46965
48056
|
const mx = (a.cx + b.cx) / 2;
|
|
46966
48057
|
const my = (a.cy + b.cy) / 2;
|
|
48058
|
+
const bow = {
|
|
48059
|
+
curved: leg.style === "arc",
|
|
48060
|
+
offset: 0,
|
|
48061
|
+
labelX: mx,
|
|
48062
|
+
labelY: my - 4
|
|
48063
|
+
};
|
|
48064
|
+
const routeLabelStyle = leg.label !== void 0 ? labelOnFill(fillAt(bow.labelX, bow.labelY)) : void 0;
|
|
46967
48065
|
legs.push({
|
|
46968
|
-
d: legPath(a, b,
|
|
48066
|
+
d: legPath(a, b, bow.curved, bow.offset),
|
|
46969
48067
|
width: routeWidthFor(Number(leg.value)),
|
|
46970
48068
|
color: mix(palette.text, palette.bg, 72),
|
|
46971
48069
|
arrow: true,
|
|
46972
48070
|
lineNumber: leg.lineNumber,
|
|
46973
48071
|
...leg.label !== void 0 && {
|
|
46974
48072
|
label: leg.label,
|
|
46975
|
-
labelX:
|
|
46976
|
-
labelY:
|
|
48073
|
+
labelX: bow.labelX,
|
|
48074
|
+
labelY: bow.labelY,
|
|
48075
|
+
labelColor: routeLabelStyle.color,
|
|
48076
|
+
labelHalo: routeLabelStyle.halo,
|
|
48077
|
+
labelHaloColor: routeLabelStyle.haloColor
|
|
46977
48078
|
}
|
|
46978
48079
|
});
|
|
46979
48080
|
}
|
|
@@ -47001,20 +48102,29 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47001
48102
|
const a = poiScreen.get(e.fromId);
|
|
47002
48103
|
const b = poiScreen.get(e.toId);
|
|
47003
48104
|
if (!a || !b) return;
|
|
47004
|
-
const
|
|
47005
|
-
const offset = n > 1 ? (i - (n - 1) / 2) * FAN_STEP : 0;
|
|
48105
|
+
const fanOffset = n > 1 ? (i - (n - 1) / 2) * FAN_STEP : 0;
|
|
47006
48106
|
const mx = (a.cx + b.cx) / 2;
|
|
47007
48107
|
const my = (a.cy + b.cy) / 2;
|
|
48108
|
+
const bow = {
|
|
48109
|
+
curved: e.style === "arc" || n > 1,
|
|
48110
|
+
offset: fanOffset,
|
|
48111
|
+
labelX: mx,
|
|
48112
|
+
labelY: my - 4
|
|
48113
|
+
};
|
|
48114
|
+
const edgeLabelStyle = e.label !== void 0 ? labelOnFill(fillAt(bow.labelX, bow.labelY)) : void 0;
|
|
47008
48115
|
legs.push({
|
|
47009
|
-
d: legPath(a, b, curved, offset),
|
|
48116
|
+
d: legPath(a, b, bow.curved, bow.offset),
|
|
47010
48117
|
width: widthFor(e),
|
|
47011
48118
|
color: mix(palette.text, palette.bg, 66),
|
|
47012
48119
|
arrow: e.directed,
|
|
47013
48120
|
lineNumber: e.lineNumber,
|
|
47014
48121
|
...e.label !== void 0 && {
|
|
47015
48122
|
label: e.label,
|
|
47016
|
-
labelX:
|
|
47017
|
-
labelY:
|
|
48123
|
+
labelX: bow.labelX,
|
|
48124
|
+
labelY: bow.labelY,
|
|
48125
|
+
labelColor: edgeLabelStyle.color,
|
|
48126
|
+
labelHalo: edgeLabelStyle.halo,
|
|
48127
|
+
labelHaloColor: edgeLabelStyle.haloColor
|
|
47018
48128
|
}
|
|
47019
48129
|
});
|
|
47020
48130
|
});
|
|
@@ -47056,25 +48166,25 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47056
48166
|
}
|
|
47057
48167
|
}
|
|
47058
48168
|
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));
|
|
47059
|
-
const
|
|
48169
|
+
const showRegionLabels = resolved.directives.noRegionLabels !== true;
|
|
48170
|
+
const isCompact = width < COMPACT_WIDTH_PX;
|
|
47060
48171
|
const LABEL_PADX = 6;
|
|
47061
48172
|
const LABEL_PADY = 3;
|
|
47062
|
-
const labelW = (text) => measureLegendText(text,
|
|
47063
|
-
const labelH =
|
|
48173
|
+
const labelW = (text) => measureLegendText(text, FONT2) + 2 * LABEL_PADX;
|
|
48174
|
+
const labelH = FONT2 + 2 * LABEL_PADY;
|
|
47064
48175
|
const pushRegionLabel = (x, y, text, fill2, lineNumber) => {
|
|
47065
|
-
const color =
|
|
47066
|
-
|
|
47067
|
-
|
|
47068
|
-
|
|
48176
|
+
const { color, haloColor } = labelOnFill(fill2);
|
|
48177
|
+
const halfW = measureLegendText(text, FONT2) / 2;
|
|
48178
|
+
const overflows = [y - FONT2 * 0.55, y - FONT2 * 0.1].some(
|
|
48179
|
+
(sy) => fillAt(x - halfW, sy) !== fill2 || fillAt(x + halfW, sy) !== fill2
|
|
47069
48180
|
);
|
|
47070
|
-
const haloColor = color === palette.textOnFillLight ? palette.textOnFillDark : palette.textOnFillLight;
|
|
47071
48181
|
labels.push({
|
|
47072
48182
|
x,
|
|
47073
48183
|
y,
|
|
47074
48184
|
text,
|
|
47075
48185
|
anchor: "middle",
|
|
47076
48186
|
color,
|
|
47077
|
-
halo:
|
|
48187
|
+
halo: overflows,
|
|
47078
48188
|
haloColor,
|
|
47079
48189
|
lineNumber
|
|
47080
48190
|
});
|
|
@@ -47083,21 +48193,50 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47083
48193
|
US: [-98.5, 39.5]
|
|
47084
48194
|
// CONUS geographic centre (near Lebanon, Kansas)
|
|
47085
48195
|
};
|
|
47086
|
-
|
|
47087
|
-
|
|
47088
|
-
|
|
47089
|
-
|
|
47090
|
-
|
|
48196
|
+
const REGION_LABEL_GAP = 2;
|
|
48197
|
+
const regionLabelRect = (cx, cy, text) => {
|
|
48198
|
+
const w = measureLegendText(text, FONT2) + 2 * REGION_LABEL_GAP;
|
|
48199
|
+
return { x: cx - w / 2, y: cy - FONT2 / 2, w, h: FONT2 };
|
|
48200
|
+
};
|
|
48201
|
+
if (showRegionLabels) {
|
|
48202
|
+
const frameContainers = new Set(resolved.poiFrameContainers);
|
|
48203
|
+
const entries = regions.map((r) => {
|
|
48204
|
+
const isContainer = frameContainers.has(r.id);
|
|
48205
|
+
if (r.layer === "base" && !isContainer || r.label === void 0)
|
|
48206
|
+
return null;
|
|
48207
|
+
const isUsState = r.layer === "us-state" || r.id.startsWith("US-");
|
|
48208
|
+
const f = isUsState ? usLayer?.get(r.id) : worldLayer.get(r.id);
|
|
48209
|
+
if (!f) return null;
|
|
47091
48210
|
const [[x0, y0], [x1, y1]] = path.bounds(f);
|
|
47092
|
-
const
|
|
47093
|
-
|
|
47094
|
-
const
|
|
48211
|
+
const boxW = x1 - x0;
|
|
48212
|
+
const boxH = y1 - y0;
|
|
48213
|
+
const abbrev = isUsState ? r.id.replace(/^US-/, "") : void 0;
|
|
48214
|
+
const candidates = abbrev !== void 0 ? isCompact ? [abbrev, r.label] : [r.label, abbrev] : [r.label];
|
|
48215
|
+
const anchor = !isUsState ? WORLD_LABEL_ANCHORS[r.id] : void 0;
|
|
47095
48216
|
const c = anchor ? project(anchor[0], anchor[1]) : path.centroid(f);
|
|
47096
|
-
if (!c || !Number.isFinite(c[0]))
|
|
48217
|
+
if (!c || !Number.isFinite(c[0])) return null;
|
|
48218
|
+
return { r, c, boxW, boxH, area: boxW * boxH, candidates };
|
|
48219
|
+
}).filter((e) => e !== null).sort((a, b) => b.area - a.area || a.r.lineNumber - b.r.lineNumber);
|
|
48220
|
+
const placedRegionRects = [];
|
|
48221
|
+
const POI_LABEL_PAD = 14;
|
|
48222
|
+
const poiObstacles = pois.map((p) => ({
|
|
48223
|
+
x: p.cx - p.r - POI_LABEL_PAD,
|
|
48224
|
+
y: p.cy - p.r - POI_LABEL_PAD,
|
|
48225
|
+
w: 2 * (p.r + POI_LABEL_PAD),
|
|
48226
|
+
h: 2 * (p.r + POI_LABEL_PAD)
|
|
48227
|
+
}));
|
|
48228
|
+
for (const { r, c, boxW, boxH, candidates } of entries) {
|
|
48229
|
+
const text = candidates.find((t) => {
|
|
48230
|
+
if (labelW(t) > boxW || labelH > boxH) return false;
|
|
48231
|
+
const rect = regionLabelRect(c[0], c[1], t);
|
|
48232
|
+
return !placedRegionRects.some((p) => rectsOverlap(rect, p)) && !poiObstacles.some((o) => rectsOverlap(rect, o));
|
|
48233
|
+
});
|
|
48234
|
+
if (text === void 0) continue;
|
|
48235
|
+
placedRegionRects.push(regionLabelRect(c[0], c[1], text));
|
|
47097
48236
|
pushRegionLabel(c[0], c[1], text, r.fill, r.lineNumber);
|
|
47098
48237
|
}
|
|
47099
48238
|
for (const seed of insetLabelSeeds) {
|
|
47100
|
-
const text =
|
|
48239
|
+
const text = isCompact ? seed.iso.replace(/^US-/, "") : seed.name;
|
|
47101
48240
|
const src = regionById.get(seed.iso);
|
|
47102
48241
|
pushRegionLabel(
|
|
47103
48242
|
seed.x,
|
|
@@ -47108,22 +48247,26 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47108
48247
|
);
|
|
47109
48248
|
}
|
|
47110
48249
|
}
|
|
47111
|
-
|
|
47112
|
-
|
|
47113
|
-
const ordered = [...pois].sort(
|
|
47114
|
-
(a, b) => a.lineNumber - b.lineNumber || (a.id < b.id ? -1 : 1)
|
|
47115
|
-
);
|
|
48250
|
+
if (resolved.directives.noPoiLabels !== true) {
|
|
48251
|
+
const ordered = [...pois].filter((p) => p.clusterId === void 0).sort((a, b) => a.lineNumber - b.lineNumber || (a.id < b.id ? -1 : 1));
|
|
47116
48252
|
const poiById = new Map(resolved.pois.map((q) => [q.id, q]));
|
|
47117
48253
|
const labelText = (p) => {
|
|
47118
48254
|
const src = poiById.get(p.id);
|
|
47119
48255
|
return src?.label ?? src?.name ?? p.id;
|
|
47120
48256
|
};
|
|
47121
|
-
const poiLabH =
|
|
48257
|
+
const poiLabH = FONT2 * 1.25;
|
|
47122
48258
|
const labelInfo = (p) => {
|
|
47123
48259
|
const text = labelText(p);
|
|
47124
|
-
return { text, w: measureLegendText(text,
|
|
48260
|
+
return { text, w: measureLegendText(text, FONT2) };
|
|
47125
48261
|
};
|
|
47126
48262
|
const GAP = 3;
|
|
48263
|
+
const clusterMembersById = /* @__PURE__ */ new Map();
|
|
48264
|
+
for (const p of pois) {
|
|
48265
|
+
if (p.clusterId === void 0) continue;
|
|
48266
|
+
const arr = clusterMembersById.get(p.clusterId);
|
|
48267
|
+
if (arr) arr.push(p);
|
|
48268
|
+
else clusterMembersById.set(p.clusterId, [p]);
|
|
48269
|
+
}
|
|
47127
48270
|
const inlineRect = (p, w, side) => {
|
|
47128
48271
|
switch (side) {
|
|
47129
48272
|
case "right":
|
|
@@ -47153,11 +48296,11 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47153
48296
|
const x = side === "right" ? rect.x : side === "left" ? rect.x + w : p.cx;
|
|
47154
48297
|
labels.push({
|
|
47155
48298
|
x,
|
|
47156
|
-
y: rect.y + poiLabH / 2 +
|
|
48299
|
+
y: rect.y + poiLabH / 2 + FONT2 / 3,
|
|
47157
48300
|
text,
|
|
47158
48301
|
anchor,
|
|
47159
48302
|
color: palette.text,
|
|
47160
|
-
halo:
|
|
48303
|
+
halo: false,
|
|
47161
48304
|
haloColor: palette.bg,
|
|
47162
48305
|
poiId: p.id,
|
|
47163
48306
|
lineNumber: p.lineNumber
|
|
@@ -47168,43 +48311,60 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47168
48311
|
return rect.x >= 0 && rect.x + rect.w <= width && rect.y >= 0 && rect.y + rect.h <= height && !collides(rect);
|
|
47169
48312
|
};
|
|
47170
48313
|
const GROUP_R = 30;
|
|
47171
|
-
const
|
|
48314
|
+
const groups2 = [];
|
|
47172
48315
|
for (const p of ordered) {
|
|
47173
|
-
const near =
|
|
48316
|
+
const near = groups2.find(
|
|
47174
48317
|
(g) => g.some((q) => Math.hypot(q.cx - p.cx, q.cy - p.cy) < GROUP_R)
|
|
47175
48318
|
);
|
|
47176
48319
|
if (near) near.push(p);
|
|
47177
|
-
else
|
|
48320
|
+
else groups2.push([p]);
|
|
47178
48321
|
}
|
|
47179
48322
|
const ROW_GAP2 = 3;
|
|
47180
48323
|
const step = poiLabH + ROW_GAP2;
|
|
47181
48324
|
const COL_GAP = 16;
|
|
47182
|
-
const
|
|
47183
|
-
|
|
48325
|
+
const makeItems = (group) => group.map((p) => ({ p, ...labelInfo(p) })).sort((a, b) => a.p.cy - b.p.cy || (a.text < b.text ? -1 : 1));
|
|
48326
|
+
const columnRows = (items, side) => {
|
|
47184
48327
|
const left = Math.min(...items.map((o) => o.p.cx - o.p.r));
|
|
47185
48328
|
const right = Math.max(...items.map((o) => o.p.cx + o.p.r));
|
|
47186
|
-
const cyMid = (Math.min(...items.map((o) => o.p.cy)) + Math.max(...items.map((o) => o.p.cy))) / 2;
|
|
47187
48329
|
const maxW = Math.max(...items.map((o) => o.w));
|
|
47188
|
-
const
|
|
47189
|
-
const colX = side === "right" ? right + COL_GAP : left - COL_GAP;
|
|
48330
|
+
const cyMid = (Math.min(...items.map((o) => o.p.cy)) + Math.max(...items.map((o) => o.p.cy))) / 2;
|
|
48331
|
+
const colX = side === "right" ? Math.min(right + COL_GAP, width - 2 - maxW) : Math.max(left - COL_GAP, 2 + maxW);
|
|
47190
48332
|
const totalH = items.length * step;
|
|
47191
48333
|
let startY = cyMid - totalH / 2;
|
|
47192
48334
|
startY = Math.max(2, Math.min(startY, height - totalH - 2));
|
|
47193
|
-
items.
|
|
48335
|
+
return items.map((o, i) => {
|
|
47194
48336
|
const rowCy = startY + i * step + step / 2;
|
|
47195
|
-
|
|
47196
|
-
|
|
47197
|
-
|
|
47198
|
-
|
|
47199
|
-
|
|
47200
|
-
|
|
48337
|
+
return {
|
|
48338
|
+
o,
|
|
48339
|
+
colX,
|
|
48340
|
+
rowCy,
|
|
48341
|
+
rect: {
|
|
48342
|
+
x: side === "right" ? colX : colX - o.w,
|
|
48343
|
+
y: rowCy - poiLabH / 2,
|
|
48344
|
+
w: o.w,
|
|
48345
|
+
h: poiLabH
|
|
48346
|
+
}
|
|
48347
|
+
};
|
|
48348
|
+
});
|
|
48349
|
+
};
|
|
48350
|
+
const wouldColumnBeClean = (items, side) => columnRows(items, side).every(
|
|
48351
|
+
({ rect }) => rect.x >= 0 && rect.x + rect.w <= width && rect.y >= 0 && rect.y + rect.h <= height && !collides(rect)
|
|
48352
|
+
);
|
|
48353
|
+
const defaultColumnSide = (items) => {
|
|
48354
|
+
const right = Math.max(...items.map((o) => o.p.cx + o.p.r));
|
|
48355
|
+
const maxW = Math.max(...items.map((o) => o.w));
|
|
48356
|
+
return right + COL_GAP + maxW <= width - 2 ? "right" : "left";
|
|
48357
|
+
};
|
|
48358
|
+
const commitColumn = (items, side, clusterId) => {
|
|
48359
|
+
for (const { o, colX, rowCy, rect } of columnRows(items, side)) {
|
|
48360
|
+
obstacles.push(rect);
|
|
47201
48361
|
labels.push({
|
|
47202
48362
|
x: colX,
|
|
47203
|
-
y: rowCy +
|
|
48363
|
+
y: rowCy + FONT2 / 3,
|
|
47204
48364
|
text: o.text,
|
|
47205
48365
|
anchor: side === "right" ? "start" : "end",
|
|
47206
48366
|
color: palette.text,
|
|
47207
|
-
halo:
|
|
48367
|
+
halo: false,
|
|
47208
48368
|
haloColor: palette.bg,
|
|
47209
48369
|
leader: {
|
|
47210
48370
|
x1: o.p.cx,
|
|
@@ -47214,24 +48374,141 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47214
48374
|
},
|
|
47215
48375
|
leaderColor: o.p.fill,
|
|
47216
48376
|
poiId: o.p.id,
|
|
47217
|
-
lineNumber: o.p.lineNumber
|
|
48377
|
+
lineNumber: o.p.lineNumber,
|
|
48378
|
+
...clusterId !== void 0 && { clusterMember: clusterId }
|
|
47218
48379
|
});
|
|
48380
|
+
}
|
|
48381
|
+
};
|
|
48382
|
+
const pushHidden = (p) => {
|
|
48383
|
+
const { text, w } = labelInfo(p);
|
|
48384
|
+
let x = p.cx + p.r + GAP;
|
|
48385
|
+
let anchor = "start";
|
|
48386
|
+
if (x + w > width) {
|
|
48387
|
+
x = p.cx - p.r - GAP - w;
|
|
48388
|
+
anchor = "end";
|
|
48389
|
+
}
|
|
48390
|
+
const y = Math.max(0, Math.min(p.cy - poiLabH / 2, height - poiLabH));
|
|
48391
|
+
labels.push({
|
|
48392
|
+
x: anchor === "start" ? x : x + w,
|
|
48393
|
+
y: y + poiLabH / 2 + FONT2 / 3,
|
|
48394
|
+
text,
|
|
48395
|
+
anchor,
|
|
48396
|
+
color: palette.text,
|
|
48397
|
+
halo: false,
|
|
48398
|
+
haloColor: palette.bg,
|
|
48399
|
+
poiId: p.id,
|
|
48400
|
+
hidden: true,
|
|
48401
|
+
lineNumber: p.lineNumber
|
|
47219
48402
|
});
|
|
47220
48403
|
};
|
|
47221
|
-
for (const
|
|
48404
|
+
for (const [clusterId, members] of clusterMembersById) {
|
|
48405
|
+
if (members.length === 0) continue;
|
|
48406
|
+
const items = makeItems(members);
|
|
48407
|
+
const side = wouldColumnBeClean(items, "right") ? "right" : wouldColumnBeClean(items, "left") ? "left" : defaultColumnSide(items);
|
|
48408
|
+
commitColumn(items, side, clusterId);
|
|
48409
|
+
}
|
|
48410
|
+
const maxExtent = MAX_CLUSTER_EXTENT_FACTOR * Math.min(width, height);
|
|
48411
|
+
const clusterPending = [];
|
|
48412
|
+
for (const g of groups2) {
|
|
48413
|
+
const items = makeItems(g);
|
|
47222
48414
|
if (g.length === 1) {
|
|
47223
|
-
const p =
|
|
47224
|
-
const { text, w } = labelInfo(p);
|
|
48415
|
+
const { p, text, w } = items[0];
|
|
47225
48416
|
const side = ["right", "left", "above", "below"].find(
|
|
47226
48417
|
(s) => inlineFits(p, w, s)
|
|
47227
48418
|
);
|
|
47228
|
-
if (side)
|
|
47229
|
-
|
|
47230
|
-
|
|
48419
|
+
if (side) pushInline(p, text, w, side);
|
|
48420
|
+
else commitColumn(items, defaultColumnSide(items));
|
|
48421
|
+
continue;
|
|
48422
|
+
}
|
|
48423
|
+
const left = Math.min(...items.map((o) => o.p.cx - o.p.r));
|
|
48424
|
+
const right = Math.max(...items.map((o) => o.p.cx + o.p.r));
|
|
48425
|
+
const minCy = Math.min(...items.map((o) => o.p.cy));
|
|
48426
|
+
const maxCy = Math.max(...items.map((o) => o.p.cy));
|
|
48427
|
+
const diag = Math.hypot(right - left, maxCy - minCy);
|
|
48428
|
+
if (diag > maxExtent || items.length > MAX_COLUMN_ROWS) {
|
|
48429
|
+
items.forEach((o) => pushHidden(o.p));
|
|
48430
|
+
} else {
|
|
48431
|
+
clusterPending.push(items);
|
|
48432
|
+
}
|
|
48433
|
+
}
|
|
48434
|
+
for (const items of clusterPending) {
|
|
48435
|
+
const side = ["right", "left"].find(
|
|
48436
|
+
(s) => wouldColumnBeClean(items, s)
|
|
48437
|
+
);
|
|
48438
|
+
if (side) commitColumn(items, side);
|
|
48439
|
+
else items.forEach((o) => pushHidden(o.p));
|
|
48440
|
+
}
|
|
48441
|
+
}
|
|
48442
|
+
if (resolved.directives.noContextLabels !== true) {
|
|
48443
|
+
for (const l of labels) {
|
|
48444
|
+
if (l.hidden) continue;
|
|
48445
|
+
const w = labelW(l.text);
|
|
48446
|
+
const x = l.anchor === "start" ? l.x : l.anchor === "end" ? l.x - w : l.x - w / 2;
|
|
48447
|
+
obstacles.push({ x, y: l.y - labelH / 2, w, h: labelH });
|
|
48448
|
+
}
|
|
48449
|
+
for (const box of insets)
|
|
48450
|
+
obstacles.push({ x: box.x, y: box.y, w: box.w, h: box.h });
|
|
48451
|
+
const countryCandidates = [];
|
|
48452
|
+
for (const f of worldLayer.values()) {
|
|
48453
|
+
const iso = typeof f.id === "string" ? f.id : String(f.id ?? "");
|
|
48454
|
+
if (!iso || regionById.has(iso)) continue;
|
|
48455
|
+
let hasReferencedSub = false;
|
|
48456
|
+
for (const k of regionById.keys())
|
|
48457
|
+
if (k.startsWith(iso + "-")) {
|
|
48458
|
+
hasReferencedSub = true;
|
|
48459
|
+
break;
|
|
47231
48460
|
}
|
|
48461
|
+
if (hasReferencedSub) continue;
|
|
48462
|
+
const b = path.bounds(f);
|
|
48463
|
+
const [x0, y0] = b[0];
|
|
48464
|
+
const [x1, y1] = b[1];
|
|
48465
|
+
if (!Number.isFinite(x0) || !Number.isFinite(x1)) continue;
|
|
48466
|
+
const anchorLngLat = WORLD_LABEL_ANCHORS[iso];
|
|
48467
|
+
const a = anchorLngLat ? project(anchorLngLat[0], anchorLngLat[1]) : path.centroid(f);
|
|
48468
|
+
countryCandidates.push({
|
|
48469
|
+
name: f.properties?.name ?? iso,
|
|
48470
|
+
bbox: [x0, y0, x1, y1],
|
|
48471
|
+
anchor: a && Number.isFinite(a[0]) ? [a[0], a[1]] : null
|
|
48472
|
+
});
|
|
48473
|
+
}
|
|
48474
|
+
const framedStateContainers = (resolved.poiFrameContainers ?? []).some(
|
|
48475
|
+
(id) => id.startsWith("US-")
|
|
48476
|
+
);
|
|
48477
|
+
if (usLayer && framedStateContainers) {
|
|
48478
|
+
const containerSet = new Set(resolved.poiFrameContainers);
|
|
48479
|
+
for (const [iso, f] of usLayer) {
|
|
48480
|
+
if (containerSet.has(iso) || regionById.has(iso)) continue;
|
|
48481
|
+
const viewF = cullFeatureToView(f);
|
|
48482
|
+
if (!viewF) continue;
|
|
48483
|
+
const b = path.bounds(viewF);
|
|
48484
|
+
const [x0, y0] = b[0];
|
|
48485
|
+
const [x1, y1] = b[1];
|
|
48486
|
+
if (!Number.isFinite(x0) || !Number.isFinite(x1)) continue;
|
|
48487
|
+
const a = path.centroid(viewF);
|
|
48488
|
+
countryCandidates.push({
|
|
48489
|
+
name: f.properties?.name ?? iso,
|
|
48490
|
+
bbox: [x0, y0, x1, y1],
|
|
48491
|
+
anchor: a && Number.isFinite(a[0]) ? [a[0], a[1]] : null
|
|
48492
|
+
});
|
|
47232
48493
|
}
|
|
47233
|
-
placeColumn(g);
|
|
47234
48494
|
}
|
|
48495
|
+
const contextLabels = placeContextLabels({
|
|
48496
|
+
projection: resolved.projection,
|
|
48497
|
+
dLonSpan,
|
|
48498
|
+
dLatSpan,
|
|
48499
|
+
width,
|
|
48500
|
+
height,
|
|
48501
|
+
waterBodies: data.waterBodies,
|
|
48502
|
+
countries: countryCandidates,
|
|
48503
|
+
palette,
|
|
48504
|
+
project,
|
|
48505
|
+
collides,
|
|
48506
|
+
// Water labels must stay over open water — `fillAt` returns the ocean
|
|
48507
|
+
// backdrop colour off-land and a region fill on-land (lakes/states count
|
|
48508
|
+
// as land here, which is the safe side for an ocean name).
|
|
48509
|
+
overLand: (x, y) => fillAt(x, y) !== water
|
|
48510
|
+
});
|
|
48511
|
+
labels.push(...contextLabels);
|
|
47235
48512
|
}
|
|
47236
48513
|
let legend = null;
|
|
47237
48514
|
if (!resolved.directives.noLegend) {
|
|
@@ -47266,22 +48543,33 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47266
48543
|
...resolved.caption !== void 0 && { caption: resolved.caption },
|
|
47267
48544
|
regions,
|
|
47268
48545
|
rivers,
|
|
48546
|
+
relief,
|
|
48547
|
+
reliefHatch,
|
|
48548
|
+
coastlineStyle,
|
|
47269
48549
|
legs,
|
|
47270
48550
|
pois,
|
|
48551
|
+
clusters,
|
|
47271
48552
|
labels,
|
|
47272
48553
|
legend,
|
|
47273
48554
|
insets,
|
|
47274
|
-
insetRegions
|
|
48555
|
+
insetRegions,
|
|
48556
|
+
projection,
|
|
48557
|
+
stretch: stretchParams,
|
|
48558
|
+
diagnostics: []
|
|
47275
48559
|
};
|
|
47276
48560
|
}
|
|
47277
|
-
var FIT_PAD, RAMP_FLOOR, R_DEFAULT, R_MIN, R_MAX, W_MIN, W_MAX,
|
|
48561
|
+
var FIT_PAD, RAMP_FLOOR, R_DEFAULT, R_MIN, R_MAX, W_MIN, W_MAX, FONT2, MAX_CLUSTER_EXTENT_FACTOR, MAX_COLUMN_ROWS, REGION_LABEL_HALO_RATIO, LAND_TINT_LIGHT, LAND_TINT_DARK, TAG_TINT_LIGHT, TAG_TINT_DARK, WATER_TINT_LIGHT, WATER_TINT_DARK, RIVER_WIDTH, COMPACT_WIDTH_PX, RELIEF_MIN_AREA, RELIEF_MIN_DIM, RELIEF_HATCH_SPACING, RELIEF_HATCH_WIDTH, RELIEF_HATCH_STRENGTH, COASTLINE_RING_COUNT, COASTLINE_D0, COASTLINE_STEP, COASTLINE_THICKNESS, COASTLINE_OPACITY_NEAR, COASTLINE_OPACITY_FAR, COASTLINE_MIN_EXTENT, COASTLINE_MIN_EXTENT_GLOBAL, COASTLINE_STROKE_MIX, FOREIGN_TINT_LIGHT, FOREIGN_TINT_DARK, MUTED_FOREIGN_LIGHT, MUTED_FOREIGN_DARK, COLO_R, GOLDEN_ANGLE, STACK_OVERLAP, STACK_RING_MAX, STACK_RING_GAP, FAN_STEP, ARC_CURVE_FRAC, decodeCache, usConusProjection, alaskaProjection, hawaiiProjection, INSET_STATES, inAlaska, inHawaii, FOREIGN_BORDER, US_NON_CONUS;
|
|
47278
48562
|
var init_layout15 = __esm({
|
|
47279
48563
|
"src/map/layout.ts"() {
|
|
47280
48564
|
"use strict";
|
|
47281
48565
|
init_color_utils();
|
|
48566
|
+
init_geo();
|
|
48567
|
+
init_colorize();
|
|
48568
|
+
init_colors();
|
|
47282
48569
|
init_label_layout();
|
|
47283
48570
|
init_legend_constants();
|
|
47284
48571
|
init_title_constants();
|
|
48572
|
+
init_context_labels();
|
|
47285
48573
|
FIT_PAD = 24;
|
|
47286
48574
|
RAMP_FLOOR = 15;
|
|
47287
48575
|
R_DEFAULT = 6;
|
|
@@ -47289,29 +48577,66 @@ var init_layout15 = __esm({
|
|
|
47289
48577
|
R_MAX = 22;
|
|
47290
48578
|
W_MIN = 1.25;
|
|
47291
48579
|
W_MAX = 8;
|
|
47292
|
-
|
|
47293
|
-
|
|
47294
|
-
|
|
47295
|
-
|
|
48580
|
+
FONT2 = 11;
|
|
48581
|
+
MAX_CLUSTER_EXTENT_FACTOR = 0.18;
|
|
48582
|
+
MAX_COLUMN_ROWS = 7;
|
|
48583
|
+
REGION_LABEL_HALO_RATIO = 4.5;
|
|
48584
|
+
LAND_TINT_LIGHT = 12;
|
|
48585
|
+
LAND_TINT_DARK = 24;
|
|
47296
48586
|
TAG_TINT_LIGHT = 60;
|
|
47297
48587
|
TAG_TINT_DARK = 68;
|
|
47298
|
-
|
|
48588
|
+
WATER_TINT_LIGHT = 24;
|
|
48589
|
+
WATER_TINT_DARK = 24;
|
|
47299
48590
|
RIVER_WIDTH = 1.3;
|
|
48591
|
+
COMPACT_WIDTH_PX = 480;
|
|
48592
|
+
RELIEF_MIN_AREA = 12;
|
|
48593
|
+
RELIEF_MIN_DIM = 2;
|
|
48594
|
+
RELIEF_HATCH_SPACING = 2;
|
|
48595
|
+
RELIEF_HATCH_WIDTH = 0.15;
|
|
48596
|
+
RELIEF_HATCH_STRENGTH = 32;
|
|
48597
|
+
COASTLINE_RING_COUNT = 5;
|
|
48598
|
+
COASTLINE_D0 = 16e-4;
|
|
48599
|
+
COASTLINE_STEP = 28e-4;
|
|
48600
|
+
COASTLINE_THICKNESS = 14e-4;
|
|
48601
|
+
COASTLINE_OPACITY_NEAR = 0.5;
|
|
48602
|
+
COASTLINE_OPACITY_FAR = 0.1;
|
|
48603
|
+
COASTLINE_MIN_EXTENT = 6e-4;
|
|
48604
|
+
COASTLINE_MIN_EXTENT_GLOBAL = 6e-4;
|
|
48605
|
+
COASTLINE_STROKE_MIX = 32;
|
|
47300
48606
|
FOREIGN_TINT_LIGHT = 30;
|
|
47301
48607
|
FOREIGN_TINT_DARK = 62;
|
|
47302
|
-
MUTED_WATER_LIGHT = 14;
|
|
47303
|
-
MUTED_WATER_DARK = 10;
|
|
47304
48608
|
MUTED_FOREIGN_LIGHT = 28;
|
|
47305
48609
|
MUTED_FOREIGN_DARK = 16;
|
|
47306
|
-
MUTED_LAND_DARK = 24;
|
|
47307
48610
|
COLO_R = 9;
|
|
47308
48611
|
GOLDEN_ANGLE = 2.399963229728653;
|
|
48612
|
+
STACK_OVERLAP = 1;
|
|
48613
|
+
STACK_RING_MAX = 8;
|
|
48614
|
+
STACK_RING_GAP = 4;
|
|
47309
48615
|
FAN_STEP = 16;
|
|
47310
48616
|
ARC_CURVE_FRAC = 0.18;
|
|
48617
|
+
decodeCache = /* @__PURE__ */ new WeakMap();
|
|
47311
48618
|
usConusProjection = () => geoConicEqualArea().parallels([29.5, 45.5]).rotate([96, 0]);
|
|
47312
48619
|
alaskaProjection = () => geoConicEqualArea().rotate([154, 0]).center([-2, 58.5]).parallels([55, 65]);
|
|
47313
48620
|
hawaiiProjection = () => geoMercator();
|
|
47314
48621
|
INSET_STATES = /* @__PURE__ */ new Set(["US-AK", "US-HI"]);
|
|
48622
|
+
inAlaska = (lon, lat) => lat >= 51 && (lon <= -129 || lon >= 172);
|
|
48623
|
+
inHawaii = (lon, lat) => lat >= 18 && lat <= 23 && lon >= -161 && lon <= -154;
|
|
48624
|
+
FOREIGN_BORDER = {
|
|
48625
|
+
CA: [
|
|
48626
|
+
"US-AK",
|
|
48627
|
+
"US-WA",
|
|
48628
|
+
"US-ID",
|
|
48629
|
+
"US-MT",
|
|
48630
|
+
"US-ND",
|
|
48631
|
+
"US-MN",
|
|
48632
|
+
"US-MI",
|
|
48633
|
+
"US-NY",
|
|
48634
|
+
"US-VT",
|
|
48635
|
+
"US-NH",
|
|
48636
|
+
"US-ME"
|
|
48637
|
+
],
|
|
48638
|
+
MX: ["US-CA", "US-AZ", "US-NM", "US-TX"]
|
|
48639
|
+
};
|
|
47315
48640
|
US_NON_CONUS = /* @__PURE__ */ new Set([
|
|
47316
48641
|
"US-AK",
|
|
47317
48642
|
"US-HI",
|
|
@@ -47331,6 +48656,58 @@ __export(renderer_exports16, {
|
|
|
47331
48656
|
renderMapForExport: () => renderMapForExport
|
|
47332
48657
|
});
|
|
47333
48658
|
import * as d3Selection18 from "d3-selection";
|
|
48659
|
+
function pointInRing2(px, py, ring) {
|
|
48660
|
+
let inside = false;
|
|
48661
|
+
for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
|
|
48662
|
+
const [xi, yi] = ring[i];
|
|
48663
|
+
const [xj, yj] = ring[j];
|
|
48664
|
+
if (yi > py !== yj > py && px < (xj - xi) * (py - yi) / (yj - yi) + xi)
|
|
48665
|
+
inside = !inside;
|
|
48666
|
+
}
|
|
48667
|
+
return inside;
|
|
48668
|
+
}
|
|
48669
|
+
function ringToPath(ring) {
|
|
48670
|
+
let d = "";
|
|
48671
|
+
for (let i = 0; i < ring.length; i++)
|
|
48672
|
+
d += (i ? "L" : "M") + ring[i][0] + "," + ring[i][1];
|
|
48673
|
+
return d + "Z";
|
|
48674
|
+
}
|
|
48675
|
+
function coastlineOuterRings(regions, minExtent) {
|
|
48676
|
+
const paths = [];
|
|
48677
|
+
for (const r of regions) {
|
|
48678
|
+
const rings = parsePathRings(r.d);
|
|
48679
|
+
for (let i = 0; i < rings.length; i++) {
|
|
48680
|
+
const ring = rings[i];
|
|
48681
|
+
if (ring.length < 3) continue;
|
|
48682
|
+
let minX = Infinity;
|
|
48683
|
+
let minY = Infinity;
|
|
48684
|
+
let maxX = -Infinity;
|
|
48685
|
+
let maxY = -Infinity;
|
|
48686
|
+
for (const [x, y] of ring) {
|
|
48687
|
+
if (x < minX) minX = x;
|
|
48688
|
+
if (x > maxX) maxX = x;
|
|
48689
|
+
if (y < minY) minY = y;
|
|
48690
|
+
if (y > maxY) maxY = y;
|
|
48691
|
+
}
|
|
48692
|
+
if (Math.max(maxX - minX, maxY - minY) < minExtent) continue;
|
|
48693
|
+
const [fx, fy] = ring[0];
|
|
48694
|
+
let depth = 0;
|
|
48695
|
+
for (let j = 0; j < rings.length; j++)
|
|
48696
|
+
if (j !== i && pointInRing2(fx, fy, rings[j])) depth++;
|
|
48697
|
+
if (depth % 2 === 1) continue;
|
|
48698
|
+
paths.push(ringToPath(ring));
|
|
48699
|
+
}
|
|
48700
|
+
}
|
|
48701
|
+
return paths;
|
|
48702
|
+
}
|
|
48703
|
+
function appendWaterLines(g, outerRings, style, flatWater) {
|
|
48704
|
+
const d = outerRings.join(" ");
|
|
48705
|
+
const linesOuterFirst = [...style.lines].sort((a, b) => b.d - a.d);
|
|
48706
|
+
for (const line12 of linesOuterFirst) {
|
|
48707
|
+
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");
|
|
48708
|
+
g.append("path").attr("d", d).attr("stroke", flatWater).attr("stroke-width", 2 * line12.d).attr("stroke-linejoin", "round").attr("stroke-linecap", "round");
|
|
48709
|
+
}
|
|
48710
|
+
}
|
|
47334
48711
|
function renderMap(container, resolved, data, palette, isDark, onClickItem, exportDims, activeGroupOverride) {
|
|
47335
48712
|
d3Selection18.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
47336
48713
|
const width = exportDims?.width ?? container.clientWidth;
|
|
@@ -47343,6 +48720,11 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47343
48720
|
{
|
|
47344
48721
|
palette,
|
|
47345
48722
|
isDark,
|
|
48723
|
+
// Export-only: forward the contain-fit request from mapExportDimensions so a
|
|
48724
|
+
// clamped/floored (off-aspect) export canvas letterboxes instead of
|
|
48725
|
+
// stretch-distorting. The in-app preview pane passes no exportDims → unset →
|
|
48726
|
+
// keeps the global stretch-fill.
|
|
48727
|
+
preferContain: exportDims?.preferContain ?? false,
|
|
47346
48728
|
...activeGroupOverride !== void 0 && {
|
|
47347
48729
|
activeGroup: activeGroupOverride
|
|
47348
48730
|
}
|
|
@@ -47356,6 +48738,7 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47356
48738
|
const gRegions = svg.append("g").attr("class", "dgmo-map-regions");
|
|
47357
48739
|
const drawRegion = (g, r, strokeWidth) => {
|
|
47358
48740
|
const p = g.append("path").attr("d", r.d).attr("fill", r.fill).attr("stroke", r.stroke).attr("stroke-width", strokeWidth);
|
|
48741
|
+
if (r.label) p.attr("data-region-name", r.label);
|
|
47359
48742
|
if (r.layer !== "base") {
|
|
47360
48743
|
p.classed("dgmo-map-region", true).attr("data-region", r.id);
|
|
47361
48744
|
if (r.value !== void 0) p.attr("data-value", r.value);
|
|
@@ -47376,6 +48759,52 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47376
48759
|
}
|
|
47377
48760
|
};
|
|
47378
48761
|
for (const r of layout.regions) drawRegion(gRegions, r, 0.5);
|
|
48762
|
+
if (layout.relief.length && layout.reliefHatch) {
|
|
48763
|
+
const h = layout.reliefHatch;
|
|
48764
|
+
const rangeClipId = "dgmo-relief-clip";
|
|
48765
|
+
const landClipId = "dgmo-relief-land";
|
|
48766
|
+
const rangeClip = defs.append("clipPath").attr("id", rangeClipId);
|
|
48767
|
+
for (const s of layout.relief) rangeClip.append("path").attr("d", s.d);
|
|
48768
|
+
const landClip = defs.append("clipPath").attr("id", landClipId);
|
|
48769
|
+
for (const r of layout.regions)
|
|
48770
|
+
if (r.id !== "lake") landClip.append("path").attr("d", r.d);
|
|
48771
|
+
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");
|
|
48772
|
+
for (let y = h.spacing; y < height; y += h.spacing) {
|
|
48773
|
+
gRelief.append("line").attr("x1", 0).attr("y1", y).attr("x2", width).attr("y2", y);
|
|
48774
|
+
}
|
|
48775
|
+
}
|
|
48776
|
+
if (layout.coastlineStyle) {
|
|
48777
|
+
const cs = layout.coastlineStyle;
|
|
48778
|
+
const maskId = "dgmo-map-water-mask";
|
|
48779
|
+
const mask = defs.append("mask").attr("id", maskId).attr("maskUnits", "userSpaceOnUse").attr("x", 0).attr("y", 0).attr("width", width).attr("height", height);
|
|
48780
|
+
mask.append("rect").attr("x", 0).attr("y", 0).attr("width", width).attr("height", height).attr("fill", "white");
|
|
48781
|
+
const landD = layout.regions.filter((r) => r.id !== "lake").map((r) => r.d).join(" ");
|
|
48782
|
+
const lakeD = layout.regions.filter((r) => r.id === "lake").map((r) => r.d).join(" ");
|
|
48783
|
+
if (landD) mask.append("path").attr("d", landD).attr("fill", "black");
|
|
48784
|
+
if (lakeD) mask.append("path").attr("d", lakeD).attr("fill", "white");
|
|
48785
|
+
if (layout.insets.length) {
|
|
48786
|
+
const reach = Math.max(0, ...cs.lines.map((l) => l.d + l.thickness));
|
|
48787
|
+
for (const box of layout.insets) {
|
|
48788
|
+
const d = box.points.map((p, i) => `${i ? "L" : "M"}${p[0]},${p[1]}`).join("") + "Z";
|
|
48789
|
+
mask.append("path").attr("d", d).attr("fill", "black").attr("stroke", "black").attr("stroke-width", 2 * reach).attr("stroke-linejoin", "round");
|
|
48790
|
+
}
|
|
48791
|
+
}
|
|
48792
|
+
const gWater = svg.append("g").attr("class", "dgmo-map-water-lines").attr("fill", "none").attr("mask", `url(#${maskId})`);
|
|
48793
|
+
appendWaterLines(
|
|
48794
|
+
gWater,
|
|
48795
|
+
coastlineOuterRings(layout.regions, cs.minExtent),
|
|
48796
|
+
cs,
|
|
48797
|
+
layout.background
|
|
48798
|
+
);
|
|
48799
|
+
const byStroke = /* @__PURE__ */ new Map();
|
|
48800
|
+
for (const r of layout.regions) {
|
|
48801
|
+
const arr = byStroke.get(r.stroke);
|
|
48802
|
+
if (arr) arr.push(r.d);
|
|
48803
|
+
else byStroke.set(r.stroke, [r.d]);
|
|
48804
|
+
}
|
|
48805
|
+
for (const [stroke2, ds] of byStroke)
|
|
48806
|
+
gWater.append("path").attr("d", ds.join(" ")).attr("stroke", stroke2).attr("stroke-width", 0.5).attr("stroke-linejoin", "round");
|
|
48807
|
+
}
|
|
47379
48808
|
if (layout.rivers.length) {
|
|
47380
48809
|
const gRivers = svg.append("g").attr("class", "dgmo-map-rivers").attr("fill", "none");
|
|
47381
48810
|
for (const r of layout.rivers) {
|
|
@@ -47384,15 +48813,61 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47384
48813
|
}
|
|
47385
48814
|
if (layout.insets.length) {
|
|
47386
48815
|
const insetG = svg.append("g").attr("class", "dgmo-map-insets");
|
|
47387
|
-
|
|
48816
|
+
layout.insets.forEach((box, bi) => {
|
|
47388
48817
|
const d = box.points.map((p, i) => `${i ? "L" : "M"}${p[0]},${p[1]}`).join("") + "Z";
|
|
47389
48818
|
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");
|
|
47390
|
-
|
|
48819
|
+
if (box.contextLand) {
|
|
48820
|
+
const clipId = `dgmo-map-inset-clip-${bi}`;
|
|
48821
|
+
defs.append("clipPath").attr("id", clipId).append("path").attr("d", d);
|
|
48822
|
+
insetG.append("path").attr("d", box.contextLand.d).attr("fill", box.contextLand.fill).attr("clip-path", `url(#${clipId})`);
|
|
48823
|
+
}
|
|
48824
|
+
});
|
|
47391
48825
|
for (const r of layout.insetRegions) drawRegion(insetG, r, 0.5);
|
|
47392
|
-
|
|
48826
|
+
if (layout.coastlineStyle) {
|
|
48827
|
+
const cs = layout.coastlineStyle;
|
|
48828
|
+
const maskId = "dgmo-map-inset-water-mask";
|
|
48829
|
+
const mask = defs.append("mask").attr("id", maskId).attr("maskUnits", "userSpaceOnUse").attr("x", 0).attr("y", 0).attr("width", width).attr("height", height);
|
|
48830
|
+
for (const box of layout.insets) {
|
|
48831
|
+
const d = box.points.map((p, i) => `${i ? "L" : "M"}${p[0]},${p[1]}`).join("") + "Z";
|
|
48832
|
+
mask.append("path").attr("d", d).attr("fill", "white");
|
|
48833
|
+
}
|
|
48834
|
+
layout.insets.forEach((box, bi) => {
|
|
48835
|
+
if (box.contextLand)
|
|
48836
|
+
mask.append("path").attr("d", box.contextLand.d).attr("fill", "black").attr("clip-path", `url(#dgmo-map-inset-clip-${bi})`);
|
|
48837
|
+
});
|
|
48838
|
+
for (const r of layout.insetRegions)
|
|
48839
|
+
if (r.id !== "lake")
|
|
48840
|
+
mask.append("path").attr("d", r.d).attr("fill", "black");
|
|
48841
|
+
for (const r of layout.insetRegions)
|
|
48842
|
+
if (r.id === "lake")
|
|
48843
|
+
mask.append("path").attr("d", r.d).attr("fill", "white");
|
|
48844
|
+
const clipId = "dgmo-map-inset-water-clip";
|
|
48845
|
+
const clip = defs.append("clipPath").attr("id", clipId);
|
|
48846
|
+
for (const box of layout.insets) {
|
|
48847
|
+
const d = box.points.map((p, i) => `${i ? "L" : "M"}${p[0]},${p[1]}`).join("") + "Z";
|
|
48848
|
+
clip.append("path").attr("d", d);
|
|
48849
|
+
}
|
|
48850
|
+
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})`);
|
|
48851
|
+
appendWaterLines(
|
|
48852
|
+
gInsetWater,
|
|
48853
|
+
coastlineOuterRings(layout.insetRegions, cs.minExtent),
|
|
48854
|
+
cs,
|
|
48855
|
+
layout.background
|
|
48856
|
+
);
|
|
48857
|
+
for (const r of layout.insetRegions)
|
|
48858
|
+
gInsetWater.append("path").attr("d", r.d).attr("stroke", r.stroke).attr("stroke-width", 0.5).attr("stroke-linejoin", "round");
|
|
48859
|
+
}
|
|
48860
|
+
}
|
|
48861
|
+
const wireSync = (sel, lineNumber) => {
|
|
48862
|
+
if (lineNumber < 1) return;
|
|
48863
|
+
sel.attr("data-line-number", lineNumber);
|
|
48864
|
+
if (onClickItem)
|
|
48865
|
+
sel.style("cursor", "pointer").on("click", () => onClickItem(lineNumber));
|
|
48866
|
+
};
|
|
47393
48867
|
const gLegs = svg.append("g").attr("class", "dgmo-map-legs").attr("fill", "none");
|
|
47394
48868
|
layout.legs.forEach((leg, i) => {
|
|
47395
48869
|
const p = gLegs.append("path").attr("d", leg.d).attr("stroke", leg.color).attr("stroke-width", leg.width).attr("stroke-linecap", "round");
|
|
48870
|
+
wireSync(p, leg.lineNumber);
|
|
47396
48871
|
if (leg.arrow) {
|
|
47397
48872
|
const id = `dgmo-map-arrow-${i}`;
|
|
47398
48873
|
const s = arrowSize(leg.width);
|
|
@@ -47400,25 +48875,38 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47400
48875
|
p.attr("marker-end", `url(#${id})`);
|
|
47401
48876
|
}
|
|
47402
48877
|
if (leg.label !== void 0 && leg.labelX !== void 0) {
|
|
47403
|
-
emitText(
|
|
48878
|
+
const lt = emitText(
|
|
47404
48879
|
gLegs,
|
|
47405
48880
|
leg.labelX,
|
|
47406
48881
|
leg.labelY ?? 0,
|
|
47407
48882
|
leg.label,
|
|
47408
48883
|
"middle",
|
|
47409
|
-
palette.textMuted,
|
|
47410
|
-
haloColor,
|
|
47411
|
-
true,
|
|
48884
|
+
leg.labelColor ?? palette.textMuted,
|
|
48885
|
+
leg.labelHaloColor ?? haloColor,
|
|
48886
|
+
leg.labelHalo ?? true,
|
|
47412
48887
|
LABEL_FONT - 1
|
|
47413
48888
|
);
|
|
48889
|
+
wireSync(lt, leg.lineNumber);
|
|
47414
48890
|
}
|
|
47415
48891
|
});
|
|
48892
|
+
const gSpider = svg.append("g").attr("class", "dgmo-map-spider");
|
|
48893
|
+
for (const cl of layout.clusters) {
|
|
48894
|
+
if (!exportDims) {
|
|
48895
|
+
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");
|
|
48896
|
+
}
|
|
48897
|
+
for (const leg of cl.legs) {
|
|
48898
|
+
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");
|
|
48899
|
+
}
|
|
48900
|
+
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");
|
|
48901
|
+
}
|
|
47416
48902
|
const gPois = svg.append("g").attr("class", "dgmo-map-pois");
|
|
47417
48903
|
for (const poi of layout.pois) {
|
|
47418
48904
|
if (poi.isOrigin) {
|
|
47419
48905
|
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);
|
|
47420
48906
|
}
|
|
47421
48907
|
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);
|
|
48908
|
+
if (poi.clusterId !== void 0)
|
|
48909
|
+
c.attr("data-cluster-member", poi.clusterId);
|
|
47422
48910
|
if (poi.tags) {
|
|
47423
48911
|
for (const [group, value] of Object.entries(poi.tags)) {
|
|
47424
48912
|
c.attr(`data-tag-${group.toLowerCase()}`, value.toLowerCase());
|
|
@@ -47446,12 +48934,32 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47446
48934
|
}
|
|
47447
48935
|
const gLabels = svg.append("g").attr("class", "dgmo-map-labels");
|
|
47448
48936
|
for (const lab of layout.labels) {
|
|
48937
|
+
if (lab.hidden) {
|
|
48938
|
+
if (exportDims) continue;
|
|
48939
|
+
emitText(
|
|
48940
|
+
gLabels,
|
|
48941
|
+
lab.x,
|
|
48942
|
+
lab.y,
|
|
48943
|
+
lab.text,
|
|
48944
|
+
lab.anchor,
|
|
48945
|
+
lab.color,
|
|
48946
|
+
lab.haloColor,
|
|
48947
|
+
lab.halo,
|
|
48948
|
+
LABEL_FONT,
|
|
48949
|
+
lab.italic,
|
|
48950
|
+
lab.letterSpacing
|
|
48951
|
+
).attr("data-poi", lab.poiId ?? null).attr("data-poi-hidden", "").style("opacity", 0).style("pointer-events", "none");
|
|
48952
|
+
continue;
|
|
48953
|
+
}
|
|
47449
48954
|
if (lab.leader) {
|
|
47450
48955
|
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(
|
|
47451
48956
|
"stroke",
|
|
47452
48957
|
lab.leaderColor ?? mix(palette.textMuted, palette.bg, 60)
|
|
47453
48958
|
).attr("stroke-width", lab.leaderColor ? 1 : 0.75);
|
|
47454
48959
|
if (lab.poiId !== void 0) line12.attr("data-poi", lab.poiId);
|
|
48960
|
+
if (lab.clusterMember !== void 0)
|
|
48961
|
+
line12.attr("data-cluster-member", lab.clusterMember);
|
|
48962
|
+
wireSync(line12, lab.lineNumber);
|
|
47455
48963
|
}
|
|
47456
48964
|
const t = emitText(
|
|
47457
48965
|
gLabels,
|
|
@@ -47462,11 +48970,38 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47462
48970
|
lab.color,
|
|
47463
48971
|
lab.haloColor,
|
|
47464
48972
|
lab.halo,
|
|
47465
|
-
LABEL_FONT
|
|
48973
|
+
LABEL_FONT,
|
|
48974
|
+
lab.italic,
|
|
48975
|
+
lab.letterSpacing,
|
|
48976
|
+
lab.lines
|
|
47466
48977
|
);
|
|
47467
48978
|
if (lab.poiId !== void 0) {
|
|
47468
48979
|
t.attr("data-poi", lab.poiId).style("cursor", "default");
|
|
47469
48980
|
}
|
|
48981
|
+
if (lab.clusterMember !== void 0) {
|
|
48982
|
+
t.attr("data-cluster-member", lab.clusterMember);
|
|
48983
|
+
}
|
|
48984
|
+
wireSync(t, lab.lineNumber);
|
|
48985
|
+
}
|
|
48986
|
+
if (!exportDims && layout.clusters.length) {
|
|
48987
|
+
const gBadge = svg.append("g").attr("class", "dgmo-map-cluster-badges");
|
|
48988
|
+
for (const cl of layout.clusters) {
|
|
48989
|
+
const g = gBadge.append("g").attr("data-cluster", cl.id).style("opacity", 0).style("pointer-events", "none");
|
|
48990
|
+
const R = 9;
|
|
48991
|
+
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);
|
|
48992
|
+
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);
|
|
48993
|
+
emitText(
|
|
48994
|
+
g,
|
|
48995
|
+
cl.cx,
|
|
48996
|
+
cl.cy + 3,
|
|
48997
|
+
String(cl.count),
|
|
48998
|
+
"middle",
|
|
48999
|
+
palette.text,
|
|
49000
|
+
palette.bg,
|
|
49001
|
+
false,
|
|
49002
|
+
LABEL_FONT
|
|
49003
|
+
);
|
|
49004
|
+
}
|
|
47470
49005
|
}
|
|
47471
49006
|
if (layout.legend) {
|
|
47472
49007
|
const legendY = (layout.title ? TITLE_Y + TITLE_FONT_SIZE : 0) + (layout.subtitle ? TITLE_FONT_SIZE : 0) + 8;
|
|
@@ -47500,10 +49035,10 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47500
49035
|
}
|
|
47501
49036
|
}
|
|
47502
49037
|
if (layout.title) {
|
|
47503
|
-
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);
|
|
49038
|
+
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);
|
|
47504
49039
|
}
|
|
47505
49040
|
if (layout.subtitle) {
|
|
47506
|
-
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);
|
|
49041
|
+
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);
|
|
47507
49042
|
}
|
|
47508
49043
|
if (layout.caption) {
|
|
47509
49044
|
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);
|
|
@@ -47512,10 +49047,21 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47512
49047
|
function renderMapForExport(container, resolved, data, palette, isDark, exportDims) {
|
|
47513
49048
|
renderMap(container, resolved, data, palette, isDark, void 0, exportDims);
|
|
47514
49049
|
}
|
|
47515
|
-
function emitText(g, x, y, text, anchor, color, halo, withHalo, fontSize) {
|
|
47516
|
-
const t = g.append("text").attr("x", x).attr("y", y).attr("text-anchor", anchor).attr("font-size", fontSize).attr("fill", color)
|
|
49050
|
+
function emitText(g, x, y, text, anchor, color, halo, withHalo, fontSize, italic, letterSpacing, lines) {
|
|
49051
|
+
const t = g.append("text").attr("x", x).attr("y", y).attr("text-anchor", anchor).attr("font-size", fontSize).attr("fill", color);
|
|
49052
|
+
if (lines && lines.length > 1) {
|
|
49053
|
+
const lineHeight = fontSize + 2;
|
|
49054
|
+
const startDy = -((lines.length - 1) / 2) * lineHeight;
|
|
49055
|
+
lines.forEach((ln, i) => {
|
|
49056
|
+
t.append("tspan").attr("x", x).attr("dy", i === 0 ? startDy : lineHeight).text(ln);
|
|
49057
|
+
});
|
|
49058
|
+
} else {
|
|
49059
|
+
t.text(text);
|
|
49060
|
+
}
|
|
49061
|
+
if (italic) t.attr("font-style", "italic");
|
|
49062
|
+
if (letterSpacing) t.attr("letter-spacing", letterSpacing);
|
|
47517
49063
|
if (withHalo) {
|
|
47518
|
-
t.attr("paint-order", "stroke fill").attr("stroke", halo).attr("stroke-width",
|
|
49064
|
+
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);
|
|
47519
49065
|
}
|
|
47520
49066
|
return t;
|
|
47521
49067
|
}
|
|
@@ -47532,6 +49078,178 @@ var init_renderer16 = __esm({
|
|
|
47532
49078
|
}
|
|
47533
49079
|
});
|
|
47534
49080
|
|
|
49081
|
+
// src/map/dimensions.ts
|
|
49082
|
+
var dimensions_exports = {};
|
|
49083
|
+
__export(dimensions_exports, {
|
|
49084
|
+
mapContentAspect: () => mapContentAspect,
|
|
49085
|
+
mapExportDimensions: () => mapExportDimensions
|
|
49086
|
+
});
|
|
49087
|
+
import { geoPath as geoPath2 } from "d3-geo";
|
|
49088
|
+
function mapContentAspect(resolved, data, ref = REF) {
|
|
49089
|
+
const { projection, fitTarget } = buildMapProjection(resolved, data);
|
|
49090
|
+
projection.fitSize([ref, ref], fitTarget);
|
|
49091
|
+
const b = geoPath2(projection).bounds(fitTarget);
|
|
49092
|
+
const w = b[1][0] - b[0][0];
|
|
49093
|
+
const h = b[1][1] - b[0][1];
|
|
49094
|
+
const aspect = w / h;
|
|
49095
|
+
return Number.isFinite(aspect) && aspect > 0 ? aspect : FALLBACK_ASPECT;
|
|
49096
|
+
}
|
|
49097
|
+
function mapExportDimensions(resolved, data, baseWidth = 1200) {
|
|
49098
|
+
const raw = mapContentAspect(resolved, data);
|
|
49099
|
+
const clamped = Math.max(ASPECT_MIN, Math.min(ASPECT_MAX, raw));
|
|
49100
|
+
const width = baseWidth;
|
|
49101
|
+
let height = Math.round(width / clamped);
|
|
49102
|
+
let chromeReserve = 0;
|
|
49103
|
+
if (resolved.title && resolved.pois.length > 0) {
|
|
49104
|
+
const bannerBottom = (resolved.subtitle ? TITLE_Y + TITLE_FONT_SIZE : TITLE_Y) + TITLE_FONT_SIZE / 2;
|
|
49105
|
+
chromeReserve += Math.max(FIT_PAD2, bannerBottom + TITLE_GAP) - FIT_PAD2;
|
|
49106
|
+
}
|
|
49107
|
+
let floored = false;
|
|
49108
|
+
if (height - chromeReserve < MIN_MAP_BAND) {
|
|
49109
|
+
height = Math.round(chromeReserve + MIN_MAP_BAND);
|
|
49110
|
+
floored = true;
|
|
49111
|
+
}
|
|
49112
|
+
const preferContain = clamped !== raw || floored;
|
|
49113
|
+
return { width, height, preferContain };
|
|
49114
|
+
}
|
|
49115
|
+
var FIT_PAD2, TITLE_GAP, ASPECT_MAX, ASPECT_MIN, MIN_MAP_BAND, FALLBACK_ASPECT, REF;
|
|
49116
|
+
var init_dimensions = __esm({
|
|
49117
|
+
"src/map/dimensions.ts"() {
|
|
49118
|
+
"use strict";
|
|
49119
|
+
init_title_constants();
|
|
49120
|
+
init_layout15();
|
|
49121
|
+
FIT_PAD2 = 24;
|
|
49122
|
+
TITLE_GAP = 16;
|
|
49123
|
+
ASPECT_MAX = 3;
|
|
49124
|
+
ASPECT_MIN = 0.9;
|
|
49125
|
+
MIN_MAP_BAND = 200;
|
|
49126
|
+
FALLBACK_ASPECT = 1.5;
|
|
49127
|
+
REF = 1e3;
|
|
49128
|
+
}
|
|
49129
|
+
});
|
|
49130
|
+
|
|
49131
|
+
// src/map/load-data.ts
|
|
49132
|
+
var load_data_exports = {};
|
|
49133
|
+
__export(load_data_exports, {
|
|
49134
|
+
loadMapData: () => loadMapData
|
|
49135
|
+
});
|
|
49136
|
+
async function loadNodeBuiltins() {
|
|
49137
|
+
const [{ readFile }, { fileURLToPath }, { dirname, resolve }] = await Promise.all([
|
|
49138
|
+
import("fs/promises"),
|
|
49139
|
+
import("url"),
|
|
49140
|
+
import("path")
|
|
49141
|
+
]);
|
|
49142
|
+
return { readFile, fileURLToPath, dirname, resolve };
|
|
49143
|
+
}
|
|
49144
|
+
async function readJson(nb, dir, name) {
|
|
49145
|
+
return JSON.parse(await nb.readFile(nb.resolve(dir, name), "utf8"));
|
|
49146
|
+
}
|
|
49147
|
+
async function firstExistingDir(nb, baseDir) {
|
|
49148
|
+
for (const rel of CANDIDATE_DIRS) {
|
|
49149
|
+
const dir = nb.resolve(baseDir, rel);
|
|
49150
|
+
try {
|
|
49151
|
+
await nb.readFile(nb.resolve(dir, FILES.gazetteer), "utf8");
|
|
49152
|
+
return dir;
|
|
49153
|
+
} catch {
|
|
49154
|
+
}
|
|
49155
|
+
}
|
|
49156
|
+
throw new Error(
|
|
49157
|
+
`map data assets not found near ${baseDir} (looked in ${CANDIDATE_DIRS.join(", ")}). Run \`pnpm build:map-data\` and \`pnpm build\`.`
|
|
49158
|
+
);
|
|
49159
|
+
}
|
|
49160
|
+
function validate(data) {
|
|
49161
|
+
const topoOk = (t) => !!t && t.type === "Topology" && !!t.objects;
|
|
49162
|
+
if (!topoOk(data.worldCoarse) || !topoOk(data.worldDetail) || !topoOk(data.usStates) || !data.gazetteer || !Array.isArray(data.gazetteer.cities) || !data.gazetteer.byName) {
|
|
49163
|
+
throw new Error("map data assets are malformed (failed shape validation)");
|
|
49164
|
+
}
|
|
49165
|
+
return data;
|
|
49166
|
+
}
|
|
49167
|
+
function moduleBaseDir(nb) {
|
|
49168
|
+
try {
|
|
49169
|
+
const url = import.meta.url;
|
|
49170
|
+
if (url) return nb.dirname(nb.fileURLToPath(url));
|
|
49171
|
+
} catch {
|
|
49172
|
+
}
|
|
49173
|
+
if (typeof __dirname !== "undefined") return __dirname;
|
|
49174
|
+
return process.cwd();
|
|
49175
|
+
}
|
|
49176
|
+
function loadMapData() {
|
|
49177
|
+
cache ??= (async () => {
|
|
49178
|
+
const nb = await loadNodeBuiltins();
|
|
49179
|
+
const dir = await firstExistingDir(nb, moduleBaseDir(nb));
|
|
49180
|
+
const [
|
|
49181
|
+
worldCoarse,
|
|
49182
|
+
worldDetail,
|
|
49183
|
+
usStates,
|
|
49184
|
+
lakes,
|
|
49185
|
+
rivers,
|
|
49186
|
+
mountainRanges,
|
|
49187
|
+
naLand,
|
|
49188
|
+
naLakes,
|
|
49189
|
+
waterBodies,
|
|
49190
|
+
gazetteer
|
|
49191
|
+
] = await Promise.all([
|
|
49192
|
+
// worldCoarse (110m) is LOAD-BEARING but NOT a render source: the world
|
|
49193
|
+
// basemap renders from worldDetail (50m) at all scales (resolver pins
|
|
49194
|
+
// basemaps.world = 'detail'). Coarse stays as the authoritative region
|
|
49195
|
+
// name index + dominant-landmass bbox source in resolver.ts. Do not drop it.
|
|
49196
|
+
readJson(nb, dir, FILES.worldCoarse),
|
|
49197
|
+
readJson(nb, dir, FILES.worldDetail),
|
|
49198
|
+
readJson(nb, dir, FILES.usStates),
|
|
49199
|
+
// Lakes/rivers/mountain/NA/water assets are optional — older bundles may predate them.
|
|
49200
|
+
readJson(nb, dir, FILES.lakes).catch(() => void 0),
|
|
49201
|
+
readJson(nb, dir, FILES.rivers).catch(() => void 0),
|
|
49202
|
+
readJson(nb, dir, FILES.mountainRanges).catch(
|
|
49203
|
+
() => void 0
|
|
49204
|
+
),
|
|
49205
|
+
readJson(nb, dir, FILES.naLand).catch(() => void 0),
|
|
49206
|
+
readJson(nb, dir, FILES.naLakes).catch(() => void 0),
|
|
49207
|
+
readJson(nb, dir, FILES.waterBodies).catch(() => void 0),
|
|
49208
|
+
readJson(nb, dir, FILES.gazetteer)
|
|
49209
|
+
]);
|
|
49210
|
+
return validate({
|
|
49211
|
+
worldCoarse,
|
|
49212
|
+
worldDetail,
|
|
49213
|
+
usStates,
|
|
49214
|
+
gazetteer,
|
|
49215
|
+
...lakes && { lakes },
|
|
49216
|
+
...rivers && { rivers },
|
|
49217
|
+
...mountainRanges && { mountainRanges },
|
|
49218
|
+
...naLand && { naLand },
|
|
49219
|
+
...naLakes && { naLakes },
|
|
49220
|
+
...waterBodies && { waterBodies }
|
|
49221
|
+
});
|
|
49222
|
+
})().catch((e) => {
|
|
49223
|
+
cache = void 0;
|
|
49224
|
+
throw e;
|
|
49225
|
+
});
|
|
49226
|
+
return cache;
|
|
49227
|
+
}
|
|
49228
|
+
var FILES, CANDIDATE_DIRS, cache;
|
|
49229
|
+
var init_load_data = __esm({
|
|
49230
|
+
"src/map/load-data.ts"() {
|
|
49231
|
+
"use strict";
|
|
49232
|
+
FILES = {
|
|
49233
|
+
worldCoarse: "world-coarse.json",
|
|
49234
|
+
worldDetail: "world-detail.json",
|
|
49235
|
+
usStates: "us-states.json",
|
|
49236
|
+
lakes: "lakes.json",
|
|
49237
|
+
rivers: "rivers.json",
|
|
49238
|
+
mountainRanges: "mountain-ranges.json",
|
|
49239
|
+
naLand: "na-land.json",
|
|
49240
|
+
naLakes: "na-lakes.json",
|
|
49241
|
+
waterBodies: "water-bodies.json",
|
|
49242
|
+
gazetteer: "gazetteer.json"
|
|
49243
|
+
};
|
|
49244
|
+
CANDIDATE_DIRS = [
|
|
49245
|
+
"./data",
|
|
49246
|
+
"./map-data",
|
|
49247
|
+
"../map-data",
|
|
49248
|
+
"../src/map/data"
|
|
49249
|
+
];
|
|
49250
|
+
}
|
|
49251
|
+
});
|
|
49252
|
+
|
|
47535
49253
|
// src/pyramid/renderer.ts
|
|
47536
49254
|
var renderer_exports17 = {};
|
|
47537
49255
|
__export(renderer_exports17, {
|
|
@@ -49534,8 +51252,8 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
|
|
|
49534
51252
|
const lines = splitParticipantLabel(p.label, LABEL_MAX_CHARS);
|
|
49535
51253
|
if (lines.length === 0) continue;
|
|
49536
51254
|
const widest = Math.max(...lines.map((l) => l.length));
|
|
49537
|
-
const
|
|
49538
|
-
uniformBoxWidth = Math.max(uniformBoxWidth,
|
|
51255
|
+
const labelWidth2 = widest * LABEL_CHAR_WIDTH + 10;
|
|
51256
|
+
uniformBoxWidth = Math.max(uniformBoxWidth, labelWidth2);
|
|
49539
51257
|
}
|
|
49540
51258
|
uniformBoxWidth = Math.min(MAX_BOX_WIDTH, uniformBoxWidth);
|
|
49541
51259
|
const effectiveGap = Math.max(PARTICIPANT_GAP, uniformBoxWidth + 30);
|
|
@@ -52234,15 +53952,15 @@ function renderArcDiagram(container, parsed, palette, _isDark, onClickItem, expo
|
|
|
52234
53952
|
textColor,
|
|
52235
53953
|
onClickItem
|
|
52236
53954
|
);
|
|
52237
|
-
const
|
|
52238
|
-
for (const node of nodes)
|
|
53955
|
+
const neighbors2 = /* @__PURE__ */ new Map();
|
|
53956
|
+
for (const node of nodes) neighbors2.set(node, /* @__PURE__ */ new Set());
|
|
52239
53957
|
for (const link of links) {
|
|
52240
|
-
|
|
52241
|
-
|
|
53958
|
+
neighbors2.get(link.source).add(link.target);
|
|
53959
|
+
neighbors2.get(link.target).add(link.source);
|
|
52242
53960
|
}
|
|
52243
53961
|
const FADE_OPACITY3 = 0.1;
|
|
52244
53962
|
function handleMouseEnter(hovered) {
|
|
52245
|
-
const connected =
|
|
53963
|
+
const connected = neighbors2.get(hovered);
|
|
52246
53964
|
g.selectAll(".arc-link").each(function() {
|
|
52247
53965
|
const el = d3Selection23.select(this);
|
|
52248
53966
|
const src = el.attr("data-source");
|
|
@@ -54177,7 +55895,7 @@ function renderVenn(container, parsed, palette, _isDark, onClickItem, exportDims
|
|
|
54177
55895
|
8,
|
|
54178
55896
|
Math.floor(OVERLAP_WRAP_TARGET_W / OVERLAP_CH_W)
|
|
54179
55897
|
);
|
|
54180
|
-
function
|
|
55898
|
+
function wrapLabel3(text, maxChars) {
|
|
54181
55899
|
const words = text.split(/\s+/).filter(Boolean);
|
|
54182
55900
|
const lines = [];
|
|
54183
55901
|
let cur = "";
|
|
@@ -54223,7 +55941,7 @@ function renderVenn(container, parsed, palette, _isDark, onClickItem, exportDims
|
|
|
54223
55941
|
if (!ov.label) continue;
|
|
54224
55942
|
const idxs = ov.sets.map((s) => vennSets.findIndex((vs) => vs.name === s));
|
|
54225
55943
|
if (idxs.some((idx) => idx < 0)) continue;
|
|
54226
|
-
const lines =
|
|
55944
|
+
const lines = wrapLabel3(ov.label, MAX_WRAP_CHARS);
|
|
54227
55945
|
wrappedOverlapLabels.set(ov, lines);
|
|
54228
55946
|
const dir = predictOverlapDirRaw(idxs);
|
|
54229
55947
|
const longest = lines.reduce((m, l) => Math.max(m, l.length), 0);
|
|
@@ -55660,25 +57378,29 @@ async function renderForExport(content, theme, palette, viewState, options) {
|
|
|
55660
57378
|
if (detectedType === "map") {
|
|
55661
57379
|
const { parseMap: parseMap2 } = await Promise.resolve().then(() => (init_parser12(), parser_exports11));
|
|
55662
57380
|
const { resolveMap: resolveMap2 } = await Promise.resolve().then(() => (init_resolver2(), resolver_exports));
|
|
55663
|
-
const { loadMapData: loadMapData2 } = await Promise.resolve().then(() => (init_load_data(), load_data_exports));
|
|
55664
57381
|
const { renderMapForExport: renderMapForExport2 } = await Promise.resolve().then(() => (init_renderer16(), renderer_exports16));
|
|
57382
|
+
const { mapExportDimensions: mapExportDimensions2 } = await Promise.resolve().then(() => (init_dimensions(), dimensions_exports));
|
|
55665
57383
|
const effectivePalette2 = await resolveExportPalette(theme, palette);
|
|
55666
57384
|
const mapParsed = parseMap2(content);
|
|
55667
|
-
let mapData;
|
|
55668
|
-
|
|
55669
|
-
|
|
55670
|
-
|
|
55671
|
-
|
|
57385
|
+
let mapData = options?.mapData;
|
|
57386
|
+
if (!mapData) {
|
|
57387
|
+
const { loadMapData: loadMapData2 } = await Promise.resolve().then(() => (init_load_data(), load_data_exports));
|
|
57388
|
+
try {
|
|
57389
|
+
mapData = await loadMapData2();
|
|
57390
|
+
} catch {
|
|
57391
|
+
return "";
|
|
57392
|
+
}
|
|
55672
57393
|
}
|
|
55673
57394
|
const mapResolved = resolveMap2(mapParsed, mapData);
|
|
55674
|
-
const
|
|
57395
|
+
const dims2 = mapExportDimensions2(mapResolved, mapData, EXPORT_WIDTH);
|
|
57396
|
+
const container2 = createExportContainer(dims2.width, dims2.height);
|
|
55675
57397
|
renderMapForExport2(
|
|
55676
57398
|
container2,
|
|
55677
57399
|
mapResolved,
|
|
55678
57400
|
mapData,
|
|
55679
57401
|
effectivePalette2,
|
|
55680
57402
|
theme === "dark",
|
|
55681
|
-
|
|
57403
|
+
dims2
|
|
55682
57404
|
);
|
|
55683
57405
|
return finalizeSvgExport(container2, theme, effectivePalette2);
|
|
55684
57406
|
}
|
|
@@ -56520,7 +58242,8 @@ async function render(content, options) {
|
|
|
56520
58242
|
...options?.c4Container !== void 0 && {
|
|
56521
58243
|
c4Container: options.c4Container
|
|
56522
58244
|
},
|
|
56523
|
-
...options?.tagGroup !== void 0 && { tagGroup: options.tagGroup }
|
|
58245
|
+
...options?.tagGroup !== void 0 && { tagGroup: options.tagGroup },
|
|
58246
|
+
...options?.mapData !== void 0 && { mapData: options.mapData }
|
|
56524
58247
|
});
|
|
56525
58248
|
if (chartType === "map") {
|
|
56526
58249
|
try {
|
|
@@ -56531,7 +58254,7 @@ async function render(content, options) {
|
|
|
56531
58254
|
Promise.resolve().then(() => (init_load_data(), load_data_exports))
|
|
56532
58255
|
]
|
|
56533
58256
|
);
|
|
56534
|
-
const data = await loadMapData2();
|
|
58257
|
+
const data = options?.mapData ?? await loadMapData2();
|
|
56535
58258
|
diagnostics = [...resolveMap2(parseMap2(content), data).diagnostics];
|
|
56536
58259
|
} catch {
|
|
56537
58260
|
}
|