@diagrammo/dgmo 0.21.1 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -6
- package/dist/advanced.cjs +2003 -466
- package/dist/advanced.d.cts +5714 -0
- package/dist/advanced.d.ts +5714 -0
- package/dist/advanced.js +1999 -466
- package/dist/auto.cjs +2048 -449
- package/dist/auto.d.cts +39 -0
- package/dist/auto.d.ts +39 -0
- package/dist/auto.js +121 -121
- package/dist/auto.mjs +2050 -450
- package/dist/cli.cjs +170 -170
- package/dist/editor.cjs +13 -16
- package/dist/editor.js +13 -16
- package/dist/highlight.cjs +15 -13
- package/dist/highlight.js +15 -13
- package/dist/index.cjs +2032 -435
- package/dist/index.d.cts +339 -0
- package/dist/index.d.ts +339 -0
- package/dist/index.js +2034 -436
- package/dist/internal.cjs +2003 -466
- package/dist/internal.d.cts +5714 -0
- package/dist/internal.d.ts +5714 -0
- package/dist/internal.js +1999 -466
- package/dist/map-data/water-bodies.json +1 -0
- package/docs/language-reference.md +20 -9
- package/gallery/fixtures/map-categorical-world.dgmo +16 -0
- package/gallery/fixtures/map-categorical.dgmo +0 -1
- package/gallery/fixtures/map-choropleth.dgmo +0 -1
- package/gallery/fixtures/map-coastline.dgmo +7 -0
- package/gallery/fixtures/map-colorize.dgmo +11 -0
- package/gallery/fixtures/map-direct-color.dgmo +0 -1
- package/gallery/fixtures/map-reference-world.dgmo +11 -0
- package/gallery/fixtures/map-region-scope.dgmo +0 -3
- package/gallery/fixtures/map-route.dgmo +0 -1
- package/package.json +1 -1
- package/src/advanced.ts +12 -1
- package/src/boxes-and-lines/renderer.ts +39 -12
- package/src/cli.ts +1 -1
- package/src/completion.ts +32 -25
- package/src/cycle/renderer.ts +14 -1
- package/src/d3.ts +8 -2
- package/src/editor/highlight-api.ts +4 -0
- package/src/editor/keywords.ts +13 -16
- package/src/infra/renderer.ts +35 -7
- package/src/map/colorize.ts +54 -0
- package/src/map/context-labels.ts +429 -0
- package/src/map/data/types.ts +34 -0
- package/src/map/data/water-bodies.json +1 -0
- package/src/map/dimensions.ts +117 -0
- package/src/map/geo-query.ts +21 -3
- package/src/map/geo.ts +47 -1
- package/src/map/layout.ts +1300 -251
- package/src/map/load-data.ts +10 -2
- package/src/map/parser.ts +42 -116
- package/src/map/renderer.ts +512 -13
- package/src/map/resolved-types.ts +16 -2
- package/src/map/resolver.ts +208 -59
- package/src/map/types.ts +30 -32
- package/src/mindmap/renderer.ts +10 -1
- package/src/palettes/atlas.ts +77 -0
- package/src/palettes/blueprint.ts +73 -0
- package/src/palettes/color-utils.ts +58 -1
- package/src/palettes/index.ts +12 -3
- package/src/palettes/slate.ts +73 -0
- package/src/palettes/tidewater.ts +73 -0
- package/src/render.ts +8 -1
- package/src/tech-radar/renderer.ts +3 -0
- package/src/tech-radar/types.ts +3 -0
- package/src/utils/d3-types.ts +5 -0
- package/src/utils/legend-layout.ts +21 -4
- package/src/utils/legend-types.ts +7 -0
- package/src/utils/reserved-key-registry.ts +3 -0
- package/src/palettes/bold.ts +0 -67
package/dist/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,24 +16380,6 @@ 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
16383
|
case "region-metric": {
|
|
15970
16384
|
dup(d.regionMetric);
|
|
15971
16385
|
const { label: rmLabel, colorName: rmColor } = peelTrailingColorName(value);
|
|
@@ -15981,91 +16395,43 @@ function parseMap(content) {
|
|
|
15981
16395
|
dup(d.flowMetric);
|
|
15982
16396
|
d.flowMetric = value;
|
|
15983
16397
|
break;
|
|
15984
|
-
case "
|
|
15985
|
-
dup(d.
|
|
15986
|
-
|
|
15987
|
-
const s = parseScale(value, line12);
|
|
15988
|
-
if (s) d.scale = s;
|
|
15989
|
-
}
|
|
15990
|
-
break;
|
|
15991
|
-
case "region-labels":
|
|
15992
|
-
dup(d.regionLabels);
|
|
15993
|
-
if (value && !["full", "abbrev", "off"].includes(value))
|
|
15994
|
-
pushWarning(
|
|
15995
|
-
line12,
|
|
15996
|
-
`Unknown region-labels "${value}" (expected full | abbrev | off).`
|
|
15997
|
-
);
|
|
15998
|
-
d.regionLabels = value;
|
|
15999
|
-
break;
|
|
16000
|
-
case "poi-labels":
|
|
16001
|
-
dup(d.poiLabels);
|
|
16002
|
-
if (value && !["off", "auto", "all"].includes(value))
|
|
16003
|
-
pushWarning(
|
|
16004
|
-
line12,
|
|
16005
|
-
`Unknown poi-labels "${value}" (expected off | auto | all).`
|
|
16006
|
-
);
|
|
16007
|
-
d.poiLabels = value;
|
|
16008
|
-
break;
|
|
16009
|
-
case "default-country":
|
|
16010
|
-
dup(d.defaultCountry);
|
|
16011
|
-
d.defaultCountry = value;
|
|
16012
|
-
break;
|
|
16013
|
-
case "default-state":
|
|
16014
|
-
dup(d.defaultState);
|
|
16015
|
-
d.defaultState = value;
|
|
16398
|
+
case "locale":
|
|
16399
|
+
dup(d.locale);
|
|
16400
|
+
d.locale = value;
|
|
16016
16401
|
break;
|
|
16017
16402
|
case "active-tag":
|
|
16018
16403
|
dup(d.activeTag);
|
|
16019
16404
|
d.activeTag = value;
|
|
16020
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. ──
|
|
16021
16412
|
case "no-legend":
|
|
16022
16413
|
d.noLegend = true;
|
|
16023
16414
|
break;
|
|
16024
|
-
case "no-
|
|
16025
|
-
d.
|
|
16415
|
+
case "no-coastline":
|
|
16416
|
+
d.noCoastline = true;
|
|
16026
16417
|
break;
|
|
16027
|
-
case "relief":
|
|
16028
|
-
d.
|
|
16418
|
+
case "no-relief":
|
|
16419
|
+
d.noRelief = true;
|
|
16029
16420
|
break;
|
|
16030
|
-
case "
|
|
16031
|
-
|
|
16032
|
-
if (d.basemapStyle !== void 0 && d.basemapStyle !== key)
|
|
16033
|
-
pushWarning(
|
|
16034
|
-
line12,
|
|
16035
|
-
`Conflicting basemap dress \u2014 "${d.basemapStyle}" then "${key}"; last wins.`
|
|
16036
|
-
);
|
|
16037
|
-
d.basemapStyle = key;
|
|
16421
|
+
case "no-context-labels":
|
|
16422
|
+
d.noContextLabels = true;
|
|
16038
16423
|
break;
|
|
16039
|
-
case "
|
|
16040
|
-
|
|
16041
|
-
d.subtitle = value;
|
|
16424
|
+
case "no-region-labels":
|
|
16425
|
+
d.noRegionLabels = true;
|
|
16042
16426
|
break;
|
|
16043
|
-
case "
|
|
16044
|
-
|
|
16045
|
-
|
|
16427
|
+
case "no-poi-labels":
|
|
16428
|
+
d.noPoiLabels = true;
|
|
16429
|
+
break;
|
|
16430
|
+
case "no-colorize":
|
|
16431
|
+
d.noColorize = true;
|
|
16046
16432
|
break;
|
|
16047
16433
|
}
|
|
16048
16434
|
}
|
|
16049
|
-
function parseScale(value, line12) {
|
|
16050
|
-
const toks = value.split(/\s+/).filter(Boolean);
|
|
16051
|
-
const min = Number(toks[0]);
|
|
16052
|
-
const max = Number(toks[1]);
|
|
16053
|
-
if (!Number.isFinite(min) || !Number.isFinite(max)) {
|
|
16054
|
-
pushError(line12, `scale requires numeric <min> <max> (got "${value}").`);
|
|
16055
|
-
return null;
|
|
16056
|
-
}
|
|
16057
|
-
const scale = { min, max };
|
|
16058
|
-
if (toks[2] === "center") {
|
|
16059
|
-
const c = Number(toks[3]);
|
|
16060
|
-
if (Number.isFinite(c)) scale.center = c;
|
|
16061
|
-
else
|
|
16062
|
-
pushError(
|
|
16063
|
-
line12,
|
|
16064
|
-
`scale center requires a number (got "${toks[3] ?? ""}").`
|
|
16065
|
-
);
|
|
16066
|
-
}
|
|
16067
|
-
return scale;
|
|
16068
|
-
}
|
|
16069
16435
|
function handleTag(trimmed, line12) {
|
|
16070
16436
|
const m = matchTagBlockHeading(trimmed);
|
|
16071
16437
|
if (!m) {
|
|
@@ -16265,13 +16631,15 @@ function parseMap(content) {
|
|
|
16265
16631
|
pushError(line12, `Edge has an empty endpoint: "${trimmed}".`);
|
|
16266
16632
|
continue;
|
|
16267
16633
|
}
|
|
16268
|
-
const
|
|
16634
|
+
const isLast = k === links.length - 1;
|
|
16635
|
+
const meta = isLast ? lastSplit.meta : {};
|
|
16636
|
+
const style = links[k].style === "arc" ? "arc" : "straight";
|
|
16269
16637
|
edges.push({
|
|
16270
16638
|
from,
|
|
16271
16639
|
to,
|
|
16272
16640
|
...links[k].label !== void 0 && { label: links[k].label },
|
|
16273
16641
|
directed: links[k].directed,
|
|
16274
|
-
style
|
|
16642
|
+
style,
|
|
16275
16643
|
meta,
|
|
16276
16644
|
lineNumber: line12
|
|
16277
16645
|
});
|
|
@@ -16357,22 +16725,19 @@ var init_parser12 = __esm({
|
|
|
16357
16725
|
LEG_ARROW_RE = /^(-[^>]*?->|->|~[^>]*?~>|~>|--)\s+(.+)$/;
|
|
16358
16726
|
AT_RE = /(^|[\s,])at\s*:/i;
|
|
16359
16727
|
DIRECTIVE_SET = /* @__PURE__ */ new Set([
|
|
16360
|
-
"region",
|
|
16361
|
-
"projection",
|
|
16362
16728
|
"region-metric",
|
|
16363
16729
|
"poi-metric",
|
|
16364
16730
|
"flow-metric",
|
|
16365
|
-
"
|
|
16366
|
-
"region-labels",
|
|
16367
|
-
"poi-labels",
|
|
16368
|
-
"default-country",
|
|
16369
|
-
"default-state",
|
|
16731
|
+
"locale",
|
|
16370
16732
|
"active-tag",
|
|
16733
|
+
"caption",
|
|
16371
16734
|
"no-legend",
|
|
16372
|
-
"no-
|
|
16373
|
-
"relief",
|
|
16374
|
-
"
|
|
16375
|
-
"
|
|
16735
|
+
"no-coastline",
|
|
16736
|
+
"no-relief",
|
|
16737
|
+
"no-context-labels",
|
|
16738
|
+
"no-region-labels",
|
|
16739
|
+
"no-poi-labels",
|
|
16740
|
+
"no-colorize"
|
|
16376
16741
|
]);
|
|
16377
16742
|
}
|
|
16378
16743
|
});
|
|
@@ -24294,8 +24659,8 @@ function renderKanban(container, parsed, palette, isDark, options) {
|
|
|
24294
24659
|
let metaY = separatorY + sCardSeparatorGap + sCardMetaFontSize;
|
|
24295
24660
|
for (const meta of tagMeta) {
|
|
24296
24661
|
cg.append("text").attr("x", cx + sCardPaddingX).attr("y", metaY).attr("font-size", sCardMetaFontSize).attr("fill", onCardText).text(`${meta.label}: `);
|
|
24297
|
-
const
|
|
24298
|
-
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);
|
|
24299
24664
|
metaY += sCardMetaLineHeight;
|
|
24300
24665
|
}
|
|
24301
24666
|
for (const detail of card.details) {
|
|
@@ -24639,8 +25004,8 @@ function renderSwimlaneCard(parent, cardLayout, tagGroups, activeTagGroup, palet
|
|
|
24639
25004
|
let metaY = separatorY + sCardSeparatorGap + sCardMetaFontSize;
|
|
24640
25005
|
for (const meta of tagMeta) {
|
|
24641
25006
|
cg.append("text").attr("x", cx + sCardPaddingX).attr("y", metaY).attr("font-size", sCardMetaFontSize).attr("fill", palette.textMuted).text(`${meta.label}: `);
|
|
24642
|
-
const
|
|
24643
|
-
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);
|
|
24644
25009
|
metaY += sCardMetaLineHeight;
|
|
24645
25010
|
}
|
|
24646
25011
|
for (const detail of card.details) {
|
|
@@ -25474,8 +25839,8 @@ function classifyEREntities(tables, relationships) {
|
|
|
25474
25839
|
}
|
|
25475
25840
|
}
|
|
25476
25841
|
const mmParticipants = /* @__PURE__ */ new Set();
|
|
25477
|
-
for (const [id,
|
|
25478
|
-
if (
|
|
25842
|
+
for (const [id, neighbors2] of tableStarNeighbors) {
|
|
25843
|
+
if (neighbors2.size >= 2) mmParticipants.add(id);
|
|
25479
25844
|
}
|
|
25480
25845
|
const indegreeValues = Object.values(indegreeMap);
|
|
25481
25846
|
const mean = indegreeValues.reduce((a, b) => a + b, 0) / indegreeValues.length;
|
|
@@ -26148,7 +26513,8 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26148
26513
|
controlsExpanded,
|
|
26149
26514
|
onToggleDescriptions,
|
|
26150
26515
|
onToggleControlsExpand,
|
|
26151
|
-
exportMode = false
|
|
26516
|
+
exportMode = false,
|
|
26517
|
+
controlsHost
|
|
26152
26518
|
} = options ?? {};
|
|
26153
26519
|
d3Selection6.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
26154
26520
|
const width = exportDims?.width ?? container.clientWidth;
|
|
@@ -26166,7 +26532,11 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26166
26532
|
const sGroupLabelZone = sctx.structural(GROUP_LABEL_ZONE);
|
|
26167
26533
|
const sTitleFontSize = sctx.text(TITLE_FONT_SIZE);
|
|
26168
26534
|
const sTitleY = sctx.structural(TITLE_Y);
|
|
26169
|
-
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(
|
|
26170
26540
|
getMaxLegendReservedHeight(
|
|
26171
26541
|
{
|
|
26172
26542
|
groups: parsed.tagGroups,
|
|
@@ -26175,7 +26545,7 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26175
26545
|
},
|
|
26176
26546
|
width
|
|
26177
26547
|
)
|
|
26178
|
-
);
|
|
26548
|
+
) : 0;
|
|
26179
26549
|
const activeGroup = resolveActiveTagGroup(
|
|
26180
26550
|
parsed.tagGroups,
|
|
26181
26551
|
parsed.options["active-tag"],
|
|
@@ -26490,10 +26860,10 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26490
26860
|
const hasDescriptions = parsed.nodes.some(
|
|
26491
26861
|
(n) => n.description && n.description.length > 0
|
|
26492
26862
|
);
|
|
26493
|
-
const hasLegend = parsed.tagGroups.length > 0 || hasDescriptions;
|
|
26863
|
+
const hasLegend = parsed.tagGroups.length > 0 || hasDescriptions && controlsHost !== "app";
|
|
26494
26864
|
if (hasLegend) {
|
|
26495
26865
|
let controlsGroup;
|
|
26496
|
-
if (hasDescriptions && onToggleDescriptions) {
|
|
26866
|
+
if (hasDescriptions && (onToggleDescriptions || controlsHost === "app")) {
|
|
26497
26867
|
controlsGroup = {
|
|
26498
26868
|
toggles: [
|
|
26499
26869
|
{
|
|
@@ -26511,7 +26881,14 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26511
26881
|
groups: parsed.tagGroups,
|
|
26512
26882
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
26513
26883
|
mode: exportMode ? "export" : "preview",
|
|
26514
|
-
|
|
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 }
|
|
26515
26892
|
};
|
|
26516
26893
|
const legendState = {
|
|
26517
26894
|
activeGroup,
|
|
@@ -27758,8 +28135,9 @@ function renderMindmap(container, parsed, layout, palette, isDark, onClickItem,
|
|
|
27758
28135
|
const containerHeight = exportDims?.height ?? (container.getBoundingClientRect().height || 600);
|
|
27759
28136
|
d3Selection7.select(container).selectAll("*").remove();
|
|
27760
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";
|
|
27761
28139
|
const hasControls = !!options?.onToggleColorByDepth || !!options?.onToggleDescriptions;
|
|
27762
|
-
const hasLegend = parsed.tagGroups.length > 0 || hasControls;
|
|
28140
|
+
const hasLegend = parsed.tagGroups.length > 0 || hasControls && !appHosted;
|
|
27763
28141
|
const fixedLegend = !isExport && hasLegend;
|
|
27764
28142
|
const legendReserve = fixedLegend ? getMaxLegendReservedHeight(
|
|
27765
28143
|
{
|
|
@@ -27853,7 +28231,10 @@ function renderMindmap(container, parsed, layout, palette, isDark, onClickItem,
|
|
|
27853
28231
|
}),
|
|
27854
28232
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
27855
28233
|
mode: options?.exportMode ? "export" : "preview",
|
|
27856
|
-
...controlsToggles !== void 0 && { controlsGroup: controlsToggles }
|
|
28234
|
+
...controlsToggles !== void 0 && { controlsGroup: controlsToggles },
|
|
28235
|
+
...options?.controlsHost !== void 0 && {
|
|
28236
|
+
controlsHost: options.controlsHost
|
|
28237
|
+
}
|
|
27857
28238
|
};
|
|
27858
28239
|
const legendState = {
|
|
27859
28240
|
activeGroup: options?.colorByDepth ? null : activeTagGroup !== void 0 ? activeTagGroup : parsed.options["active-tag"] ?? null,
|
|
@@ -28296,8 +28677,8 @@ function computeFieldAlignX(children) {
|
|
|
28296
28677
|
for (const child of children) {
|
|
28297
28678
|
if (child.metadata["_labelField"] === "true" && child.children.length >= 2) {
|
|
28298
28679
|
const labelEl = child.children[0];
|
|
28299
|
-
const
|
|
28300
|
-
maxLabelWidth = Math.max(maxLabelWidth,
|
|
28680
|
+
const labelWidth2 = labelEl.label.length * CHAR_WIDTH5;
|
|
28681
|
+
maxLabelWidth = Math.max(maxLabelWidth, labelWidth2);
|
|
28301
28682
|
labelFieldCount++;
|
|
28302
28683
|
}
|
|
28303
28684
|
}
|
|
@@ -33262,7 +33643,7 @@ function hasRoles(node) {
|
|
|
33262
33643
|
function computeNodeWidth2(node, expanded, options) {
|
|
33263
33644
|
const badgeVal = node.computedConcurrentInvocations === 0 && node.computedInstances > 1 ? node.computedInstances : 0;
|
|
33264
33645
|
const badgeLen = badgeVal > 0 ? `${badgeVal}x`.length + 2 : 0;
|
|
33265
|
-
const
|
|
33646
|
+
const labelWidth2 = (node.label.length + badgeLen) * CHAR_WIDTH7 + PADDING_X3;
|
|
33266
33647
|
const allKeys = [];
|
|
33267
33648
|
if (node.computedRps > 0) allKeys.push("RPS");
|
|
33268
33649
|
if (expanded) {
|
|
@@ -33306,7 +33687,7 @@ function computeNodeWidth2(node, expanded, options) {
|
|
|
33306
33687
|
allKeys.push("overflow");
|
|
33307
33688
|
}
|
|
33308
33689
|
}
|
|
33309
|
-
if (allKeys.length === 0) return Math.max(MIN_NODE_WIDTH2,
|
|
33690
|
+
if (allKeys.length === 0) return Math.max(MIN_NODE_WIDTH2, labelWidth2);
|
|
33310
33691
|
const maxKeyLen = Math.max(...allKeys.map((k) => k.length));
|
|
33311
33692
|
let maxRowWidth = 0;
|
|
33312
33693
|
if (node.computedRps > 0) {
|
|
@@ -33394,7 +33775,7 @@ function computeNodeWidth2(node, expanded, options) {
|
|
|
33394
33775
|
truncated.length * META_CHAR_WIDTH3 + PADDING_X3
|
|
33395
33776
|
);
|
|
33396
33777
|
}
|
|
33397
|
-
return Math.max(MIN_NODE_WIDTH2,
|
|
33778
|
+
return Math.max(MIN_NODE_WIDTH2, labelWidth2, maxRowWidth + 20, descWidth);
|
|
33398
33779
|
}
|
|
33399
33780
|
function computeNodeHeight2(node, expanded, options) {
|
|
33400
33781
|
const propCount = countDisplayProps(node, expanded, options);
|
|
@@ -34944,8 +35325,9 @@ function computeInfraLegendGroups(nodes, tagGroups, palette, edges) {
|
|
|
34944
35325
|
}
|
|
34945
35326
|
return groups;
|
|
34946
35327
|
}
|
|
34947
|
-
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) {
|
|
34948
35329
|
if (legendGroups.length === 0 && !playback) return;
|
|
35330
|
+
const appHostedPlayback = controlsHost === "app" && !!playback;
|
|
34949
35331
|
const legendG = rootSvg.append("g").attr("transform", `translate(0, ${legendY})`);
|
|
34950
35332
|
if (activeGroup) {
|
|
34951
35333
|
legendG.attr("data-legend-active", activeGroup.toLowerCase());
|
|
@@ -34954,14 +35336,29 @@ function renderLegend3(rootSvg, legendGroups, totalWidth, legendY, palette, isDa
|
|
|
34954
35336
|
name: g.name,
|
|
34955
35337
|
entries: g.entries.map((e) => ({ value: e.value, color: e.color }))
|
|
34956
35338
|
}));
|
|
34957
|
-
if (playback) {
|
|
35339
|
+
if (playback && !appHostedPlayback) {
|
|
34958
35340
|
allGroups.push({ name: "Playback", entries: [] });
|
|
34959
35341
|
}
|
|
34960
35342
|
const legendConfig = {
|
|
34961
35343
|
groups: allGroups,
|
|
34962
35344
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
34963
35345
|
mode: exportMode ? "export" : "preview",
|
|
34964
|
-
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
|
+
}
|
|
34965
35362
|
};
|
|
34966
35363
|
const legendState = { activeGroup };
|
|
34967
35364
|
renderLegendD3(
|
|
@@ -35012,8 +35409,9 @@ function renderLegend3(rootSvg, legendGroups, totalWidth, legendY, palette, isDa
|
|
|
35012
35409
|
}
|
|
35013
35410
|
}
|
|
35014
35411
|
}
|
|
35015
|
-
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) {
|
|
35016
35413
|
d3Selection11.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
35414
|
+
const appHostedPlayback = controlsHost === "app" && !!playback;
|
|
35017
35415
|
const ctx = ScaleContext.identity();
|
|
35018
35416
|
const sc = buildScaledConstants(ctx);
|
|
35019
35417
|
const legendGroups = computeInfraLegendGroups(
|
|
@@ -35022,7 +35420,7 @@ function renderInfra(container, layout, palette, isDark, title, titleLineNumber,
|
|
|
35022
35420
|
palette,
|
|
35023
35421
|
layout.edges
|
|
35024
35422
|
);
|
|
35025
|
-
const hasLegend = legendGroups.length > 0 || !!playback;
|
|
35423
|
+
const hasLegend = legendGroups.length > 0 || !!playback && !appHostedPlayback;
|
|
35026
35424
|
const fixedLegend = !exportMode && hasLegend;
|
|
35027
35425
|
const legendDynamicH = hasLegend ? getMaxLegendReservedHeight(
|
|
35028
35426
|
{
|
|
@@ -35166,7 +35564,8 @@ function renderInfra(container, layout, palette, isDark, title, titleLineNumber,
|
|
|
35166
35564
|
isDark,
|
|
35167
35565
|
activeGroup ?? null,
|
|
35168
35566
|
playback ?? void 0,
|
|
35169
|
-
exportMode
|
|
35567
|
+
exportMode,
|
|
35568
|
+
controlsHost
|
|
35170
35569
|
);
|
|
35171
35570
|
legendSvg.selectAll(".infra-legend-group").style("pointer-events", "auto");
|
|
35172
35571
|
} else {
|
|
@@ -35179,7 +35578,8 @@ function renderInfra(container, layout, palette, isDark, title, titleLineNumber,
|
|
|
35179
35578
|
isDark,
|
|
35180
35579
|
activeGroup ?? null,
|
|
35181
35580
|
playback ?? void 0,
|
|
35182
|
-
exportMode
|
|
35581
|
+
exportMode,
|
|
35582
|
+
controlsHost
|
|
35183
35583
|
);
|
|
35184
35584
|
}
|
|
35185
35585
|
}
|
|
@@ -42813,6 +43213,9 @@ function renderTechRadar(container, parsed, palette, isDark, onClickItem, export
|
|
|
42813
43213
|
onToggle: (active) => options.onToggleListing(active)
|
|
42814
43214
|
}
|
|
42815
43215
|
]
|
|
43216
|
+
},
|
|
43217
|
+
...options.controlsHost !== void 0 && {
|
|
43218
|
+
controlsHost: options.controlsHost
|
|
42816
43219
|
}
|
|
42817
43220
|
};
|
|
42818
43221
|
const legendState = {
|
|
@@ -44635,7 +45038,7 @@ function computeCycleLayout(parsed, options) {
|
|
|
44635
45038
|
const circleNodes = parsed.options["circle-nodes"] === "true";
|
|
44636
45039
|
const nodeDims = parsed.nodes.map((node) => {
|
|
44637
45040
|
const hasDesc = !hideDescriptions && node.description.length > 0;
|
|
44638
|
-
const
|
|
45041
|
+
const labelWidth2 = Math.max(
|
|
44639
45042
|
MIN_NODE_WIDTH4,
|
|
44640
45043
|
node.label.length * LABEL_CHAR_W + NODE_PAD_X * 2
|
|
44641
45044
|
);
|
|
@@ -44644,12 +45047,12 @@ function computeCycleLayout(parsed, options) {
|
|
|
44644
45047
|
}
|
|
44645
45048
|
if (!hasDesc) {
|
|
44646
45049
|
return {
|
|
44647
|
-
width: Math.min(MAX_NODE_WIDTH3,
|
|
45050
|
+
width: Math.min(MAX_NODE_WIDTH3, labelWidth2),
|
|
44648
45051
|
height: PLAIN_NODE_HEIGHT,
|
|
44649
45052
|
wrappedDesc: []
|
|
44650
45053
|
};
|
|
44651
45054
|
}
|
|
44652
|
-
return chooseDescribedRectDims(node.description,
|
|
45055
|
+
return chooseDescribedRectDims(node.description, labelWidth2);
|
|
44653
45056
|
});
|
|
44654
45057
|
if (circleNodes) {
|
|
44655
45058
|
const maxDiam = Math.max(...nodeDims.map((d) => d.width));
|
|
@@ -44845,10 +45248,10 @@ function computeCycleLayout(parsed, options) {
|
|
|
44845
45248
|
scale
|
|
44846
45249
|
};
|
|
44847
45250
|
}
|
|
44848
|
-
function chooseDescribedRectDims(description,
|
|
45251
|
+
function chooseDescribedRectDims(description, labelWidth2) {
|
|
44849
45252
|
const minW = Math.min(
|
|
44850
45253
|
MAX_NODE_WIDTH3,
|
|
44851
|
-
Math.max(MIN_NODE_WIDTH4,
|
|
45254
|
+
Math.max(MIN_NODE_WIDTH4, labelWidth2, DESC_MIN_WIDTH)
|
|
44852
45255
|
);
|
|
44853
45256
|
let best = null;
|
|
44854
45257
|
let bestScore = Infinity;
|
|
@@ -45277,7 +45680,8 @@ function renderCycle(container, parsed, palette, isDark, onClickItem, exportDims
|
|
|
45277
45680
|
const hideDescriptions = (renderOptions?.hideDescriptions ?? false) || parsed.options["no-descriptions"] === "true" || viewState?.hd === true;
|
|
45278
45681
|
const showDescriptions = !hideDescriptions;
|
|
45279
45682
|
const hasDescriptions = parsed.nodes.some((n) => n.description.length > 0) || parsed.edges.some((e) => e.description.length > 0);
|
|
45280
|
-
const
|
|
45683
|
+
const appHostedControls = renderOptions?.controlsHost === "app";
|
|
45684
|
+
const hasLegend = !appHostedControls && hasDescriptions && !!renderOptions?.onToggleDescriptions;
|
|
45281
45685
|
const showTitle = !!parsed.title && parsed.options["no-title"] !== "on";
|
|
45282
45686
|
const legendOffset = hasLegend ? sLegendHeight : 0;
|
|
45283
45687
|
const layoutHeight = height - (showTitle ? sTitleAreaHeight : 0) - legendOffset;
|
|
@@ -45314,7 +45718,10 @@ function renderCycle(container, parsed, palette, isDark, onClickItem, exportDims
|
|
|
45314
45718
|
groups: [],
|
|
45315
45719
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
45316
45720
|
mode: renderOptions?.exportMode ? "export" : "preview",
|
|
45317
|
-
controlsGroup
|
|
45721
|
+
controlsGroup,
|
|
45722
|
+
...renderOptions?.controlsHost !== void 0 && {
|
|
45723
|
+
controlsHost: renderOptions.controlsHost
|
|
45724
|
+
}
|
|
45318
45725
|
};
|
|
45319
45726
|
const legendState = {
|
|
45320
45727
|
activeGroup: null,
|
|
@@ -45568,7 +45975,7 @@ var init_renderer15 = __esm({
|
|
|
45568
45975
|
});
|
|
45569
45976
|
|
|
45570
45977
|
// src/map/geo.ts
|
|
45571
|
-
import { feature } from "topojson-client";
|
|
45978
|
+
import { feature, neighbors } from "topojson-client";
|
|
45572
45979
|
import { geoBounds, geoArea } from "d3-geo";
|
|
45573
45980
|
function geomObject(topo) {
|
|
45574
45981
|
const key = Object.keys(topo.objects)[0];
|
|
@@ -45586,6 +45993,107 @@ function featureIndex(topo) {
|
|
|
45586
45993
|
}
|
|
45587
45994
|
return idx;
|
|
45588
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
|
+
}
|
|
45589
46097
|
function featureBbox(topo, geomId) {
|
|
45590
46098
|
const geom = geomObject(topo).geometries.find((g) => g.id === geomId);
|
|
45591
46099
|
if (!geom) return null;
|
|
@@ -45703,11 +46211,13 @@ function unionLongitudes(lons) {
|
|
|
45703
46211
|
}
|
|
45704
46212
|
return { west: pts[gapIdx], east: pts[gapIdx - 1] + 360 };
|
|
45705
46213
|
}
|
|
45706
|
-
var fold, DETACH_GAP_DEG, DETACH_AREA_FRAC;
|
|
46214
|
+
var fold, adjacencyCache, EDGE_EPS, DETACH_GAP_DEG, DETACH_AREA_FRAC;
|
|
45707
46215
|
var init_geo = __esm({
|
|
45708
46216
|
"src/map/geo.ts"() {
|
|
45709
46217
|
"use strict";
|
|
45710
46218
|
fold = (s) => s.normalize("NFD").replace(/\p{Diacritic}/gu, "").toLowerCase().trim();
|
|
46219
|
+
adjacencyCache = /* @__PURE__ */ new WeakMap();
|
|
46220
|
+
EDGE_EPS = 1e-9;
|
|
45711
46221
|
DETACH_GAP_DEG = 10;
|
|
45712
46222
|
DETACH_AREA_FRAC = 0.25;
|
|
45713
46223
|
}
|
|
@@ -45727,6 +46237,12 @@ function looksUS(lat, lon) {
|
|
|
45727
46237
|
if (lat < 15 || lat > 72) return false;
|
|
45728
46238
|
return lon >= -180 && lon <= -64 || lon >= 172;
|
|
45729
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
|
+
}
|
|
45730
46246
|
function resolveMap(parsed, data) {
|
|
45731
46247
|
const diagnostics = [...parsed.diagnostics];
|
|
45732
46248
|
const err = (line12, message, code) => {
|
|
@@ -45737,9 +46253,6 @@ function resolveMap(parsed, data) {
|
|
|
45737
46253
|
};
|
|
45738
46254
|
const result = {
|
|
45739
46255
|
title: parsed.title,
|
|
45740
|
-
...parsed.directives.subtitle !== void 0 && {
|
|
45741
|
-
subtitle: parsed.directives.subtitle
|
|
45742
|
-
},
|
|
45743
46256
|
...parsed.directives.caption !== void 0 && {
|
|
45744
46257
|
caption: parsed.directives.caption
|
|
45745
46258
|
},
|
|
@@ -45749,7 +46262,7 @@ function resolveMap(parsed, data) {
|
|
|
45749
46262
|
// renderer's job (step 4) — the resolver only carries `tags` + `tagGroups`
|
|
45750
46263
|
// through; it never resolves a tag value to a palette color (#10).
|
|
45751
46264
|
directives: { ...parsed.directives },
|
|
45752
|
-
basemaps: { world: "
|
|
46265
|
+
basemaps: { world: "detail", subdivisions: [] },
|
|
45753
46266
|
regions: [],
|
|
45754
46267
|
pois: [],
|
|
45755
46268
|
edges: [],
|
|
@@ -45758,7 +46271,8 @@ function resolveMap(parsed, data) {
|
|
|
45758
46271
|
[-180, -85],
|
|
45759
46272
|
[180, 85]
|
|
45760
46273
|
],
|
|
45761
|
-
projection: "
|
|
46274
|
+
projection: "equirectangular",
|
|
46275
|
+
poiFrameContainers: [],
|
|
45762
46276
|
diagnostics,
|
|
45763
46277
|
error: parsed.error
|
|
45764
46278
|
};
|
|
@@ -45768,7 +46282,10 @@ function resolveMap(parsed, data) {
|
|
|
45768
46282
|
...[...countryIndex.values()].map((v) => v.name),
|
|
45769
46283
|
...[...usStateIndex.values()].map((v) => v.name)
|
|
45770
46284
|
];
|
|
45771
|
-
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) => {
|
|
45772
46289
|
const f = fold(r.name);
|
|
45773
46290
|
return usStateIndex.has(f) && !countryIndex.has(f);
|
|
45774
46291
|
}) || parsed.regions.some(
|
|
@@ -45919,7 +46436,7 @@ function resolveMap(parsed, data) {
|
|
|
45919
46436
|
if (!scope)
|
|
45920
46437
|
warn(
|
|
45921
46438
|
line12,
|
|
45922
|
-
`"${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.`,
|
|
45923
46440
|
"W_MAP_AMBIGUOUS_NAME"
|
|
45924
46441
|
);
|
|
45925
46442
|
}
|
|
@@ -45932,17 +46449,21 @@ function resolveMap(parsed, data) {
|
|
|
45932
46449
|
return fold(pos.name);
|
|
45933
46450
|
};
|
|
45934
46451
|
const poiCountries = [];
|
|
45935
|
-
let
|
|
46452
|
+
let anyUsPoi = false;
|
|
46453
|
+
let anyNonNaPoi = false;
|
|
45936
46454
|
const noteCountry = (iso) => {
|
|
45937
46455
|
if (iso) {
|
|
45938
46456
|
poiCountries.push(iso);
|
|
45939
|
-
if (iso
|
|
46457
|
+
if (iso === "US") anyUsPoi = true;
|
|
46458
|
+
if (iso !== "US" && iso !== "CA" && iso !== "MX") anyNonNaPoi = true;
|
|
45940
46459
|
}
|
|
45941
46460
|
};
|
|
45942
46461
|
const deferred = [];
|
|
45943
46462
|
for (const p of parsed.pois) {
|
|
45944
46463
|
if (p.pos.kind === "coords") {
|
|
45945
|
-
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;
|
|
45946
46467
|
addResolvedPoi(p.pos.lat, p.pos.lon, p);
|
|
45947
46468
|
continue;
|
|
45948
46469
|
}
|
|
@@ -45960,14 +46481,15 @@ function resolveMap(parsed, data) {
|
|
|
45960
46481
|
deferred.push(p);
|
|
45961
46482
|
}
|
|
45962
46483
|
}
|
|
45963
|
-
const inferredCountry =
|
|
46484
|
+
const inferredCountry = localeCountry ?? mostCommonCountry(regions, poiCountries) ?? void 0;
|
|
46485
|
+
const inferredScope = localeSubdivision ?? inferredCountry;
|
|
45964
46486
|
for (const p of deferred) {
|
|
45965
46487
|
if (p.pos.kind !== "name") continue;
|
|
45966
46488
|
const got = lookupName(
|
|
45967
46489
|
p.pos.name,
|
|
45968
46490
|
p.pos.scope,
|
|
45969
46491
|
p.lineNumber,
|
|
45970
|
-
|
|
46492
|
+
inferredScope,
|
|
45971
46493
|
true
|
|
45972
46494
|
);
|
|
45973
46495
|
if (got.kind === "ok") {
|
|
@@ -46037,7 +46559,8 @@ function resolveMap(parsed, data) {
|
|
|
46037
46559
|
const meta = sizeValue !== void 0 ? { value: sizeValue } : {};
|
|
46038
46560
|
if (pos.kind === "coords") {
|
|
46039
46561
|
const id = alias ? fold(alias) : `@${pos.lat},${pos.lon}`;
|
|
46040
|
-
if (
|
|
46562
|
+
if (looksUS(pos.lat, pos.lon)) anyUsPoi = true;
|
|
46563
|
+
else if (!looksNorthAmericaNeighbor(pos.lat, pos.lon)) anyNonNaPoi = true;
|
|
46041
46564
|
if (!registry.has(id)) {
|
|
46042
46565
|
registerPoi(
|
|
46043
46566
|
id,
|
|
@@ -46060,7 +46583,7 @@ function resolveMap(parsed, data) {
|
|
|
46060
46583
|
if (registry.has(f)) return f;
|
|
46061
46584
|
const aliased = declaredByName.get(f);
|
|
46062
46585
|
if (aliased) return aliased;
|
|
46063
|
-
const got = lookupName(pos.name, pos.scope, line12,
|
|
46586
|
+
const got = lookupName(pos.name, pos.scope, line12, inferredScope, true);
|
|
46064
46587
|
if (got.kind !== "ok") return null;
|
|
46065
46588
|
noteCountry(got.iso);
|
|
46066
46589
|
registerPoi(
|
|
@@ -46117,9 +46640,12 @@ function resolveMap(parsed, data) {
|
|
|
46117
46640
|
}
|
|
46118
46641
|
routes.push({ stopIds, legs, lineNumber: rt.lineNumber });
|
|
46119
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;
|
|
46120
46647
|
const subdivisions = [];
|
|
46121
|
-
if (usSubdivisionReferenced ||
|
|
46122
|
-
subdivisions.push("us-states");
|
|
46648
|
+
if (usSubdivisionReferenced || usOriented) subdivisions.push("us-states");
|
|
46123
46649
|
const regionBoxes = [];
|
|
46124
46650
|
for (const ref of referencedRegionIds) {
|
|
46125
46651
|
const bb = featureBbox(data.usStates, ref.id);
|
|
@@ -46137,17 +46663,51 @@ function resolveMap(parsed, data) {
|
|
|
46137
46663
|
[-180, -85],
|
|
46138
46664
|
[180, 85]
|
|
46139
46665
|
];
|
|
46140
|
-
|
|
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
|
+
}
|
|
46141
46703
|
const lonSpan = extent2[1][0] - extent2[0][0];
|
|
46142
46704
|
const latSpan = extent2[1][1] - extent2[0][1];
|
|
46143
46705
|
const span = Math.max(lonSpan, latSpan);
|
|
46144
46706
|
const maxAbsLat = Math.max(Math.abs(extent2[0][1]), Math.abs(extent2[1][1]));
|
|
46145
|
-
const usDominant = (subdivisions.includes("us-states") || regions.some((r) => r.layer === "us-state")) && !regions.some((r) => r.layer === "country" && r.iso !== "US") && !anyNonUsPoi;
|
|
46146
46707
|
let projection;
|
|
46147
|
-
|
|
46148
|
-
|
|
46149
|
-
|
|
46150
|
-
} else if (usDominant) {
|
|
46708
|
+
if (isPoiOnly && usOriented && lonSpan < US_NATIONAL_LON_SPAN) {
|
|
46709
|
+
projection = "mercator";
|
|
46710
|
+
} else if (usOriented) {
|
|
46151
46711
|
projection = "albers-usa";
|
|
46152
46712
|
} else if (span > WORLD_SPAN || maxAbsLat > MERCATOR_MAX_LAT) {
|
|
46153
46713
|
projection = "equirectangular";
|
|
@@ -46165,11 +46725,20 @@ function resolveMap(parsed, data) {
|
|
|
46165
46725
|
result.edges = edges;
|
|
46166
46726
|
result.routes = routes;
|
|
46167
46727
|
result.basemaps = {
|
|
46168
|
-
|
|
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",
|
|
46169
46737
|
subdivisions
|
|
46170
46738
|
};
|
|
46171
46739
|
result.extent = extent2;
|
|
46172
46740
|
result.projection = projection;
|
|
46741
|
+
result.poiFrameContainers = containerRegionIds;
|
|
46173
46742
|
result.error = parsed.error ?? firstError(diagnostics);
|
|
46174
46743
|
return result;
|
|
46175
46744
|
}
|
|
@@ -46206,7 +46775,7 @@ function firstError(diags) {
|
|
|
46206
46775
|
const e = diags.find((d) => d.severity === "error");
|
|
46207
46776
|
return e ? formatDgmoError(e) : null;
|
|
46208
46777
|
}
|
|
46209
|
-
var WORLD_SPAN, MERCATOR_MAX_LAT, PAD_FRACTION, WORLD_LAT_SOUTH, WORLD_LAT_NORTH, REGION_ALIASES, US_STATE_POSTAL;
|
|
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;
|
|
46210
46779
|
var init_resolver2 = __esm({
|
|
46211
46780
|
"src/map/resolver.ts"() {
|
|
46212
46781
|
"use strict";
|
|
@@ -46215,8 +46784,11 @@ var init_resolver2 = __esm({
|
|
|
46215
46784
|
WORLD_SPAN = 90;
|
|
46216
46785
|
MERCATOR_MAX_LAT = 80;
|
|
46217
46786
|
PAD_FRACTION = 0.05;
|
|
46787
|
+
REGION_PAD_FRACTION = 0.12;
|
|
46218
46788
|
WORLD_LAT_SOUTH = -58;
|
|
46219
46789
|
WORLD_LAT_NORTH = 78;
|
|
46790
|
+
POI_ZOOM_FLOOR_DEG = 7;
|
|
46791
|
+
US_NATIONAL_LON_SPAN = 48;
|
|
46220
46792
|
REGION_ALIASES = {
|
|
46221
46793
|
// Common everyday names → the Natural-Earth display name actually shipped.
|
|
46222
46794
|
"united states": "united states of america",
|
|
@@ -46294,10 +46866,277 @@ var init_resolver2 = __esm({
|
|
|
46294
46866
|
}
|
|
46295
46867
|
});
|
|
46296
46868
|
|
|
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
|
+
}
|
|
46891
|
+
});
|
|
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]);
|
|
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 };
|
|
46952
|
+
}
|
|
46953
|
+
return best?.lines ?? [text];
|
|
46954
|
+
}
|
|
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 };
|
|
46959
|
+
}
|
|
46960
|
+
function rectFits(r, width, height) {
|
|
46961
|
+
return r.x >= 0 && r.y >= 0 && r.x + r.w <= width && r.y + r.h <= height;
|
|
46962
|
+
}
|
|
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]
|
|
47037
|
+
});
|
|
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;
|
|
47108
|
+
}
|
|
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"() {
|
|
47112
|
+
"use strict";
|
|
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
|
|
47131
|
+
};
|
|
47132
|
+
}
|
|
47133
|
+
});
|
|
47134
|
+
|
|
46297
47135
|
// src/map/layout.ts
|
|
46298
47136
|
import {
|
|
46299
47137
|
geoPath,
|
|
46300
47138
|
geoNaturalEarth1,
|
|
47139
|
+
geoEqualEarth,
|
|
46301
47140
|
geoEquirectangular,
|
|
46302
47141
|
geoConicEqualArea,
|
|
46303
47142
|
geoMercator,
|
|
@@ -46309,12 +47148,34 @@ function geomObject2(topo) {
|
|
|
46309
47148
|
const key = Object.keys(topo.objects)[0];
|
|
46310
47149
|
return topo.objects[key];
|
|
46311
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
|
+
}
|
|
46312
47167
|
function decodeLayer(topo) {
|
|
47168
|
+
const cached = decodeCache.get(topo);
|
|
47169
|
+
if (cached) return cached;
|
|
46313
47170
|
const out = /* @__PURE__ */ new Map();
|
|
46314
47171
|
for (const g of geomObject2(topo).geometries) {
|
|
46315
47172
|
const f = feature2(topo, g);
|
|
46316
|
-
|
|
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);
|
|
46317
47177
|
}
|
|
47178
|
+
decodeCache.set(topo, out);
|
|
46318
47179
|
return out;
|
|
46319
47180
|
}
|
|
46320
47181
|
function projectionFor(family) {
|
|
@@ -46323,9 +47184,12 @@ function projectionFor(family) {
|
|
|
46323
47184
|
return usConusProjection();
|
|
46324
47185
|
case "mercator":
|
|
46325
47186
|
return geoMercator();
|
|
47187
|
+
case "equal-earth":
|
|
47188
|
+
return geoEqualEarth();
|
|
47189
|
+
case "equirectangular":
|
|
47190
|
+
return geoEquirectangular();
|
|
46326
47191
|
case "natural-earth":
|
|
46327
47192
|
return geoNaturalEarth1();
|
|
46328
|
-
case "equirectangular":
|
|
46329
47193
|
default:
|
|
46330
47194
|
return geoEquirectangular();
|
|
46331
47195
|
}
|
|
@@ -46344,13 +47208,11 @@ function mapNeutralLandColor(palette, isDark, _dataActive = false) {
|
|
|
46344
47208
|
isDark ? LAND_TINT_DARK : LAND_TINT_LIGHT
|
|
46345
47209
|
);
|
|
46346
47210
|
}
|
|
46347
|
-
function
|
|
46348
|
-
const { palette, isDark } = opts;
|
|
46349
|
-
const { width, height } = size;
|
|
47211
|
+
function buildMapProjection(resolved, data) {
|
|
46350
47212
|
const wantsUsStates = resolved.basemaps.subdivisions.includes("us-states");
|
|
46351
|
-
const usCrisp = resolved.projection === "albers-usa" && wantsUsStates && !!data.naLand;
|
|
47213
|
+
const usCrisp = (resolved.projection === "albers-usa" || resolved.projection === "mercator") && wantsUsStates && !!data.naLand;
|
|
46352
47214
|
const worldTopo = usCrisp ? data.worldDetail : resolved.basemaps.world === "detail" ? data.worldDetail : data.worldCoarse;
|
|
46353
|
-
const worldLayer = decodeLayer(worldTopo);
|
|
47215
|
+
const worldLayer = new Map(decodeLayer(worldTopo));
|
|
46354
47216
|
if (usCrisp && data.naLand) {
|
|
46355
47217
|
const [nbW, nbS, nbE, nbN] = [-140, 10, -52, 66];
|
|
46356
47218
|
const crisp = decodeLayer(data.naLand);
|
|
@@ -46359,16 +47221,109 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46359
47221
|
if (!base) continue;
|
|
46360
47222
|
const [[bw, bs], [be, bn]] = geoBounds2(base);
|
|
46361
47223
|
if (bw >= nbW && be <= nbE && bs >= nbS && bn <= nbN)
|
|
46362
|
-
worldLayer.set(iso, cf);
|
|
47224
|
+
worldLayer.set(iso, { ...cf, properties: base.properties });
|
|
46363
47225
|
}
|
|
46364
47226
|
}
|
|
46365
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);
|
|
46366
47321
|
const usContext = usLayer !== null;
|
|
46367
47322
|
const regionStroke = isDark ? mix(palette.bg, palette.text, 78) : mix(palette.text, palette.bg, 78);
|
|
46368
47323
|
const values = resolved.regions.filter((r) => r.value !== void 0).map((r) => r.value);
|
|
46369
|
-
const
|
|
46370
|
-
const rampMin =
|
|
46371
|
-
const rampMax =
|
|
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);
|
|
46372
47327
|
const rampHue = resolveColor(resolved.directives.regionMetricColor ?? "", palette) ?? palette.colors.red;
|
|
46373
47328
|
const hasRamp = values.length > 0;
|
|
46374
47329
|
const VALUE_NAME = hasRamp ? resolved.directives.regionMetric?.trim() || "Value" : null;
|
|
@@ -46389,7 +47344,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46389
47344
|
activeGroup = VALUE_NAME ?? (resolved.tagGroups.length > 0 ? resolved.tagGroups[0].name : null);
|
|
46390
47345
|
}
|
|
46391
47346
|
const activeIsScore = VALUE_NAME !== null && activeGroup === VALUE_NAME;
|
|
46392
|
-
const mutedBasemap =
|
|
47347
|
+
const mutedBasemap = activeGroup !== null;
|
|
46393
47348
|
const neutralFill = mapNeutralLandColor(palette, isDark, mutedBasemap);
|
|
46394
47349
|
const water = mapBackgroundColor(palette, isDark, mutedBasemap);
|
|
46395
47350
|
const lakeStroke = mix(regionStroke, water, 45);
|
|
@@ -46398,6 +47353,39 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46398
47353
|
palette.bg,
|
|
46399
47354
|
mutedBasemap ? isDark ? MUTED_FOREIGN_DARK : MUTED_FOREIGN_LIGHT : isDark ? FOREIGN_TINT_DARK : FOREIGN_TINT_LIGHT
|
|
46400
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);
|
|
46401
47389
|
const rampBase = isDark ? mix(palette.surface, palette.text, 28) : palette.bg;
|
|
46402
47390
|
const fillForValue = (s) => {
|
|
46403
47391
|
const t = rampMax > rampMin ? (s - rampMin) / (rampMax - rampMin) : 1;
|
|
@@ -46433,43 +47421,15 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46433
47421
|
if (activeIsScore) {
|
|
46434
47422
|
return r.value !== void 0 ? fillForValue(r.value) : neutralFill;
|
|
46435
47423
|
}
|
|
47424
|
+
if (colorizeActive) return (r.iso && colorByIso.get(r.iso)) ?? neutralFill;
|
|
46436
47425
|
return tagFill(r.tags, activeGroup) ?? neutralFill;
|
|
46437
47426
|
};
|
|
46438
47427
|
const regionById = new Map(resolved.regions.map((r) => [r.iso, r]));
|
|
46439
|
-
const
|
|
46440
|
-
const [[w, s], [e, n]] = resolved.extent;
|
|
46441
|
-
const N = 16;
|
|
46442
|
-
const coords = [];
|
|
46443
|
-
for (let i = 0; i <= N; i++) {
|
|
46444
|
-
const t = i / N;
|
|
46445
|
-
const lon = w + (e - w) * t;
|
|
46446
|
-
const lat = s + (n - s) * t;
|
|
46447
|
-
coords.push([lon, s], [lon, n], [w, lat], [e, lat]);
|
|
46448
|
-
}
|
|
46449
|
-
return {
|
|
46450
|
-
type: "Feature",
|
|
46451
|
-
properties: {},
|
|
46452
|
-
geometry: { type: "MultiPoint", coordinates: coords }
|
|
46453
|
-
};
|
|
46454
|
-
};
|
|
46455
|
-
let fitFeatures;
|
|
46456
|
-
if (resolved.projection === "albers-usa" && usLayer) {
|
|
46457
|
-
fitFeatures = [...usLayer.entries()].filter(([iso]) => !US_NON_CONUS.has(iso)).map(([, f]) => f);
|
|
46458
|
-
} else {
|
|
46459
|
-
fitFeatures = [extentOutline()];
|
|
46460
|
-
}
|
|
46461
|
-
const fitTarget = { type: "FeatureCollection", features: fitFeatures };
|
|
46462
|
-
const projection = projectionFor(resolved.projection);
|
|
46463
|
-
if (resolved.projection !== "albers-usa") {
|
|
46464
|
-
let centerLon = (resolved.extent[0][0] + resolved.extent[1][0]) / 2;
|
|
46465
|
-
if (centerLon > 180) centerLon -= 360;
|
|
46466
|
-
projection.rotate([-centerLon, 0]);
|
|
46467
|
-
}
|
|
46468
|
-
const TITLE_GAP = 16;
|
|
47428
|
+
const TITLE_GAP2 = 16;
|
|
46469
47429
|
let topPad = FIT_PAD;
|
|
46470
47430
|
if (resolved.title && resolved.pois.length > 0) {
|
|
46471
47431
|
const bannerBottom = (resolved.subtitle ? TITLE_Y + TITLE_FONT_SIZE : TITLE_Y) + TITLE_FONT_SIZE / 2;
|
|
46472
|
-
topPad = Math.max(FIT_PAD, bannerBottom +
|
|
47432
|
+
topPad = Math.max(FIT_PAD, bannerBottom + TITLE_GAP2);
|
|
46473
47433
|
}
|
|
46474
47434
|
const fitBox = [
|
|
46475
47435
|
[FIT_PAD, topPad],
|
|
@@ -46479,12 +47439,10 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46479
47439
|
]
|
|
46480
47440
|
];
|
|
46481
47441
|
projection.fitExtent(fitBox, fitTarget);
|
|
46482
|
-
const fitGB = geoBounds2(fitTarget);
|
|
46483
|
-
const fitIsGlobal = fitGB[1][0] - fitGB[0][0] >= 270 || fitGB[1][1] - fitGB[0][1] >= 130;
|
|
46484
47442
|
let path;
|
|
46485
47443
|
let project;
|
|
46486
47444
|
let stretchParams = null;
|
|
46487
|
-
if (fitIsGlobal) {
|
|
47445
|
+
if (fitIsGlobal && !opts.preferContain) {
|
|
46488
47446
|
const cb = geoPath(projection).bounds(fitTarget);
|
|
46489
47447
|
const bx0 = cb[0][0];
|
|
46490
47448
|
const by0 = cb[0][1];
|
|
@@ -46526,7 +47484,9 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46526
47484
|
const insets = [];
|
|
46527
47485
|
const insetRegions = [];
|
|
46528
47486
|
const insetLabelSeeds = [];
|
|
46529
|
-
|
|
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)) {
|
|
46530
47490
|
const PAD = 8;
|
|
46531
47491
|
const GAP = 12;
|
|
46532
47492
|
const yB = height - FIT_PAD;
|
|
@@ -46591,8 +47551,18 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46591
47551
|
);
|
|
46592
47552
|
const d = geoPath(proj)(f) ?? "";
|
|
46593
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
|
+
}
|
|
46594
47564
|
const r = regionById.get(iso);
|
|
46595
|
-
let fill2 = neutralFill;
|
|
47565
|
+
let fill2 = colorizeActive ? colorByIso.get(iso) ?? neutralFill : neutralFill;
|
|
46596
47566
|
let lineNumber = -1;
|
|
46597
47567
|
if (r?.layer === "us-state") {
|
|
46598
47568
|
fill2 = regionFill(r);
|
|
@@ -46611,13 +47581,14 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46611
47581
|
],
|
|
46612
47582
|
// The FITTED inset projection (just fit to this box) — captured so the
|
|
46613
47583
|
// geo-query can invert pixels inside the frame back to AK/HI coords.
|
|
46614
|
-
projection: proj
|
|
47584
|
+
projection: proj,
|
|
47585
|
+
...contextLand && { contextLand }
|
|
46615
47586
|
});
|
|
46616
47587
|
insetRegions.push({
|
|
46617
47588
|
id: iso,
|
|
46618
47589
|
d,
|
|
46619
47590
|
fill: fill2,
|
|
46620
|
-
stroke: regionStroke,
|
|
47591
|
+
stroke: colorizeActive ? colorizeStroke(fill2) : regionStroke,
|
|
46621
47592
|
lineNumber,
|
|
46622
47593
|
layer: "us-state",
|
|
46623
47594
|
...r?.value !== void 0 && { value: r.value },
|
|
@@ -46630,13 +47601,16 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46630
47601
|
}
|
|
46631
47602
|
return xr;
|
|
46632
47603
|
};
|
|
46633
|
-
|
|
46634
|
-
|
|
46635
|
-
alaskaProjection(),
|
|
46636
|
-
|
|
46637
|
-
|
|
46638
|
-
|
|
46639
|
-
|
|
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
|
+
);
|
|
46640
47614
|
}
|
|
46641
47615
|
const conusFit = resolved.projection === "albers-usa" && !!usLayer;
|
|
46642
47616
|
const classifyExtent = conusFit ? geoBounds2(fitTarget) : resolved.extent;
|
|
@@ -46652,15 +47626,24 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46652
47626
|
};
|
|
46653
47627
|
const ringOverlapsView = (ring) => {
|
|
46654
47628
|
let loMin = Infinity, loMax = -Infinity, rawMin = Infinity, rawMax = -Infinity;
|
|
47629
|
+
const lons = [];
|
|
46655
47630
|
for (const [rawLon] of ring) {
|
|
46656
47631
|
const lon = normLon(rawLon);
|
|
47632
|
+
lons.push(lon);
|
|
46657
47633
|
if (lon < loMin) loMin = lon;
|
|
46658
47634
|
if (lon > loMax) loMax = lon;
|
|
46659
47635
|
if (rawLon < rawMin) rawMin = rawLon;
|
|
46660
47636
|
if (rawLon > rawMax) rawMax = rawLon;
|
|
46661
47637
|
}
|
|
46662
|
-
|
|
46663
|
-
|
|
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;
|
|
46664
47647
|
let px0 = Infinity, py0 = Infinity, px1 = -Infinity, py1 = -Infinity, anyFinite = false;
|
|
46665
47648
|
for (const [lon, lat] of ring) {
|
|
46666
47649
|
const p = project(lon, lat);
|
|
@@ -46733,7 +47716,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46733
47716
|
const regions = [];
|
|
46734
47717
|
const pushRegionLayer = (layerFeatures, layerKind, shouldCull) => {
|
|
46735
47718
|
for (const [iso, f] of layerFeatures) {
|
|
46736
|
-
if (layerKind === "us-state" && usContext && INSET_STATES.has(iso))
|
|
47719
|
+
if (layerKind === "us-state" && usContext && resolved.projection === "albers-usa" && INSET_STATES.has(iso))
|
|
46737
47720
|
continue;
|
|
46738
47721
|
if (layerKind === "country" && usContext && iso === "US") continue;
|
|
46739
47722
|
if (layerKind === "country" && iso === "AQ" && !regionById.has("AQ"))
|
|
@@ -46745,7 +47728,8 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46745
47728
|
if (!d) continue;
|
|
46746
47729
|
const isThisLayer = r?.layer === layerKind;
|
|
46747
47730
|
const isForeign = layerKind === "country" && usContext && iso !== "US";
|
|
46748
|
-
|
|
47731
|
+
const baseFill = isForeign ? foreignFill : neutralFill;
|
|
47732
|
+
let fill2 = colorizeActive ? colorByIso.get(iso) ?? baseFill : baseFill;
|
|
46749
47733
|
let label;
|
|
46750
47734
|
let lineNumber = -1;
|
|
46751
47735
|
let layer = "base";
|
|
@@ -46754,12 +47738,14 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46754
47738
|
lineNumber = r.lineNumber;
|
|
46755
47739
|
layer = layerKind;
|
|
46756
47740
|
label = r.name;
|
|
47741
|
+
} else {
|
|
47742
|
+
label = f.properties?.name;
|
|
46757
47743
|
}
|
|
46758
47744
|
regions.push({
|
|
46759
47745
|
id: iso,
|
|
46760
47746
|
d,
|
|
46761
47747
|
fill: fill2,
|
|
46762
|
-
stroke: regionStroke,
|
|
47748
|
+
stroke: colorizeActive ? colorizeStroke(fill2) : regionStroke,
|
|
46763
47749
|
lineNumber,
|
|
46764
47750
|
layer,
|
|
46765
47751
|
...label !== void 0 && { label },
|
|
@@ -46787,9 +47773,41 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46787
47773
|
});
|
|
46788
47774
|
}
|
|
46789
47775
|
}
|
|
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;
|
|
46790
47808
|
const relief = [];
|
|
46791
47809
|
let reliefHatch = null;
|
|
46792
|
-
if (
|
|
47810
|
+
if (reliefAllowed && data.mountainRanges) {
|
|
46793
47811
|
for (const [, f] of decodeLayer(data.mountainRanges)) {
|
|
46794
47812
|
const viewF = isGlobalView ? dropFrameFillers(f) : cullFeatureToView(f);
|
|
46795
47813
|
if (!viewF) continue;
|
|
@@ -46805,16 +47823,32 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46805
47823
|
if (relief.length) {
|
|
46806
47824
|
const darkTone = isDark ? palette.bg : palette.text;
|
|
46807
47825
|
const lightTone = isDark ? palette.text : palette.bg;
|
|
46808
|
-
const
|
|
47826
|
+
const reliefLandRef = colorizeActive ? isDark ? palette.surface : palette.bg : neutralFill;
|
|
47827
|
+
const landLum = relativeLuminance(reliefLandRef);
|
|
46809
47828
|
const tone = Math.abs(landLum - relativeLuminance(darkTone)) > 0.04 ? darkTone : lightTone;
|
|
46810
47829
|
reliefHatch = {
|
|
46811
|
-
color: mix(tone,
|
|
47830
|
+
color: mix(tone, reliefLandRef, RELIEF_HATCH_STRENGTH),
|
|
46812
47831
|
spacing: RELIEF_HATCH_SPACING,
|
|
46813
47832
|
width: RELIEF_HATCH_WIDTH
|
|
46814
47833
|
};
|
|
46815
47834
|
}
|
|
46816
47835
|
}
|
|
46817
|
-
|
|
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);
|
|
46818
47852
|
const rivers = [];
|
|
46819
47853
|
if (data.rivers) {
|
|
46820
47854
|
for (const [, f] of decodeLayer(data.rivers)) {
|
|
@@ -46870,38 +47904,108 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46870
47904
|
const xy = project(p.lon, p.lat);
|
|
46871
47905
|
if (xy) projected.push({ p, xy });
|
|
46872
47906
|
}
|
|
46873
|
-
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);
|
|
46874
47936
|
for (const e of projected) {
|
|
46875
|
-
|
|
46876
|
-
|
|
46877
|
-
|
|
46878
|
-
|
|
46879
|
-
|
|
46880
|
-
|
|
46881
|
-
|
|
46882
|
-
|
|
46883
|
-
|
|
46884
|
-
|
|
46885
|
-
|
|
46886
|
-
|
|
46887
|
-
|
|
46888
|
-
|
|
46889
|
-
|
|
46890
|
-
|
|
46891
|
-
|
|
46892
|
-
|
|
46893
|
-
|
|
46894
|
-
|
|
46895
|
-
|
|
46896
|
-
|
|
46897
|
-
|
|
46898
|
-
|
|
46899
|
-
|
|
46900
|
-
|
|
46901
|
-
|
|
46902
|
-
|
|
46903
|
-
|
|
46904
|
-
|
|
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
|
|
46905
48009
|
});
|
|
46906
48010
|
}
|
|
46907
48011
|
const legs = [];
|
|
@@ -46951,16 +48055,26 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46951
48055
|
if (!a || !b) continue;
|
|
46952
48056
|
const mx = (a.cx + b.cx) / 2;
|
|
46953
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;
|
|
46954
48065
|
legs.push({
|
|
46955
|
-
d: legPath(a, b,
|
|
48066
|
+
d: legPath(a, b, bow.curved, bow.offset),
|
|
46956
48067
|
width: routeWidthFor(Number(leg.value)),
|
|
46957
48068
|
color: mix(palette.text, palette.bg, 72),
|
|
46958
48069
|
arrow: true,
|
|
46959
48070
|
lineNumber: leg.lineNumber,
|
|
46960
48071
|
...leg.label !== void 0 && {
|
|
46961
48072
|
label: leg.label,
|
|
46962
|
-
labelX:
|
|
46963
|
-
labelY:
|
|
48073
|
+
labelX: bow.labelX,
|
|
48074
|
+
labelY: bow.labelY,
|
|
48075
|
+
labelColor: routeLabelStyle.color,
|
|
48076
|
+
labelHalo: routeLabelStyle.halo,
|
|
48077
|
+
labelHaloColor: routeLabelStyle.haloColor
|
|
46964
48078
|
}
|
|
46965
48079
|
});
|
|
46966
48080
|
}
|
|
@@ -46988,20 +48102,29 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46988
48102
|
const a = poiScreen.get(e.fromId);
|
|
46989
48103
|
const b = poiScreen.get(e.toId);
|
|
46990
48104
|
if (!a || !b) return;
|
|
46991
|
-
const
|
|
46992
|
-
const offset = n > 1 ? (i - (n - 1) / 2) * FAN_STEP : 0;
|
|
48105
|
+
const fanOffset = n > 1 ? (i - (n - 1) / 2) * FAN_STEP : 0;
|
|
46993
48106
|
const mx = (a.cx + b.cx) / 2;
|
|
46994
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;
|
|
46995
48115
|
legs.push({
|
|
46996
|
-
d: legPath(a, b, curved, offset),
|
|
48116
|
+
d: legPath(a, b, bow.curved, bow.offset),
|
|
46997
48117
|
width: widthFor(e),
|
|
46998
48118
|
color: mix(palette.text, palette.bg, 66),
|
|
46999
48119
|
arrow: e.directed,
|
|
47000
48120
|
lineNumber: e.lineNumber,
|
|
47001
48121
|
...e.label !== void 0 && {
|
|
47002
48122
|
label: e.label,
|
|
47003
|
-
labelX:
|
|
47004
|
-
labelY:
|
|
48123
|
+
labelX: bow.labelX,
|
|
48124
|
+
labelY: bow.labelY,
|
|
48125
|
+
labelColor: edgeLabelStyle.color,
|
|
48126
|
+
labelHalo: edgeLabelStyle.halo,
|
|
48127
|
+
labelHaloColor: edgeLabelStyle.haloColor
|
|
47005
48128
|
}
|
|
47006
48129
|
});
|
|
47007
48130
|
});
|
|
@@ -47043,25 +48166,25 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47043
48166
|
}
|
|
47044
48167
|
}
|
|
47045
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));
|
|
47046
|
-
const
|
|
48169
|
+
const showRegionLabels = resolved.directives.noRegionLabels !== true;
|
|
48170
|
+
const isCompact = width < COMPACT_WIDTH_PX;
|
|
47047
48171
|
const LABEL_PADX = 6;
|
|
47048
48172
|
const LABEL_PADY = 3;
|
|
47049
|
-
const labelW = (text) => measureLegendText(text,
|
|
47050
|
-
const labelH =
|
|
48173
|
+
const labelW = (text) => measureLegendText(text, FONT2) + 2 * LABEL_PADX;
|
|
48174
|
+
const labelH = FONT2 + 2 * LABEL_PADY;
|
|
47051
48175
|
const pushRegionLabel = (x, y, text, fill2, lineNumber) => {
|
|
47052
|
-
const color =
|
|
47053
|
-
|
|
47054
|
-
|
|
47055
|
-
|
|
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
|
|
47056
48180
|
);
|
|
47057
|
-
const haloColor = color === palette.textOnFillLight ? palette.textOnFillDark : palette.textOnFillLight;
|
|
47058
48181
|
labels.push({
|
|
47059
48182
|
x,
|
|
47060
48183
|
y,
|
|
47061
48184
|
text,
|
|
47062
48185
|
anchor: "middle",
|
|
47063
48186
|
color,
|
|
47064
|
-
halo:
|
|
48187
|
+
halo: overflows,
|
|
47065
48188
|
haloColor,
|
|
47066
48189
|
lineNumber
|
|
47067
48190
|
});
|
|
@@ -47070,21 +48193,50 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47070
48193
|
US: [-98.5, 39.5]
|
|
47071
48194
|
// CONUS geographic centre (near Lebanon, Kansas)
|
|
47072
48195
|
};
|
|
47073
|
-
|
|
47074
|
-
|
|
47075
|
-
|
|
47076
|
-
|
|
47077
|
-
|
|
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;
|
|
47078
48210
|
const [[x0, y0], [x1, y1]] = path.bounds(f);
|
|
47079
|
-
const
|
|
47080
|
-
|
|
47081
|
-
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;
|
|
47082
48216
|
const c = anchor ? project(anchor[0], anchor[1]) : path.centroid(f);
|
|
47083
|
-
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));
|
|
47084
48236
|
pushRegionLabel(c[0], c[1], text, r.fill, r.lineNumber);
|
|
47085
48237
|
}
|
|
47086
48238
|
for (const seed of insetLabelSeeds) {
|
|
47087
|
-
const text =
|
|
48239
|
+
const text = isCompact ? seed.iso.replace(/^US-/, "") : seed.name;
|
|
47088
48240
|
const src = regionById.get(seed.iso);
|
|
47089
48241
|
pushRegionLabel(
|
|
47090
48242
|
seed.x,
|
|
@@ -47095,22 +48247,26 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47095
48247
|
);
|
|
47096
48248
|
}
|
|
47097
48249
|
}
|
|
47098
|
-
|
|
47099
|
-
|
|
47100
|
-
const ordered = [...pois].sort(
|
|
47101
|
-
(a, b) => a.lineNumber - b.lineNumber || (a.id < b.id ? -1 : 1)
|
|
47102
|
-
);
|
|
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));
|
|
47103
48252
|
const poiById = new Map(resolved.pois.map((q) => [q.id, q]));
|
|
47104
48253
|
const labelText = (p) => {
|
|
47105
48254
|
const src = poiById.get(p.id);
|
|
47106
48255
|
return src?.label ?? src?.name ?? p.id;
|
|
47107
48256
|
};
|
|
47108
|
-
const poiLabH =
|
|
48257
|
+
const poiLabH = FONT2 * 1.25;
|
|
47109
48258
|
const labelInfo = (p) => {
|
|
47110
48259
|
const text = labelText(p);
|
|
47111
|
-
return { text, w: measureLegendText(text,
|
|
48260
|
+
return { text, w: measureLegendText(text, FONT2) };
|
|
47112
48261
|
};
|
|
47113
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
|
+
}
|
|
47114
48270
|
const inlineRect = (p, w, side) => {
|
|
47115
48271
|
switch (side) {
|
|
47116
48272
|
case "right":
|
|
@@ -47140,11 +48296,11 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47140
48296
|
const x = side === "right" ? rect.x : side === "left" ? rect.x + w : p.cx;
|
|
47141
48297
|
labels.push({
|
|
47142
48298
|
x,
|
|
47143
|
-
y: rect.y + poiLabH / 2 +
|
|
48299
|
+
y: rect.y + poiLabH / 2 + FONT2 / 3,
|
|
47144
48300
|
text,
|
|
47145
48301
|
anchor,
|
|
47146
48302
|
color: palette.text,
|
|
47147
|
-
halo:
|
|
48303
|
+
halo: false,
|
|
47148
48304
|
haloColor: palette.bg,
|
|
47149
48305
|
poiId: p.id,
|
|
47150
48306
|
lineNumber: p.lineNumber
|
|
@@ -47155,43 +48311,60 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47155
48311
|
return rect.x >= 0 && rect.x + rect.w <= width && rect.y >= 0 && rect.y + rect.h <= height && !collides(rect);
|
|
47156
48312
|
};
|
|
47157
48313
|
const GROUP_R = 30;
|
|
47158
|
-
const
|
|
48314
|
+
const groups2 = [];
|
|
47159
48315
|
for (const p of ordered) {
|
|
47160
|
-
const near =
|
|
48316
|
+
const near = groups2.find(
|
|
47161
48317
|
(g) => g.some((q) => Math.hypot(q.cx - p.cx, q.cy - p.cy) < GROUP_R)
|
|
47162
48318
|
);
|
|
47163
48319
|
if (near) near.push(p);
|
|
47164
|
-
else
|
|
48320
|
+
else groups2.push([p]);
|
|
47165
48321
|
}
|
|
47166
48322
|
const ROW_GAP2 = 3;
|
|
47167
48323
|
const step = poiLabH + ROW_GAP2;
|
|
47168
48324
|
const COL_GAP = 16;
|
|
47169
|
-
const
|
|
47170
|
-
|
|
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) => {
|
|
47171
48327
|
const left = Math.min(...items.map((o) => o.p.cx - o.p.r));
|
|
47172
48328
|
const right = Math.max(...items.map((o) => o.p.cx + o.p.r));
|
|
47173
|
-
const cyMid = (Math.min(...items.map((o) => o.p.cy)) + Math.max(...items.map((o) => o.p.cy))) / 2;
|
|
47174
48329
|
const maxW = Math.max(...items.map((o) => o.w));
|
|
47175
|
-
const
|
|
47176
|
-
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);
|
|
47177
48332
|
const totalH = items.length * step;
|
|
47178
48333
|
let startY = cyMid - totalH / 2;
|
|
47179
48334
|
startY = Math.max(2, Math.min(startY, height - totalH - 2));
|
|
47180
|
-
items.
|
|
48335
|
+
return items.map((o, i) => {
|
|
47181
48336
|
const rowCy = startY + i * step + step / 2;
|
|
47182
|
-
|
|
47183
|
-
|
|
47184
|
-
|
|
47185
|
-
|
|
47186
|
-
|
|
47187
|
-
|
|
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);
|
|
47188
48361
|
labels.push({
|
|
47189
48362
|
x: colX,
|
|
47190
|
-
y: rowCy +
|
|
48363
|
+
y: rowCy + FONT2 / 3,
|
|
47191
48364
|
text: o.text,
|
|
47192
48365
|
anchor: side === "right" ? "start" : "end",
|
|
47193
48366
|
color: palette.text,
|
|
47194
|
-
halo:
|
|
48367
|
+
halo: false,
|
|
47195
48368
|
haloColor: palette.bg,
|
|
47196
48369
|
leader: {
|
|
47197
48370
|
x1: o.p.cx,
|
|
@@ -47201,24 +48374,141 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47201
48374
|
},
|
|
47202
48375
|
leaderColor: o.p.fill,
|
|
47203
48376
|
poiId: o.p.id,
|
|
47204
|
-
lineNumber: o.p.lineNumber
|
|
48377
|
+
lineNumber: o.p.lineNumber,
|
|
48378
|
+
...clusterId !== void 0 && { clusterMember: clusterId }
|
|
47205
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
|
|
47206
48402
|
});
|
|
47207
48403
|
};
|
|
47208
|
-
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);
|
|
47209
48414
|
if (g.length === 1) {
|
|
47210
|
-
const p =
|
|
47211
|
-
const { text, w } = labelInfo(p);
|
|
48415
|
+
const { p, text, w } = items[0];
|
|
47212
48416
|
const side = ["right", "left", "above", "below"].find(
|
|
47213
48417
|
(s) => inlineFits(p, w, s)
|
|
47214
48418
|
);
|
|
47215
|
-
if (side)
|
|
47216
|
-
|
|
47217
|
-
|
|
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;
|
|
47218
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
|
+
});
|
|
47219
48493
|
}
|
|
47220
|
-
placeColumn(g);
|
|
47221
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);
|
|
47222
48512
|
}
|
|
47223
48513
|
let legend = null;
|
|
47224
48514
|
if (!resolved.directives.noLegend) {
|
|
@@ -47255,25 +48545,31 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47255
48545
|
rivers,
|
|
47256
48546
|
relief,
|
|
47257
48547
|
reliefHatch,
|
|
48548
|
+
coastlineStyle,
|
|
47258
48549
|
legs,
|
|
47259
48550
|
pois,
|
|
48551
|
+
clusters,
|
|
47260
48552
|
labels,
|
|
47261
48553
|
legend,
|
|
47262
48554
|
insets,
|
|
47263
48555
|
insetRegions,
|
|
47264
48556
|
projection,
|
|
47265
|
-
stretch: stretchParams
|
|
48557
|
+
stretch: stretchParams,
|
|
48558
|
+
diagnostics: []
|
|
47266
48559
|
};
|
|
47267
48560
|
}
|
|
47268
|
-
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;
|
|
47269
48562
|
var init_layout15 = __esm({
|
|
47270
48563
|
"src/map/layout.ts"() {
|
|
47271
48564
|
"use strict";
|
|
47272
48565
|
init_color_utils();
|
|
48566
|
+
init_geo();
|
|
48567
|
+
init_colorize();
|
|
47273
48568
|
init_colors();
|
|
47274
48569
|
init_label_layout();
|
|
47275
48570
|
init_legend_constants();
|
|
47276
48571
|
init_title_constants();
|
|
48572
|
+
init_context_labels();
|
|
47277
48573
|
FIT_PAD = 24;
|
|
47278
48574
|
RAMP_FLOOR = 15;
|
|
47279
48575
|
R_DEFAULT = 6;
|
|
@@ -47281,32 +48577,66 @@ var init_layout15 = __esm({
|
|
|
47281
48577
|
R_MAX = 22;
|
|
47282
48578
|
W_MIN = 1.25;
|
|
47283
48579
|
W_MAX = 8;
|
|
47284
|
-
|
|
47285
|
-
|
|
48580
|
+
FONT2 = 11;
|
|
48581
|
+
MAX_CLUSTER_EXTENT_FACTOR = 0.18;
|
|
48582
|
+
MAX_COLUMN_ROWS = 7;
|
|
48583
|
+
REGION_LABEL_HALO_RATIO = 4.5;
|
|
47286
48584
|
LAND_TINT_LIGHT = 12;
|
|
47287
48585
|
LAND_TINT_DARK = 24;
|
|
47288
48586
|
TAG_TINT_LIGHT = 60;
|
|
47289
48587
|
TAG_TINT_DARK = 68;
|
|
47290
|
-
WATER_TINT_LIGHT =
|
|
47291
|
-
WATER_TINT_DARK =
|
|
48588
|
+
WATER_TINT_LIGHT = 24;
|
|
48589
|
+
WATER_TINT_DARK = 24;
|
|
47292
48590
|
RIVER_WIDTH = 1.3;
|
|
48591
|
+
COMPACT_WIDTH_PX = 480;
|
|
47293
48592
|
RELIEF_MIN_AREA = 12;
|
|
47294
48593
|
RELIEF_MIN_DIM = 2;
|
|
47295
|
-
RELIEF_HATCH_SPACING =
|
|
47296
|
-
RELIEF_HATCH_WIDTH = 0.
|
|
48594
|
+
RELIEF_HATCH_SPACING = 2;
|
|
48595
|
+
RELIEF_HATCH_WIDTH = 0.15;
|
|
47297
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;
|
|
47298
48606
|
FOREIGN_TINT_LIGHT = 30;
|
|
47299
48607
|
FOREIGN_TINT_DARK = 62;
|
|
47300
48608
|
MUTED_FOREIGN_LIGHT = 28;
|
|
47301
48609
|
MUTED_FOREIGN_DARK = 16;
|
|
47302
48610
|
COLO_R = 9;
|
|
47303
48611
|
GOLDEN_ANGLE = 2.399963229728653;
|
|
48612
|
+
STACK_OVERLAP = 1;
|
|
48613
|
+
STACK_RING_MAX = 8;
|
|
48614
|
+
STACK_RING_GAP = 4;
|
|
47304
48615
|
FAN_STEP = 16;
|
|
47305
48616
|
ARC_CURVE_FRAC = 0.18;
|
|
48617
|
+
decodeCache = /* @__PURE__ */ new WeakMap();
|
|
47306
48618
|
usConusProjection = () => geoConicEqualArea().parallels([29.5, 45.5]).rotate([96, 0]);
|
|
47307
48619
|
alaskaProjection = () => geoConicEqualArea().rotate([154, 0]).center([-2, 58.5]).parallels([55, 65]);
|
|
47308
48620
|
hawaiiProjection = () => geoMercator();
|
|
47309
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
|
+
};
|
|
47310
48640
|
US_NON_CONUS = /* @__PURE__ */ new Set([
|
|
47311
48641
|
"US-AK",
|
|
47312
48642
|
"US-HI",
|
|
@@ -47326,6 +48656,58 @@ __export(renderer_exports16, {
|
|
|
47326
48656
|
renderMapForExport: () => renderMapForExport
|
|
47327
48657
|
});
|
|
47328
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
|
+
}
|
|
47329
48711
|
function renderMap(container, resolved, data, palette, isDark, onClickItem, exportDims, activeGroupOverride) {
|
|
47330
48712
|
d3Selection18.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
47331
48713
|
const width = exportDims?.width ?? container.clientWidth;
|
|
@@ -47338,6 +48720,11 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47338
48720
|
{
|
|
47339
48721
|
palette,
|
|
47340
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,
|
|
47341
48728
|
...activeGroupOverride !== void 0 && {
|
|
47342
48729
|
activeGroup: activeGroupOverride
|
|
47343
48730
|
}
|
|
@@ -47351,6 +48738,7 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47351
48738
|
const gRegions = svg.append("g").attr("class", "dgmo-map-regions");
|
|
47352
48739
|
const drawRegion = (g, r, strokeWidth) => {
|
|
47353
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);
|
|
47354
48742
|
if (r.layer !== "base") {
|
|
47355
48743
|
p.classed("dgmo-map-region", true).attr("data-region", r.id);
|
|
47356
48744
|
if (r.value !== void 0) p.attr("data-value", r.value);
|
|
@@ -47385,6 +48773,38 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47385
48773
|
gRelief.append("line").attr("x1", 0).attr("y1", y).attr("x2", width).attr("y2", y);
|
|
47386
48774
|
}
|
|
47387
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
|
+
}
|
|
47388
48808
|
if (layout.rivers.length) {
|
|
47389
48809
|
const gRivers = svg.append("g").attr("class", "dgmo-map-rivers").attr("fill", "none");
|
|
47390
48810
|
for (const r of layout.rivers) {
|
|
@@ -47393,15 +48813,61 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47393
48813
|
}
|
|
47394
48814
|
if (layout.insets.length) {
|
|
47395
48815
|
const insetG = svg.append("g").attr("class", "dgmo-map-insets");
|
|
47396
|
-
|
|
48816
|
+
layout.insets.forEach((box, bi) => {
|
|
47397
48817
|
const d = box.points.map((p, i) => `${i ? "L" : "M"}${p[0]},${p[1]}`).join("") + "Z";
|
|
47398
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");
|
|
47399
|
-
|
|
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
|
+
});
|
|
47400
48825
|
for (const r of layout.insetRegions) drawRegion(insetG, r, 0.5);
|
|
47401
|
-
|
|
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
|
+
};
|
|
47402
48867
|
const gLegs = svg.append("g").attr("class", "dgmo-map-legs").attr("fill", "none");
|
|
47403
48868
|
layout.legs.forEach((leg, i) => {
|
|
47404
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);
|
|
47405
48871
|
if (leg.arrow) {
|
|
47406
48872
|
const id = `dgmo-map-arrow-${i}`;
|
|
47407
48873
|
const s = arrowSize(leg.width);
|
|
@@ -47409,25 +48875,38 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47409
48875
|
p.attr("marker-end", `url(#${id})`);
|
|
47410
48876
|
}
|
|
47411
48877
|
if (leg.label !== void 0 && leg.labelX !== void 0) {
|
|
47412
|
-
emitText(
|
|
48878
|
+
const lt = emitText(
|
|
47413
48879
|
gLegs,
|
|
47414
48880
|
leg.labelX,
|
|
47415
48881
|
leg.labelY ?? 0,
|
|
47416
48882
|
leg.label,
|
|
47417
48883
|
"middle",
|
|
47418
|
-
palette.textMuted,
|
|
47419
|
-
haloColor,
|
|
47420
|
-
true,
|
|
48884
|
+
leg.labelColor ?? palette.textMuted,
|
|
48885
|
+
leg.labelHaloColor ?? haloColor,
|
|
48886
|
+
leg.labelHalo ?? true,
|
|
47421
48887
|
LABEL_FONT - 1
|
|
47422
48888
|
);
|
|
48889
|
+
wireSync(lt, leg.lineNumber);
|
|
47423
48890
|
}
|
|
47424
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
|
+
}
|
|
47425
48902
|
const gPois = svg.append("g").attr("class", "dgmo-map-pois");
|
|
47426
48903
|
for (const poi of layout.pois) {
|
|
47427
48904
|
if (poi.isOrigin) {
|
|
47428
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);
|
|
47429
48906
|
}
|
|
47430
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);
|
|
47431
48910
|
if (poi.tags) {
|
|
47432
48911
|
for (const [group, value] of Object.entries(poi.tags)) {
|
|
47433
48912
|
c.attr(`data-tag-${group.toLowerCase()}`, value.toLowerCase());
|
|
@@ -47455,12 +48934,32 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47455
48934
|
}
|
|
47456
48935
|
const gLabels = svg.append("g").attr("class", "dgmo-map-labels");
|
|
47457
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
|
+
}
|
|
47458
48954
|
if (lab.leader) {
|
|
47459
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(
|
|
47460
48956
|
"stroke",
|
|
47461
48957
|
lab.leaderColor ?? mix(palette.textMuted, palette.bg, 60)
|
|
47462
48958
|
).attr("stroke-width", lab.leaderColor ? 1 : 0.75);
|
|
47463
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);
|
|
47464
48963
|
}
|
|
47465
48964
|
const t = emitText(
|
|
47466
48965
|
gLabels,
|
|
@@ -47471,11 +48970,38 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47471
48970
|
lab.color,
|
|
47472
48971
|
lab.haloColor,
|
|
47473
48972
|
lab.halo,
|
|
47474
|
-
LABEL_FONT
|
|
48973
|
+
LABEL_FONT,
|
|
48974
|
+
lab.italic,
|
|
48975
|
+
lab.letterSpacing,
|
|
48976
|
+
lab.lines
|
|
47475
48977
|
);
|
|
47476
48978
|
if (lab.poiId !== void 0) {
|
|
47477
48979
|
t.attr("data-poi", lab.poiId).style("cursor", "default");
|
|
47478
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
|
+
}
|
|
47479
49005
|
}
|
|
47480
49006
|
if (layout.legend) {
|
|
47481
49007
|
const legendY = (layout.title ? TITLE_Y + TITLE_FONT_SIZE : 0) + (layout.subtitle ? TITLE_FONT_SIZE : 0) + 8;
|
|
@@ -47512,7 +49038,7 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47512
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);
|
|
47513
49039
|
}
|
|
47514
49040
|
if (layout.subtitle) {
|
|
47515
|
-
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);
|
|
47516
49042
|
}
|
|
47517
49043
|
if (layout.caption) {
|
|
47518
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);
|
|
@@ -47521,10 +49047,21 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47521
49047
|
function renderMapForExport(container, resolved, data, palette, isDark, exportDims) {
|
|
47522
49048
|
renderMap(container, resolved, data, palette, isDark, void 0, exportDims);
|
|
47523
49049
|
}
|
|
47524
|
-
function emitText(g, x, y, text, anchor, color, halo, withHalo, fontSize) {
|
|
47525
|
-
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);
|
|
47526
49063
|
if (withHalo) {
|
|
47527
|
-
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);
|
|
47528
49065
|
}
|
|
47529
49066
|
return t;
|
|
47530
49067
|
}
|
|
@@ -47541,6 +49078,56 @@ var init_renderer16 = __esm({
|
|
|
47541
49078
|
}
|
|
47542
49079
|
});
|
|
47543
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
|
+
|
|
47544
49131
|
// src/map/load-data.ts
|
|
47545
49132
|
var load_data_exports = {};
|
|
47546
49133
|
__export(load_data_exports, {
|
|
@@ -47599,12 +49186,17 @@ function loadMapData() {
|
|
|
47599
49186
|
mountainRanges,
|
|
47600
49187
|
naLand,
|
|
47601
49188
|
naLakes,
|
|
49189
|
+
waterBodies,
|
|
47602
49190
|
gazetteer
|
|
47603
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.
|
|
47604
49196
|
readJson(nb, dir, FILES.worldCoarse),
|
|
47605
49197
|
readJson(nb, dir, FILES.worldDetail),
|
|
47606
49198
|
readJson(nb, dir, FILES.usStates),
|
|
47607
|
-
// Lakes/rivers/mountain/NA assets are optional — older bundles may predate them.
|
|
49199
|
+
// Lakes/rivers/mountain/NA/water assets are optional — older bundles may predate them.
|
|
47608
49200
|
readJson(nb, dir, FILES.lakes).catch(() => void 0),
|
|
47609
49201
|
readJson(nb, dir, FILES.rivers).catch(() => void 0),
|
|
47610
49202
|
readJson(nb, dir, FILES.mountainRanges).catch(
|
|
@@ -47612,6 +49204,7 @@ function loadMapData() {
|
|
|
47612
49204
|
),
|
|
47613
49205
|
readJson(nb, dir, FILES.naLand).catch(() => void 0),
|
|
47614
49206
|
readJson(nb, dir, FILES.naLakes).catch(() => void 0),
|
|
49207
|
+
readJson(nb, dir, FILES.waterBodies).catch(() => void 0),
|
|
47615
49208
|
readJson(nb, dir, FILES.gazetteer)
|
|
47616
49209
|
]);
|
|
47617
49210
|
return validate({
|
|
@@ -47623,7 +49216,8 @@ function loadMapData() {
|
|
|
47623
49216
|
...rivers && { rivers },
|
|
47624
49217
|
...mountainRanges && { mountainRanges },
|
|
47625
49218
|
...naLand && { naLand },
|
|
47626
|
-
...naLakes && { naLakes }
|
|
49219
|
+
...naLakes && { naLakes },
|
|
49220
|
+
...waterBodies && { waterBodies }
|
|
47627
49221
|
});
|
|
47628
49222
|
})().catch((e) => {
|
|
47629
49223
|
cache = void 0;
|
|
@@ -47644,6 +49238,7 @@ var init_load_data = __esm({
|
|
|
47644
49238
|
mountainRanges: "mountain-ranges.json",
|
|
47645
49239
|
naLand: "na-land.json",
|
|
47646
49240
|
naLakes: "na-lakes.json",
|
|
49241
|
+
waterBodies: "water-bodies.json",
|
|
47647
49242
|
gazetteer: "gazetteer.json"
|
|
47648
49243
|
};
|
|
47649
49244
|
CANDIDATE_DIRS = [
|
|
@@ -49657,8 +51252,8 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
|
|
|
49657
51252
|
const lines = splitParticipantLabel(p.label, LABEL_MAX_CHARS);
|
|
49658
51253
|
if (lines.length === 0) continue;
|
|
49659
51254
|
const widest = Math.max(...lines.map((l) => l.length));
|
|
49660
|
-
const
|
|
49661
|
-
uniformBoxWidth = Math.max(uniformBoxWidth,
|
|
51255
|
+
const labelWidth2 = widest * LABEL_CHAR_WIDTH + 10;
|
|
51256
|
+
uniformBoxWidth = Math.max(uniformBoxWidth, labelWidth2);
|
|
49662
51257
|
}
|
|
49663
51258
|
uniformBoxWidth = Math.min(MAX_BOX_WIDTH, uniformBoxWidth);
|
|
49664
51259
|
const effectiveGap = Math.max(PARTICIPANT_GAP, uniformBoxWidth + 30);
|
|
@@ -52357,15 +53952,15 @@ function renderArcDiagram(container, parsed, palette, _isDark, onClickItem, expo
|
|
|
52357
53952
|
textColor,
|
|
52358
53953
|
onClickItem
|
|
52359
53954
|
);
|
|
52360
|
-
const
|
|
52361
|
-
for (const node of nodes)
|
|
53955
|
+
const neighbors2 = /* @__PURE__ */ new Map();
|
|
53956
|
+
for (const node of nodes) neighbors2.set(node, /* @__PURE__ */ new Set());
|
|
52362
53957
|
for (const link of links) {
|
|
52363
|
-
|
|
52364
|
-
|
|
53958
|
+
neighbors2.get(link.source).add(link.target);
|
|
53959
|
+
neighbors2.get(link.target).add(link.source);
|
|
52365
53960
|
}
|
|
52366
53961
|
const FADE_OPACITY3 = 0.1;
|
|
52367
53962
|
function handleMouseEnter(hovered) {
|
|
52368
|
-
const connected =
|
|
53963
|
+
const connected = neighbors2.get(hovered);
|
|
52369
53964
|
g.selectAll(".arc-link").each(function() {
|
|
52370
53965
|
const el = d3Selection23.select(this);
|
|
52371
53966
|
const src = el.attr("data-source");
|
|
@@ -54300,7 +55895,7 @@ function renderVenn(container, parsed, palette, _isDark, onClickItem, exportDims
|
|
|
54300
55895
|
8,
|
|
54301
55896
|
Math.floor(OVERLAP_WRAP_TARGET_W / OVERLAP_CH_W)
|
|
54302
55897
|
);
|
|
54303
|
-
function
|
|
55898
|
+
function wrapLabel3(text, maxChars) {
|
|
54304
55899
|
const words = text.split(/\s+/).filter(Boolean);
|
|
54305
55900
|
const lines = [];
|
|
54306
55901
|
let cur = "";
|
|
@@ -54346,7 +55941,7 @@ function renderVenn(container, parsed, palette, _isDark, onClickItem, exportDims
|
|
|
54346
55941
|
if (!ov.label) continue;
|
|
54347
55942
|
const idxs = ov.sets.map((s) => vennSets.findIndex((vs) => vs.name === s));
|
|
54348
55943
|
if (idxs.some((idx) => idx < 0)) continue;
|
|
54349
|
-
const lines =
|
|
55944
|
+
const lines = wrapLabel3(ov.label, MAX_WRAP_CHARS);
|
|
54350
55945
|
wrappedOverlapLabels.set(ov, lines);
|
|
54351
55946
|
const dir = predictOverlapDirRaw(idxs);
|
|
54352
55947
|
const longest = lines.reduce((m, l) => Math.max(m, l.length), 0);
|
|
@@ -55784,6 +57379,7 @@ async function renderForExport(content, theme, palette, viewState, options) {
|
|
|
55784
57379
|
const { parseMap: parseMap2 } = await Promise.resolve().then(() => (init_parser12(), parser_exports11));
|
|
55785
57380
|
const { resolveMap: resolveMap2 } = await Promise.resolve().then(() => (init_resolver2(), resolver_exports));
|
|
55786
57381
|
const { renderMapForExport: renderMapForExport2 } = await Promise.resolve().then(() => (init_renderer16(), renderer_exports16));
|
|
57382
|
+
const { mapExportDimensions: mapExportDimensions2 } = await Promise.resolve().then(() => (init_dimensions(), dimensions_exports));
|
|
55787
57383
|
const effectivePalette2 = await resolveExportPalette(theme, palette);
|
|
55788
57384
|
const mapParsed = parseMap2(content);
|
|
55789
57385
|
let mapData = options?.mapData;
|
|
@@ -55796,14 +57392,15 @@ async function renderForExport(content, theme, palette, viewState, options) {
|
|
|
55796
57392
|
}
|
|
55797
57393
|
}
|
|
55798
57394
|
const mapResolved = resolveMap2(mapParsed, mapData);
|
|
55799
|
-
const
|
|
57395
|
+
const dims2 = mapExportDimensions2(mapResolved, mapData, EXPORT_WIDTH);
|
|
57396
|
+
const container2 = createExportContainer(dims2.width, dims2.height);
|
|
55800
57397
|
renderMapForExport2(
|
|
55801
57398
|
container2,
|
|
55802
57399
|
mapResolved,
|
|
55803
57400
|
mapData,
|
|
55804
57401
|
effectivePalette2,
|
|
55805
57402
|
theme === "dark",
|
|
55806
|
-
|
|
57403
|
+
dims2
|
|
55807
57404
|
);
|
|
55808
57405
|
return finalizeSvgExport(container2, theme, effectivePalette2);
|
|
55809
57406
|
}
|
|
@@ -56645,7 +58242,8 @@ async function render(content, options) {
|
|
|
56645
58242
|
...options?.c4Container !== void 0 && {
|
|
56646
58243
|
c4Container: options.c4Container
|
|
56647
58244
|
},
|
|
56648
|
-
...options?.tagGroup !== void 0 && { tagGroup: options.tagGroup }
|
|
58245
|
+
...options?.tagGroup !== void 0 && { tagGroup: options.tagGroup },
|
|
58246
|
+
...options?.mapData !== void 0 && { mapData: options.mapData }
|
|
56649
58247
|
});
|
|
56650
58248
|
if (chartType === "map") {
|
|
56651
58249
|
try {
|
|
@@ -56656,7 +58254,7 @@ async function render(content, options) {
|
|
|
56656
58254
|
Promise.resolve().then(() => (init_load_data(), load_data_exports))
|
|
56657
58255
|
]
|
|
56658
58256
|
);
|
|
56659
|
-
const data = await loadMapData2();
|
|
58257
|
+
const data = options?.mapData ?? await loadMapData2();
|
|
56660
58258
|
diagnostics = [...resolveMap2(parseMap2(content), data).diagnostics];
|
|
56661
58259
|
} catch {
|
|
56662
58260
|
}
|