@diagrammo/dgmo 0.21.0 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -6
- package/dist/advanced.cjs +2521 -623
- package/dist/advanced.d.cts +917 -534
- package/dist/advanced.d.ts +917 -534
- package/dist/advanced.js +2516 -623
- package/dist/auto.cjs +2333 -608
- package/dist/auto.js +119 -119
- package/dist/auto.mjs +2335 -609
- package/dist/cli.cjs +168 -168
- package/dist/editor.cjs +13 -15
- package/dist/editor.js +13 -15
- package/dist/highlight.cjs +15 -12
- package/dist/highlight.js +15 -12
- package/dist/index.cjs +2317 -595
- package/dist/index.d.cts +4 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +2319 -596
- package/dist/internal.cjs +2521 -623
- package/dist/internal.d.cts +917 -534
- package/dist/internal.d.ts +917 -534
- package/dist/internal.js +2516 -623
- package/dist/map-data/PROVENANCE.json +1 -1
- package/dist/map-data/mountain-ranges.json +1 -0
- package/dist/map-data/water-bodies.json +1 -0
- package/docs/language-reference.md +44 -31
- package/gallery/fixtures/map-categorical-world.dgmo +16 -0
- package/gallery/fixtures/map-categorical.dgmo +0 -1
- package/gallery/fixtures/map-choropleth.dgmo +0 -1
- package/gallery/fixtures/map-coastline.dgmo +7 -0
- package/gallery/fixtures/map-colorize.dgmo +11 -0
- package/gallery/fixtures/map-direct-color.dgmo +9 -0
- package/gallery/fixtures/map-reference-world.dgmo +11 -0
- package/gallery/fixtures/map-region-scope.dgmo +0 -3
- package/gallery/fixtures/map-route.dgmo +0 -1
- package/package.json +1 -1
- package/src/advanced.ts +26 -1
- package/src/boxes-and-lines/renderer.ts +39 -12
- package/src/cli.ts +1 -1
- package/src/completion.ts +32 -24
- package/src/cycle/renderer.ts +14 -1
- package/src/d3.ts +23 -11
- package/src/editor/highlight-api.ts +4 -0
- package/src/editor/keywords.ts +13 -15
- package/src/infra/renderer.ts +35 -7
- package/src/map/colorize.ts +54 -0
- package/src/map/context-labels.ts +429 -0
- package/src/map/data/PROVENANCE.json +1 -1
- package/src/map/data/mountain-ranges.json +1 -0
- package/src/map/data/types.ts +34 -0
- package/src/map/data/water-bodies.json +1 -0
- package/src/map/dimensions.ts +117 -0
- package/src/map/geo-query.ts +295 -0
- package/src/map/geo.ts +305 -2
- package/src/map/invert.ts +111 -0
- package/src/map/layout.ts +1504 -335
- package/src/map/load-data.ts +16 -2
- package/src/map/parser.ts +57 -111
- package/src/map/renderer.ts +556 -13
- package/src/map/resolved-types.ts +24 -2
- package/src/map/resolver.ts +237 -67
- package/src/map/types.ts +39 -23
- package/src/mindmap/renderer.ts +10 -1
- package/src/palettes/atlas.ts +77 -0
- package/src/palettes/blueprint.ts +73 -0
- package/src/palettes/color-utils.ts +58 -1
- package/src/palettes/index.ts +12 -3
- package/src/palettes/slate.ts +73 -0
- package/src/palettes/tidewater.ts +73 -0
- package/src/render.ts +8 -1
- package/src/tech-radar/renderer.ts +3 -0
- package/src/tech-radar/types.ts +3 -0
- package/src/utils/d3-types.ts +5 -0
- package/src/utils/legend-layout.ts +21 -4
- package/src/utils/legend-types.ts +7 -0
- package/src/utils/reserved-key-registry.ts +3 -0
- package/src/palettes/bold.ts +0 -67
package/dist/index.cjs
CHANGED
|
@@ -93,18 +93,18 @@ function computeQuadrantPointLabels(points, chartBounds, obstacles, pointRadius,
|
|
|
93
93
|
const results = [];
|
|
94
94
|
for (let i = 0; i < points.length; i++) {
|
|
95
95
|
const pt = points[i];
|
|
96
|
-
const
|
|
96
|
+
const labelWidth2 = pt.label.length * fontSize * CHAR_WIDTH_RATIO + 8;
|
|
97
97
|
let best = null;
|
|
98
98
|
const directions = [
|
|
99
99
|
{
|
|
100
100
|
// Above
|
|
101
101
|
gen: (offset) => {
|
|
102
|
-
const lx = pt.cx -
|
|
102
|
+
const lx = pt.cx - labelWidth2 / 2;
|
|
103
103
|
const ly = pt.cy - offset - labelHeight;
|
|
104
|
-
if (ly < chartBounds.top || lx < chartBounds.left || lx +
|
|
104
|
+
if (ly < chartBounds.top || lx < chartBounds.left || lx + labelWidth2 > chartBounds.right)
|
|
105
105
|
return null;
|
|
106
106
|
return {
|
|
107
|
-
rect: { x: lx, y: ly, w:
|
|
107
|
+
rect: { x: lx, y: ly, w: labelWidth2, h: labelHeight },
|
|
108
108
|
textX: pt.cx,
|
|
109
109
|
textY: ly + labelHeight / 2,
|
|
110
110
|
anchor: "middle"
|
|
@@ -114,12 +114,12 @@ function computeQuadrantPointLabels(points, chartBounds, obstacles, pointRadius,
|
|
|
114
114
|
{
|
|
115
115
|
// Below
|
|
116
116
|
gen: (offset) => {
|
|
117
|
-
const lx = pt.cx -
|
|
117
|
+
const lx = pt.cx - labelWidth2 / 2;
|
|
118
118
|
const ly = pt.cy + offset;
|
|
119
|
-
if (ly + labelHeight > chartBounds.bottom || lx < chartBounds.left || lx +
|
|
119
|
+
if (ly + labelHeight > chartBounds.bottom || lx < chartBounds.left || lx + labelWidth2 > chartBounds.right)
|
|
120
120
|
return null;
|
|
121
121
|
return {
|
|
122
|
-
rect: { x: lx, y: ly, w:
|
|
122
|
+
rect: { x: lx, y: ly, w: labelWidth2, h: labelHeight },
|
|
123
123
|
textX: pt.cx,
|
|
124
124
|
textY: ly + labelHeight / 2,
|
|
125
125
|
anchor: "middle"
|
|
@@ -131,10 +131,10 @@ function computeQuadrantPointLabels(points, chartBounds, obstacles, pointRadius,
|
|
|
131
131
|
gen: (offset) => {
|
|
132
132
|
const lx = pt.cx + offset;
|
|
133
133
|
const ly = pt.cy - labelHeight / 2;
|
|
134
|
-
if (lx +
|
|
134
|
+
if (lx + labelWidth2 > chartBounds.right || ly < chartBounds.top || ly + labelHeight > chartBounds.bottom)
|
|
135
135
|
return null;
|
|
136
136
|
return {
|
|
137
|
-
rect: { x: lx, y: ly, w:
|
|
137
|
+
rect: { x: lx, y: ly, w: labelWidth2, h: labelHeight },
|
|
138
138
|
textX: lx,
|
|
139
139
|
textY: pt.cy,
|
|
140
140
|
anchor: "start"
|
|
@@ -144,13 +144,13 @@ function computeQuadrantPointLabels(points, chartBounds, obstacles, pointRadius,
|
|
|
144
144
|
{
|
|
145
145
|
// Left
|
|
146
146
|
gen: (offset) => {
|
|
147
|
-
const lx = pt.cx - offset -
|
|
147
|
+
const lx = pt.cx - offset - labelWidth2;
|
|
148
148
|
const ly = pt.cy - labelHeight / 2;
|
|
149
149
|
if (lx < chartBounds.left || ly < chartBounds.top || ly + labelHeight > chartBounds.bottom)
|
|
150
150
|
return null;
|
|
151
151
|
return {
|
|
152
|
-
rect: { x: lx, y: ly, w:
|
|
153
|
-
textX: lx +
|
|
152
|
+
rect: { x: lx, y: ly, w: labelWidth2, h: labelHeight },
|
|
153
|
+
textX: lx + labelWidth2,
|
|
154
154
|
textY: pt.cy,
|
|
155
155
|
anchor: "end"
|
|
156
156
|
};
|
|
@@ -200,10 +200,10 @@ function computeQuadrantPointLabels(points, chartBounds, obstacles, pointRadius,
|
|
|
200
200
|
}
|
|
201
201
|
}
|
|
202
202
|
if (!best) {
|
|
203
|
-
const lx = pt.cx -
|
|
203
|
+
const lx = pt.cx - labelWidth2 / 2;
|
|
204
204
|
const ly = pt.cy - minGap - labelHeight;
|
|
205
205
|
best = {
|
|
206
|
-
rect: { x: lx, y: ly, w:
|
|
206
|
+
rect: { x: lx, y: ly, w: labelWidth2, h: labelHeight },
|
|
207
207
|
textX: pt.cx,
|
|
208
208
|
textY: ly + labelHeight / 2,
|
|
209
209
|
anchor: "middle",
|
|
@@ -838,6 +838,9 @@ var init_reserved_key_registry = __esm({
|
|
|
838
838
|
"value",
|
|
839
839
|
"label",
|
|
840
840
|
"style"
|
|
841
|
+
// `surface:` was removed in the 2026-06-02 defaults-on review — it is no longer
|
|
842
|
+
// a recognized metadata key (the route/edge surface feature was cut; §24B.7).
|
|
843
|
+
// A stray `surface: water` is no longer captured as a reserved key.
|
|
841
844
|
]);
|
|
842
845
|
ORG_REGISTRY = staticRegistry([
|
|
843
846
|
"color",
|
|
@@ -1900,77 +1903,266 @@ function getSegmentColors(palette, count) {
|
|
|
1900
1903
|
(_, i) => hslToHex(Math.round((startHue + i * step) % 360), avgS, avgL)
|
|
1901
1904
|
);
|
|
1902
1905
|
}
|
|
1906
|
+
function politicalTints(palette, count, isDark) {
|
|
1907
|
+
if (count <= 0) return [];
|
|
1908
|
+
const base = isDark ? palette.surface : palette.bg;
|
|
1909
|
+
const c = palette.colors;
|
|
1910
|
+
const swatches = [
|
|
1911
|
+
.../* @__PURE__ */ new Set([
|
|
1912
|
+
c.green,
|
|
1913
|
+
c.yellow,
|
|
1914
|
+
c.orange,
|
|
1915
|
+
c.purple,
|
|
1916
|
+
c.red,
|
|
1917
|
+
c.teal,
|
|
1918
|
+
c.cyan,
|
|
1919
|
+
c.blue
|
|
1920
|
+
])
|
|
1921
|
+
];
|
|
1922
|
+
const bands = isDark ? POLITICAL_TINT_BANDS.dark : POLITICAL_TINT_BANDS.light;
|
|
1923
|
+
const out = [];
|
|
1924
|
+
for (const pct of bands) {
|
|
1925
|
+
if (out.length >= count) break;
|
|
1926
|
+
for (const s of swatches) out.push(mix(s, base, pct));
|
|
1927
|
+
}
|
|
1928
|
+
return out.slice(0, count);
|
|
1929
|
+
}
|
|
1930
|
+
var POLITICAL_TINT_BANDS;
|
|
1903
1931
|
var init_color_utils = __esm({
|
|
1904
1932
|
"src/palettes/color-utils.ts"() {
|
|
1905
1933
|
"use strict";
|
|
1934
|
+
POLITICAL_TINT_BANDS = {
|
|
1935
|
+
light: [32, 48, 64, 80],
|
|
1936
|
+
dark: [44, 58, 72, 86]
|
|
1937
|
+
};
|
|
1906
1938
|
}
|
|
1907
1939
|
});
|
|
1908
1940
|
|
|
1909
|
-
// src/palettes/
|
|
1910
|
-
var
|
|
1911
|
-
var
|
|
1912
|
-
"src/palettes/
|
|
1941
|
+
// src/palettes/atlas.ts
|
|
1942
|
+
var atlasPalette;
|
|
1943
|
+
var init_atlas = __esm({
|
|
1944
|
+
"src/palettes/atlas.ts"() {
|
|
1913
1945
|
"use strict";
|
|
1914
1946
|
init_registry();
|
|
1915
|
-
|
|
1916
|
-
id: "
|
|
1917
|
-
name: "
|
|
1947
|
+
atlasPalette = {
|
|
1948
|
+
id: "atlas",
|
|
1949
|
+
name: "Atlas",
|
|
1918
1950
|
light: {
|
|
1919
|
-
bg: "#
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1951
|
+
bg: "#f3ead3",
|
|
1952
|
+
// warm manila / parchment
|
|
1953
|
+
surface: "#ece0c0",
|
|
1954
|
+
// deeper paper (cards, panels)
|
|
1955
|
+
overlay: "#e8dab8",
|
|
1956
|
+
// popovers, dropdowns
|
|
1957
|
+
border: "#bcaa86",
|
|
1958
|
+
// muted sepia rule line
|
|
1959
|
+
text: "#463a26",
|
|
1960
|
+
// aged sepia-brown ink
|
|
1961
|
+
textMuted: "#7a6a4f",
|
|
1962
|
+
// faded annotation ink
|
|
1963
|
+
textOnFillLight: "#f7f1de",
|
|
1964
|
+
// parchment (light text on dark fills)
|
|
1965
|
+
textOnFillDark: "#3a2e1c",
|
|
1966
|
+
// deep ink (dark text on light fills)
|
|
1967
|
+
primary: "#5b7a99",
|
|
1968
|
+
// pull-down map ocean (steel-blue)
|
|
1969
|
+
secondary: "#7e9a6f",
|
|
1970
|
+
// lowland sage / celadon
|
|
1971
|
+
accent: "#b07f7c",
|
|
1972
|
+
// dusty rose
|
|
1973
|
+
destructive: "#b25a45",
|
|
1974
|
+
// brick / terracotta
|
|
1931
1975
|
colors: {
|
|
1932
|
-
red: "#
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1976
|
+
red: "#bf6a52",
|
|
1977
|
+
// terracotta brick
|
|
1978
|
+
orange: "#cf9a5c",
|
|
1979
|
+
// map tan / ochre
|
|
1980
|
+
yellow: "#cdb35e",
|
|
1981
|
+
// straw / muted lemon
|
|
1982
|
+
green: "#7e9a6f",
|
|
1983
|
+
// sage / celadon lowland
|
|
1984
|
+
blue: "#5b7a99",
|
|
1985
|
+
// steel-blue ocean
|
|
1986
|
+
purple: "#9a7fa6",
|
|
1987
|
+
// dusty lilac / mauve
|
|
1988
|
+
teal: "#6fa094",
|
|
1989
|
+
// muted seafoam
|
|
1990
|
+
cyan: "#79a7b5",
|
|
1991
|
+
// shallow-water blue
|
|
1992
|
+
gray: "#8a7d68",
|
|
1993
|
+
// warm taupe
|
|
1994
|
+
black: "#463a26",
|
|
1995
|
+
// ink
|
|
1996
|
+
white: "#ece0c0"
|
|
1997
|
+
// paper
|
|
1943
1998
|
}
|
|
1944
1999
|
},
|
|
1945
2000
|
dark: {
|
|
1946
|
-
bg: "#
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
2001
|
+
bg: "#1e2a33",
|
|
2002
|
+
// deep map ocean (night globe)
|
|
2003
|
+
surface: "#27353f",
|
|
2004
|
+
// raised ocean
|
|
2005
|
+
overlay: "#2e3d48",
|
|
2006
|
+
// popovers, dropdowns
|
|
2007
|
+
border: "#3d4f5c",
|
|
2008
|
+
// depth-contour line
|
|
2009
|
+
text: "#e8dcc0",
|
|
2010
|
+
// parchment ink, inverted
|
|
2011
|
+
textMuted: "#a89a7d",
|
|
2012
|
+
// faded label
|
|
2013
|
+
textOnFillLight: "#f7f1de",
|
|
2014
|
+
// parchment
|
|
2015
|
+
textOnFillDark: "#1a242c",
|
|
2016
|
+
// deep ocean ink
|
|
2017
|
+
primary: "#7ba0bf",
|
|
2018
|
+
// brighter ocean
|
|
2019
|
+
secondary: "#9bb588",
|
|
2020
|
+
// sage, lifted
|
|
2021
|
+
accent: "#cf9a96",
|
|
2022
|
+
// dusty rose, lifted
|
|
2023
|
+
destructive: "#c9745c",
|
|
2024
|
+
// brick, lifted
|
|
1958
2025
|
colors: {
|
|
1959
|
-
red: "#
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
2026
|
+
red: "#cf7a60",
|
|
2027
|
+
// terracotta
|
|
2028
|
+
orange: "#d9a96a",
|
|
2029
|
+
// tan / ochre
|
|
2030
|
+
yellow: "#d8c074",
|
|
2031
|
+
// straw
|
|
2032
|
+
green: "#9bb588",
|
|
2033
|
+
// sage lowland
|
|
2034
|
+
blue: "#7ba0bf",
|
|
2035
|
+
// ocean
|
|
2036
|
+
purple: "#b59ac0",
|
|
2037
|
+
// lilac / mauve
|
|
2038
|
+
teal: "#85b3a6",
|
|
2039
|
+
// seafoam
|
|
2040
|
+
cyan: "#92bccb",
|
|
2041
|
+
// shallow-water blue
|
|
2042
|
+
gray: "#9a8d76",
|
|
2043
|
+
// warm taupe
|
|
2044
|
+
black: "#27353f",
|
|
2045
|
+
// raised ocean
|
|
2046
|
+
white: "#e8dcc0"
|
|
2047
|
+
// parchment
|
|
1970
2048
|
}
|
|
1971
2049
|
}
|
|
1972
2050
|
};
|
|
1973
|
-
registerPalette(
|
|
2051
|
+
registerPalette(atlasPalette);
|
|
2052
|
+
}
|
|
2053
|
+
});
|
|
2054
|
+
|
|
2055
|
+
// src/palettes/blueprint.ts
|
|
2056
|
+
var blueprintPalette;
|
|
2057
|
+
var init_blueprint = __esm({
|
|
2058
|
+
"src/palettes/blueprint.ts"() {
|
|
2059
|
+
"use strict";
|
|
2060
|
+
init_registry();
|
|
2061
|
+
blueprintPalette = {
|
|
2062
|
+
id: "blueprint",
|
|
2063
|
+
name: "Blueprint",
|
|
2064
|
+
light: {
|
|
2065
|
+
bg: "#f4f8fb",
|
|
2066
|
+
// pale drafting white (faint cyan)
|
|
2067
|
+
surface: "#e6eef4",
|
|
2068
|
+
// drafting panel
|
|
2069
|
+
overlay: "#dde9f1",
|
|
2070
|
+
// popovers, dropdowns
|
|
2071
|
+
border: "#aac3d6",
|
|
2072
|
+
// pale blue grid line
|
|
2073
|
+
text: "#123a5e",
|
|
2074
|
+
// blueprint navy ink
|
|
2075
|
+
textMuted: "#4f7390",
|
|
2076
|
+
// faint draft note
|
|
2077
|
+
textOnFillLight: "#f4f8fb",
|
|
2078
|
+
// drafting white
|
|
2079
|
+
textOnFillDark: "#0c2f4d",
|
|
2080
|
+
// deep blueprint navy
|
|
2081
|
+
primary: "#1f5e8c",
|
|
2082
|
+
// blueprint blue
|
|
2083
|
+
secondary: "#5b7d96",
|
|
2084
|
+
// steel
|
|
2085
|
+
accent: "#b08a3e",
|
|
2086
|
+
// draftsman's ochre highlight
|
|
2087
|
+
destructive: "#c0504d",
|
|
2088
|
+
// correction red
|
|
2089
|
+
colors: {
|
|
2090
|
+
red: "#c25a4e",
|
|
2091
|
+
// correction red
|
|
2092
|
+
orange: "#c2823e",
|
|
2093
|
+
// ochre
|
|
2094
|
+
yellow: "#c2a843",
|
|
2095
|
+
// pencil gold
|
|
2096
|
+
green: "#4f8a6b",
|
|
2097
|
+
// drafting green
|
|
2098
|
+
blue: "#1f5e8c",
|
|
2099
|
+
// blueprint blue
|
|
2100
|
+
purple: "#6f5e96",
|
|
2101
|
+
// indigo pencil
|
|
2102
|
+
teal: "#3a8a8a",
|
|
2103
|
+
// teal
|
|
2104
|
+
cyan: "#3f8fb5",
|
|
2105
|
+
// cyan
|
|
2106
|
+
gray: "#7e8e98",
|
|
2107
|
+
// graphite
|
|
2108
|
+
black: "#123a5e",
|
|
2109
|
+
// navy ink
|
|
2110
|
+
white: "#e6eef4"
|
|
2111
|
+
// panel
|
|
2112
|
+
}
|
|
2113
|
+
},
|
|
2114
|
+
dark: {
|
|
2115
|
+
bg: "#103a5e",
|
|
2116
|
+
// deep blueprint blue (cyanotype ground)
|
|
2117
|
+
surface: "#16466e",
|
|
2118
|
+
// raised sheet
|
|
2119
|
+
overlay: "#1c5180",
|
|
2120
|
+
// popovers, dropdowns
|
|
2121
|
+
border: "#3a6f96",
|
|
2122
|
+
// grid line
|
|
2123
|
+
text: "#eaf2f8",
|
|
2124
|
+
// chalk white
|
|
2125
|
+
textMuted: "#9fc0d6",
|
|
2126
|
+
// faint chalk note
|
|
2127
|
+
textOnFillLight: "#eaf2f8",
|
|
2128
|
+
// chalk white
|
|
2129
|
+
textOnFillDark: "#0c2f4d",
|
|
2130
|
+
// deep blueprint navy
|
|
2131
|
+
primary: "#7fb8d8",
|
|
2132
|
+
// chalk cyan
|
|
2133
|
+
secondary: "#9fb8c8",
|
|
2134
|
+
// pale steel
|
|
2135
|
+
accent: "#d8c27a",
|
|
2136
|
+
// chalk amber
|
|
2137
|
+
destructive: "#e08a7a",
|
|
2138
|
+
// chalk correction red
|
|
2139
|
+
colors: {
|
|
2140
|
+
red: "#e0907e",
|
|
2141
|
+
// chalk red
|
|
2142
|
+
orange: "#e0ab78",
|
|
2143
|
+
// chalk amber
|
|
2144
|
+
yellow: "#e3d089",
|
|
2145
|
+
// chalk gold
|
|
2146
|
+
green: "#93c79e",
|
|
2147
|
+
// chalk green
|
|
2148
|
+
blue: "#8ec3e0",
|
|
2149
|
+
// chalk cyan-blue
|
|
2150
|
+
purple: "#b6a6d8",
|
|
2151
|
+
// chalk indigo
|
|
2152
|
+
teal: "#84c7c2",
|
|
2153
|
+
// chalk teal
|
|
2154
|
+
cyan: "#9fd6e0",
|
|
2155
|
+
// chalk cyan
|
|
2156
|
+
gray: "#aebecb",
|
|
2157
|
+
// chalk graphite
|
|
2158
|
+
black: "#16466e",
|
|
2159
|
+
// raised sheet
|
|
2160
|
+
white: "#eaf2f8"
|
|
2161
|
+
// chalk white
|
|
2162
|
+
}
|
|
2163
|
+
}
|
|
2164
|
+
};
|
|
2165
|
+
registerPalette(blueprintPalette);
|
|
1974
2166
|
}
|
|
1975
2167
|
});
|
|
1976
2168
|
|
|
@@ -2467,6 +2659,120 @@ var init_rose_pine = __esm({
|
|
|
2467
2659
|
}
|
|
2468
2660
|
});
|
|
2469
2661
|
|
|
2662
|
+
// src/palettes/slate.ts
|
|
2663
|
+
var slatePalette;
|
|
2664
|
+
var init_slate = __esm({
|
|
2665
|
+
"src/palettes/slate.ts"() {
|
|
2666
|
+
"use strict";
|
|
2667
|
+
init_registry();
|
|
2668
|
+
slatePalette = {
|
|
2669
|
+
id: "slate",
|
|
2670
|
+
name: "Slate",
|
|
2671
|
+
light: {
|
|
2672
|
+
bg: "#ffffff",
|
|
2673
|
+
// clean slide white
|
|
2674
|
+
surface: "#f3f5f8",
|
|
2675
|
+
// light cool-gray panel
|
|
2676
|
+
overlay: "#eaeef3",
|
|
2677
|
+
// popovers, dropdowns
|
|
2678
|
+
border: "#d4dae1",
|
|
2679
|
+
// hairline rule
|
|
2680
|
+
text: "#1f2933",
|
|
2681
|
+
// near-black slate (softer than pure black)
|
|
2682
|
+
textMuted: "#5b6672",
|
|
2683
|
+
// secondary label
|
|
2684
|
+
textOnFillLight: "#ffffff",
|
|
2685
|
+
// light text on dark fills
|
|
2686
|
+
textOnFillDark: "#1f2933",
|
|
2687
|
+
// dark text on light fills
|
|
2688
|
+
primary: "#3b6ea5",
|
|
2689
|
+
// confident corporate blue
|
|
2690
|
+
secondary: "#5b6672",
|
|
2691
|
+
// slate gray
|
|
2692
|
+
accent: "#3a9188",
|
|
2693
|
+
// muted teal accent
|
|
2694
|
+
destructive: "#c0504d",
|
|
2695
|
+
// brick red
|
|
2696
|
+
colors: {
|
|
2697
|
+
red: "#c0504d",
|
|
2698
|
+
// brick
|
|
2699
|
+
orange: "#cc7a33",
|
|
2700
|
+
// muted amber
|
|
2701
|
+
yellow: "#c9a227",
|
|
2702
|
+
// gold (not neon)
|
|
2703
|
+
green: "#5b9357",
|
|
2704
|
+
// forest / sage
|
|
2705
|
+
blue: "#3b6ea5",
|
|
2706
|
+
// corporate blue
|
|
2707
|
+
purple: "#7d5ba6",
|
|
2708
|
+
// muted violet
|
|
2709
|
+
teal: "#3a9188",
|
|
2710
|
+
// teal
|
|
2711
|
+
cyan: "#4f96c4",
|
|
2712
|
+
// steel cyan
|
|
2713
|
+
gray: "#7e8a97",
|
|
2714
|
+
// cool gray
|
|
2715
|
+
black: "#1f2933",
|
|
2716
|
+
// slate ink
|
|
2717
|
+
white: "#f3f5f8"
|
|
2718
|
+
// panel
|
|
2719
|
+
}
|
|
2720
|
+
},
|
|
2721
|
+
dark: {
|
|
2722
|
+
bg: "#161b22",
|
|
2723
|
+
// deep slate (keynote dark)
|
|
2724
|
+
surface: "#202833",
|
|
2725
|
+
// raised panel
|
|
2726
|
+
overlay: "#29323e",
|
|
2727
|
+
// popovers, dropdowns
|
|
2728
|
+
border: "#38424f",
|
|
2729
|
+
// divider
|
|
2730
|
+
text: "#e6eaef",
|
|
2731
|
+
// off-white
|
|
2732
|
+
textMuted: "#9aa5b1",
|
|
2733
|
+
// secondary label
|
|
2734
|
+
textOnFillLight: "#ffffff",
|
|
2735
|
+
// light text on dark fills
|
|
2736
|
+
textOnFillDark: "#161b22",
|
|
2737
|
+
// dark text on light fills
|
|
2738
|
+
primary: "#5b9bd5",
|
|
2739
|
+
// lifted corporate blue
|
|
2740
|
+
secondary: "#8593a3",
|
|
2741
|
+
// slate gray, lifted
|
|
2742
|
+
accent: "#45b3a3",
|
|
2743
|
+
// teal, lifted
|
|
2744
|
+
destructive: "#e07b6e",
|
|
2745
|
+
// brick, lifted
|
|
2746
|
+
colors: {
|
|
2747
|
+
red: "#e07b6e",
|
|
2748
|
+
// brick
|
|
2749
|
+
orange: "#e0975a",
|
|
2750
|
+
// amber
|
|
2751
|
+
yellow: "#d9bd5a",
|
|
2752
|
+
// gold
|
|
2753
|
+
green: "#74b56e",
|
|
2754
|
+
// forest / sage
|
|
2755
|
+
blue: "#5b9bd5",
|
|
2756
|
+
// corporate blue
|
|
2757
|
+
purple: "#a585c9",
|
|
2758
|
+
// violet
|
|
2759
|
+
teal: "#45b3a3",
|
|
2760
|
+
// teal
|
|
2761
|
+
cyan: "#62b0d9",
|
|
2762
|
+
// steel cyan
|
|
2763
|
+
gray: "#95a1ae",
|
|
2764
|
+
// cool gray
|
|
2765
|
+
black: "#202833",
|
|
2766
|
+
// raised panel
|
|
2767
|
+
white: "#e6eaef"
|
|
2768
|
+
// off-white
|
|
2769
|
+
}
|
|
2770
|
+
}
|
|
2771
|
+
};
|
|
2772
|
+
registerPalette(slatePalette);
|
|
2773
|
+
}
|
|
2774
|
+
});
|
|
2775
|
+
|
|
2470
2776
|
// src/palettes/solarized.ts
|
|
2471
2777
|
var solarizedPalette;
|
|
2472
2778
|
var init_solarized = __esm({
|
|
@@ -2562,6 +2868,120 @@ var init_solarized = __esm({
|
|
|
2562
2868
|
}
|
|
2563
2869
|
});
|
|
2564
2870
|
|
|
2871
|
+
// src/palettes/tidewater.ts
|
|
2872
|
+
var tidewaterPalette;
|
|
2873
|
+
var init_tidewater = __esm({
|
|
2874
|
+
"src/palettes/tidewater.ts"() {
|
|
2875
|
+
"use strict";
|
|
2876
|
+
init_registry();
|
|
2877
|
+
tidewaterPalette = {
|
|
2878
|
+
id: "tidewater",
|
|
2879
|
+
name: "Tidewater",
|
|
2880
|
+
light: {
|
|
2881
|
+
bg: "#eceff0",
|
|
2882
|
+
// weathered sea-mist paper
|
|
2883
|
+
surface: "#e0e4e3",
|
|
2884
|
+
// worn deck panel
|
|
2885
|
+
overlay: "#dadfdf",
|
|
2886
|
+
// popovers, dropdowns
|
|
2887
|
+
border: "#a9b2b3",
|
|
2888
|
+
// muted slate rule
|
|
2889
|
+
text: "#18313f",
|
|
2890
|
+
// ship's-log navy ink
|
|
2891
|
+
textMuted: "#51636b",
|
|
2892
|
+
// faded log entry
|
|
2893
|
+
textOnFillLight: "#f3f5f3",
|
|
2894
|
+
// weathered white
|
|
2895
|
+
textOnFillDark: "#162c38",
|
|
2896
|
+
// deep navy
|
|
2897
|
+
primary: "#1f4e6b",
|
|
2898
|
+
// deep-sea navy
|
|
2899
|
+
secondary: "#b08a4f",
|
|
2900
|
+
// rope / manila tan
|
|
2901
|
+
accent: "#c69a3e",
|
|
2902
|
+
// brass
|
|
2903
|
+
destructive: "#c1433a",
|
|
2904
|
+
// signal-flag red
|
|
2905
|
+
colors: {
|
|
2906
|
+
red: "#c1433a",
|
|
2907
|
+
// signal-flag red
|
|
2908
|
+
orange: "#cc7a38",
|
|
2909
|
+
// weathered amber
|
|
2910
|
+
yellow: "#d6bf5a",
|
|
2911
|
+
// brass gold
|
|
2912
|
+
green: "#4f8a6b",
|
|
2913
|
+
// sea-glass green
|
|
2914
|
+
blue: "#1f4e6b",
|
|
2915
|
+
// deep-sea navy
|
|
2916
|
+
purple: "#6a5a8c",
|
|
2917
|
+
// twilight harbor
|
|
2918
|
+
teal: "#3d8c8c",
|
|
2919
|
+
// sea-glass teal
|
|
2920
|
+
cyan: "#4f9bb5",
|
|
2921
|
+
// shallow water
|
|
2922
|
+
gray: "#8a8d86",
|
|
2923
|
+
// driftwood gray
|
|
2924
|
+
black: "#18313f",
|
|
2925
|
+
// navy ink
|
|
2926
|
+
white: "#e0e4e3"
|
|
2927
|
+
// deck panel
|
|
2928
|
+
}
|
|
2929
|
+
},
|
|
2930
|
+
dark: {
|
|
2931
|
+
bg: "#0f2230",
|
|
2932
|
+
// night-harbor deep sea
|
|
2933
|
+
surface: "#16303f",
|
|
2934
|
+
// raised hull
|
|
2935
|
+
overlay: "#1d3a4a",
|
|
2936
|
+
// popovers, dropdowns
|
|
2937
|
+
border: "#2c4856",
|
|
2938
|
+
// rigging line
|
|
2939
|
+
text: "#e6ebe8",
|
|
2940
|
+
// weathered white
|
|
2941
|
+
textMuted: "#9aaab0",
|
|
2942
|
+
// faded label
|
|
2943
|
+
textOnFillLight: "#f3f5f3",
|
|
2944
|
+
// weathered white
|
|
2945
|
+
textOnFillDark: "#0f2230",
|
|
2946
|
+
// deep sea
|
|
2947
|
+
primary: "#4f9bc4",
|
|
2948
|
+
// lifted sea blue
|
|
2949
|
+
secondary: "#c9a46a",
|
|
2950
|
+
// rope tan, lifted
|
|
2951
|
+
accent: "#d9b25a",
|
|
2952
|
+
// brass, lifted
|
|
2953
|
+
destructive: "#e06a5e",
|
|
2954
|
+
// signal red, lifted
|
|
2955
|
+
colors: {
|
|
2956
|
+
red: "#e06a5e",
|
|
2957
|
+
// signal-flag red
|
|
2958
|
+
orange: "#df9a52",
|
|
2959
|
+
// amber
|
|
2960
|
+
yellow: "#e0c662",
|
|
2961
|
+
// brass gold
|
|
2962
|
+
green: "#6fb58c",
|
|
2963
|
+
// sea-glass green
|
|
2964
|
+
blue: "#4f9bc4",
|
|
2965
|
+
// sea blue
|
|
2966
|
+
purple: "#9486bf",
|
|
2967
|
+
// twilight harbor
|
|
2968
|
+
teal: "#5cb0ac",
|
|
2969
|
+
// sea-glass teal
|
|
2970
|
+
cyan: "#62b4cf",
|
|
2971
|
+
// shallow water
|
|
2972
|
+
gray: "#9aa39c",
|
|
2973
|
+
// driftwood gray
|
|
2974
|
+
black: "#16303f",
|
|
2975
|
+
// raised hull
|
|
2976
|
+
white: "#e6ebe8"
|
|
2977
|
+
// weathered white
|
|
2978
|
+
}
|
|
2979
|
+
}
|
|
2980
|
+
};
|
|
2981
|
+
registerPalette(tidewaterPalette);
|
|
2982
|
+
}
|
|
2983
|
+
});
|
|
2984
|
+
|
|
2565
2985
|
// src/palettes/tokyo-night.ts
|
|
2566
2986
|
var tokyoNightPalette;
|
|
2567
2987
|
var init_tokyo_night = __esm({
|
|
@@ -2837,7 +3257,8 @@ var init_monokai = __esm({
|
|
|
2837
3257
|
// src/palettes/index.ts
|
|
2838
3258
|
var palettes_exports = {};
|
|
2839
3259
|
__export(palettes_exports, {
|
|
2840
|
-
|
|
3260
|
+
atlasPalette: () => atlasPalette,
|
|
3261
|
+
blueprintPalette: () => blueprintPalette,
|
|
2841
3262
|
catppuccinPalette: () => catppuccinPalette,
|
|
2842
3263
|
contrastText: () => contrastText,
|
|
2843
3264
|
draculaPalette: () => draculaPalette,
|
|
@@ -2858,7 +3279,9 @@ __export(palettes_exports, {
|
|
|
2858
3279
|
rosePinePalette: () => rosePinePalette,
|
|
2859
3280
|
shade: () => shade,
|
|
2860
3281
|
shapeFill: () => shapeFill,
|
|
3282
|
+
slatePalette: () => slatePalette,
|
|
2861
3283
|
solarizedPalette: () => solarizedPalette,
|
|
3284
|
+
tidewaterPalette: () => tidewaterPalette,
|
|
2862
3285
|
tint: () => tint,
|
|
2863
3286
|
tokyoNightPalette: () => tokyoNightPalette
|
|
2864
3287
|
});
|
|
@@ -2868,17 +3291,21 @@ var init_palettes = __esm({
|
|
|
2868
3291
|
"use strict";
|
|
2869
3292
|
init_registry();
|
|
2870
3293
|
init_color_utils();
|
|
2871
|
-
|
|
3294
|
+
init_atlas();
|
|
3295
|
+
init_blueprint();
|
|
2872
3296
|
init_catppuccin();
|
|
2873
3297
|
init_gruvbox();
|
|
2874
3298
|
init_nord();
|
|
2875
3299
|
init_one_dark();
|
|
2876
3300
|
init_rose_pine();
|
|
3301
|
+
init_slate();
|
|
2877
3302
|
init_solarized();
|
|
3303
|
+
init_tidewater();
|
|
2878
3304
|
init_tokyo_night();
|
|
2879
3305
|
init_dracula();
|
|
2880
3306
|
init_monokai();
|
|
2881
|
-
|
|
3307
|
+
init_atlas();
|
|
3308
|
+
init_blueprint();
|
|
2882
3309
|
init_catppuccin();
|
|
2883
3310
|
init_dracula();
|
|
2884
3311
|
init_gruvbox();
|
|
@@ -2886,9 +3313,15 @@ var init_palettes = __esm({
|
|
|
2886
3313
|
init_nord();
|
|
2887
3314
|
init_one_dark();
|
|
2888
3315
|
init_rose_pine();
|
|
3316
|
+
init_slate();
|
|
2889
3317
|
init_solarized();
|
|
3318
|
+
init_tidewater();
|
|
2890
3319
|
init_tokyo_night();
|
|
2891
3320
|
palettes = {
|
|
3321
|
+
atlas: atlasPalette,
|
|
3322
|
+
blueprint: blueprintPalette,
|
|
3323
|
+
slate: slatePalette,
|
|
3324
|
+
tidewater: tidewaterPalette,
|
|
2892
3325
|
nord: nordPalette,
|
|
2893
3326
|
catppuccin: catppuccinPalette,
|
|
2894
3327
|
solarized: solarizedPalette,
|
|
@@ -2897,8 +3330,7 @@ var init_palettes = __esm({
|
|
|
2897
3330
|
oneDark: oneDarkPalette,
|
|
2898
3331
|
rosePine: rosePinePalette,
|
|
2899
3332
|
dracula: draculaPalette,
|
|
2900
|
-
monokai: monokaiPalette
|
|
2901
|
-
bold: boldPalette
|
|
3333
|
+
monokai: monokaiPalette
|
|
2902
3334
|
};
|
|
2903
3335
|
}
|
|
2904
3336
|
});
|
|
@@ -3408,6 +3840,9 @@ function controlsGroupCapsuleWidth(toggles) {
|
|
|
3408
3840
|
}
|
|
3409
3841
|
return w;
|
|
3410
3842
|
}
|
|
3843
|
+
function isAppHostedControls(config, isExport) {
|
|
3844
|
+
return !isExport && config.controlsHost === "app" && !!config.controlsGroup && config.controlsGroup.toggles.length > 0;
|
|
3845
|
+
}
|
|
3411
3846
|
function buildControlsGroupLayout(config, state) {
|
|
3412
3847
|
const cg = config.controlsGroup;
|
|
3413
3848
|
if (!cg || cg.toggles.length === 0) return void 0;
|
|
@@ -3461,6 +3896,7 @@ function buildControlsGroupLayout(config, state) {
|
|
|
3461
3896
|
function computeLegendLayout(config, state, containerWidth) {
|
|
3462
3897
|
const { groups, controls: configControls, mode } = config;
|
|
3463
3898
|
const isExport = mode === "export";
|
|
3899
|
+
const gated = isAppHostedControls(config, isExport);
|
|
3464
3900
|
const activeGroupName = state.activeGroup?.toLowerCase() ?? null;
|
|
3465
3901
|
if (isExport && !activeGroupName) {
|
|
3466
3902
|
return {
|
|
@@ -3471,7 +3907,7 @@ function computeLegendLayout(config, state, containerWidth) {
|
|
|
3471
3907
|
pills: []
|
|
3472
3908
|
};
|
|
3473
3909
|
}
|
|
3474
|
-
const controlsGroupLayout = isExport ? void 0 : buildControlsGroupLayout(config, state);
|
|
3910
|
+
const controlsGroupLayout = isExport || gated ? void 0 : buildControlsGroupLayout(config, state);
|
|
3475
3911
|
const visibleGroups = config.showEmptyGroups ? groups : groups.filter((g) => g.entries.length > 0 || !!g.gradient);
|
|
3476
3912
|
if (visibleGroups.length === 0 && (!configControls || configControls.length === 0) && !controlsGroupLayout) {
|
|
3477
3913
|
return {
|
|
@@ -8351,8 +8787,8 @@ function computeScatterLabelGraphics(points, chartBounds, fontSize, symbolSize,
|
|
|
8351
8787
|
const pt = points[i];
|
|
8352
8788
|
const ptSize = pt.size ?? symbolSize;
|
|
8353
8789
|
const minGap = ptSize / 2 + 4;
|
|
8354
|
-
const
|
|
8355
|
-
const labelX = pt.px -
|
|
8790
|
+
const labelWidth2 = pt.name.length * fontSize * 0.6 + 8;
|
|
8791
|
+
const labelX = pt.px - labelWidth2 / 2;
|
|
8356
8792
|
let bestLabelY = 0;
|
|
8357
8793
|
let bestOffset = Infinity;
|
|
8358
8794
|
let placed = false;
|
|
@@ -8364,7 +8800,7 @@ function computeScatterLabelGraphics(points, chartBounds, fontSize, symbolSize,
|
|
|
8364
8800
|
const candidate = {
|
|
8365
8801
|
x: labelX,
|
|
8366
8802
|
y: labelY,
|
|
8367
|
-
w:
|
|
8803
|
+
w: labelWidth2,
|
|
8368
8804
|
h: labelHeight
|
|
8369
8805
|
};
|
|
8370
8806
|
let collision = false;
|
|
@@ -8406,7 +8842,7 @@ function computeScatterLabelGraphics(points, chartBounds, fontSize, symbolSize,
|
|
|
8406
8842
|
const labelRect = {
|
|
8407
8843
|
x: labelX,
|
|
8408
8844
|
y: bestLabelY,
|
|
8409
|
-
w:
|
|
8845
|
+
w: labelWidth2,
|
|
8410
8846
|
h: labelHeight
|
|
8411
8847
|
};
|
|
8412
8848
|
placedLabels.push(labelRect);
|
|
@@ -8442,7 +8878,7 @@ function computeScatterLabelGraphics(points, chartBounds, fontSize, symbolSize,
|
|
|
8442
8878
|
shape: {
|
|
8443
8879
|
x: labelX - bgPad,
|
|
8444
8880
|
y: bestLabelY - bgPad,
|
|
8445
|
-
width:
|
|
8881
|
+
width: labelWidth2 + bgPad * 2,
|
|
8446
8882
|
height: labelHeight + bgPad * 2
|
|
8447
8883
|
},
|
|
8448
8884
|
style: { fill: bg },
|
|
@@ -15882,10 +16318,6 @@ function parseMap(content) {
|
|
|
15882
16318
|
handleTag(trimmed, lineNumber);
|
|
15883
16319
|
continue;
|
|
15884
16320
|
}
|
|
15885
|
-
if ((firstWord === "muted" || firstWord === "natural") && trimmed === firstWord) {
|
|
15886
|
-
handleDirective(firstWord, "", lineNumber);
|
|
15887
|
-
continue;
|
|
15888
|
-
}
|
|
15889
16321
|
if (DIRECTIVE_SET.has(firstWord) && !trimmed.slice(firstWord.length).trimStart().startsWith(":")) {
|
|
15890
16322
|
handleDirective(
|
|
15891
16323
|
firstWord,
|
|
@@ -15932,28 +16364,13 @@ function parseMap(content) {
|
|
|
15932
16364
|
pushWarning(line12, `Duplicate directive "${key}" \u2014 last value wins.`);
|
|
15933
16365
|
};
|
|
15934
16366
|
switch (key) {
|
|
15935
|
-
case "region":
|
|
15936
|
-
dup(d.region);
|
|
15937
|
-
d.region = value;
|
|
15938
|
-
break;
|
|
15939
|
-
case "projection":
|
|
15940
|
-
dup(d.projection);
|
|
15941
|
-
if (value && ![
|
|
15942
|
-
"equirectangular",
|
|
15943
|
-
"natural-earth",
|
|
15944
|
-
"albers-usa",
|
|
15945
|
-
"mercator"
|
|
15946
|
-
].includes(value))
|
|
15947
|
-
pushWarning(
|
|
15948
|
-
line12,
|
|
15949
|
-
`Unknown projection "${value}" (expected equirectangular | natural-earth | albers-usa | mercator).`
|
|
15950
|
-
);
|
|
15951
|
-
d.projection = value;
|
|
15952
|
-
break;
|
|
15953
|
-
case "region-metric":
|
|
16367
|
+
case "region-metric": {
|
|
15954
16368
|
dup(d.regionMetric);
|
|
15955
|
-
|
|
16369
|
+
const { label: rmLabel, colorName: rmColor } = peelTrailingColorName(value);
|
|
16370
|
+
d.regionMetric = rmLabel;
|
|
16371
|
+
if (rmColor) d.regionMetricColor = rmColor;
|
|
15956
16372
|
break;
|
|
16373
|
+
}
|
|
15957
16374
|
case "poi-metric":
|
|
15958
16375
|
dup(d.poiMetric);
|
|
15959
16376
|
d.poiMetric = value;
|
|
@@ -15962,85 +16379,43 @@ function parseMap(content) {
|
|
|
15962
16379
|
dup(d.flowMetric);
|
|
15963
16380
|
d.flowMetric = value;
|
|
15964
16381
|
break;
|
|
15965
|
-
case "
|
|
15966
|
-
dup(d.
|
|
15967
|
-
|
|
15968
|
-
const s = parseScale(value, line12);
|
|
15969
|
-
if (s) d.scale = s;
|
|
15970
|
-
}
|
|
15971
|
-
break;
|
|
15972
|
-
case "region-labels":
|
|
15973
|
-
dup(d.regionLabels);
|
|
15974
|
-
if (value && !["full", "abbrev", "off"].includes(value))
|
|
15975
|
-
pushWarning(
|
|
15976
|
-
line12,
|
|
15977
|
-
`Unknown region-labels "${value}" (expected full | abbrev | off).`
|
|
15978
|
-
);
|
|
15979
|
-
d.regionLabels = value;
|
|
15980
|
-
break;
|
|
15981
|
-
case "poi-labels":
|
|
15982
|
-
dup(d.poiLabels);
|
|
15983
|
-
if (value && !["off", "auto", "all"].includes(value))
|
|
15984
|
-
pushWarning(
|
|
15985
|
-
line12,
|
|
15986
|
-
`Unknown poi-labels "${value}" (expected off | auto | all).`
|
|
15987
|
-
);
|
|
15988
|
-
d.poiLabels = value;
|
|
15989
|
-
break;
|
|
15990
|
-
case "default-country":
|
|
15991
|
-
dup(d.defaultCountry);
|
|
15992
|
-
d.defaultCountry = value;
|
|
15993
|
-
break;
|
|
15994
|
-
case "default-state":
|
|
15995
|
-
dup(d.defaultState);
|
|
15996
|
-
d.defaultState = value;
|
|
16382
|
+
case "locale":
|
|
16383
|
+
dup(d.locale);
|
|
16384
|
+
d.locale = value;
|
|
15997
16385
|
break;
|
|
15998
16386
|
case "active-tag":
|
|
15999
16387
|
dup(d.activeTag);
|
|
16000
16388
|
d.activeTag = value;
|
|
16001
16389
|
break;
|
|
16390
|
+
case "caption":
|
|
16391
|
+
dup(d.caption);
|
|
16392
|
+
d.caption = value;
|
|
16393
|
+
break;
|
|
16394
|
+
// ── Cosmetic `no-*` opt-outs: bare flags, idempotent (mirror `no-legend`,
|
|
16395
|
+
// no dup warning); each defaults the feature ON when absent. ──
|
|
16002
16396
|
case "no-legend":
|
|
16003
16397
|
d.noLegend = true;
|
|
16004
16398
|
break;
|
|
16005
|
-
case "
|
|
16006
|
-
|
|
16007
|
-
if (d.basemapStyle !== void 0 && d.basemapStyle !== key)
|
|
16008
|
-
pushWarning(
|
|
16009
|
-
line12,
|
|
16010
|
-
`Conflicting basemap dress \u2014 "${d.basemapStyle}" then "${key}"; last wins.`
|
|
16011
|
-
);
|
|
16012
|
-
d.basemapStyle = key;
|
|
16399
|
+
case "no-coastline":
|
|
16400
|
+
d.noCoastline = true;
|
|
16013
16401
|
break;
|
|
16014
|
-
case "
|
|
16015
|
-
|
|
16016
|
-
d.subtitle = value;
|
|
16402
|
+
case "no-relief":
|
|
16403
|
+
d.noRelief = true;
|
|
16017
16404
|
break;
|
|
16018
|
-
case "
|
|
16019
|
-
|
|
16020
|
-
|
|
16405
|
+
case "no-context-labels":
|
|
16406
|
+
d.noContextLabels = true;
|
|
16407
|
+
break;
|
|
16408
|
+
case "no-region-labels":
|
|
16409
|
+
d.noRegionLabels = true;
|
|
16410
|
+
break;
|
|
16411
|
+
case "no-poi-labels":
|
|
16412
|
+
d.noPoiLabels = true;
|
|
16413
|
+
break;
|
|
16414
|
+
case "no-colorize":
|
|
16415
|
+
d.noColorize = true;
|
|
16021
16416
|
break;
|
|
16022
16417
|
}
|
|
16023
16418
|
}
|
|
16024
|
-
function parseScale(value, line12) {
|
|
16025
|
-
const toks = value.split(/\s+/).filter(Boolean);
|
|
16026
|
-
const min = Number(toks[0]);
|
|
16027
|
-
const max = Number(toks[1]);
|
|
16028
|
-
if (!Number.isFinite(min) || !Number.isFinite(max)) {
|
|
16029
|
-
pushError(line12, `scale requires numeric <min> <max> (got "${value}").`);
|
|
16030
|
-
return null;
|
|
16031
|
-
}
|
|
16032
|
-
const scale = { min, max };
|
|
16033
|
-
if (toks[2] === "center") {
|
|
16034
|
-
const c = Number(toks[3]);
|
|
16035
|
-
if (Number.isFinite(c)) scale.center = c;
|
|
16036
|
-
else
|
|
16037
|
-
pushError(
|
|
16038
|
-
line12,
|
|
16039
|
-
`scale center requires a number (got "${toks[3] ?? ""}").`
|
|
16040
|
-
);
|
|
16041
|
-
}
|
|
16042
|
-
return scale;
|
|
16043
|
-
}
|
|
16044
16419
|
function handleTag(trimmed, line12) {
|
|
16045
16420
|
const m = matchTagBlockHeading(trimmed);
|
|
16046
16421
|
if (!m) {
|
|
@@ -16114,6 +16489,7 @@ function parseMap(content) {
|
|
|
16114
16489
|
};
|
|
16115
16490
|
if (regionScope !== void 0) region.scope = regionScope;
|
|
16116
16491
|
if (valueNum !== void 0) region.value = valueNum;
|
|
16492
|
+
if (split.color) region.color = split.color;
|
|
16117
16493
|
regions.push(region);
|
|
16118
16494
|
}
|
|
16119
16495
|
function handlePoi(rest, line12, indent) {
|
|
@@ -16138,6 +16514,7 @@ function parseMap(content) {
|
|
|
16138
16514
|
const poi = { pos, tags, meta, lineNumber: line12 };
|
|
16139
16515
|
if (split.alias) poi.alias = split.alias;
|
|
16140
16516
|
if (label !== void 0) poi.label = label;
|
|
16517
|
+
if (split.color) poi.color = split.color;
|
|
16141
16518
|
pois.push(poi);
|
|
16142
16519
|
open.poi = { poi, indent };
|
|
16143
16520
|
}
|
|
@@ -16238,13 +16615,15 @@ function parseMap(content) {
|
|
|
16238
16615
|
pushError(line12, `Edge has an empty endpoint: "${trimmed}".`);
|
|
16239
16616
|
continue;
|
|
16240
16617
|
}
|
|
16241
|
-
const
|
|
16618
|
+
const isLast = k === links.length - 1;
|
|
16619
|
+
const meta = isLast ? lastSplit.meta : {};
|
|
16620
|
+
const style = links[k].style === "arc" ? "arc" : "straight";
|
|
16242
16621
|
edges.push({
|
|
16243
16622
|
from,
|
|
16244
16623
|
to,
|
|
16245
16624
|
...links[k].label !== void 0 && { label: links[k].label },
|
|
16246
16625
|
directed: links[k].directed,
|
|
16247
|
-
style
|
|
16626
|
+
style,
|
|
16248
16627
|
meta,
|
|
16249
16628
|
lineNumber: line12
|
|
16250
16629
|
});
|
|
@@ -16330,20 +16709,19 @@ var init_parser12 = __esm({
|
|
|
16330
16709
|
LEG_ARROW_RE = /^(-[^>]*?->|->|~[^>]*?~>|~>|--)\s+(.+)$/;
|
|
16331
16710
|
AT_RE = /(^|[\s,])at\s*:/i;
|
|
16332
16711
|
DIRECTIVE_SET = /* @__PURE__ */ new Set([
|
|
16333
|
-
"region",
|
|
16334
|
-
"projection",
|
|
16335
16712
|
"region-metric",
|
|
16336
16713
|
"poi-metric",
|
|
16337
16714
|
"flow-metric",
|
|
16338
|
-
"
|
|
16339
|
-
"region-labels",
|
|
16340
|
-
"poi-labels",
|
|
16341
|
-
"default-country",
|
|
16342
|
-
"default-state",
|
|
16715
|
+
"locale",
|
|
16343
16716
|
"active-tag",
|
|
16717
|
+
"caption",
|
|
16344
16718
|
"no-legend",
|
|
16345
|
-
"
|
|
16346
|
-
"
|
|
16719
|
+
"no-coastline",
|
|
16720
|
+
"no-relief",
|
|
16721
|
+
"no-context-labels",
|
|
16722
|
+
"no-region-labels",
|
|
16723
|
+
"no-poi-labels",
|
|
16724
|
+
"no-colorize"
|
|
16347
16725
|
]);
|
|
16348
16726
|
}
|
|
16349
16727
|
});
|
|
@@ -24264,8 +24642,8 @@ function renderKanban(container, parsed, palette, isDark, options) {
|
|
|
24264
24642
|
let metaY = separatorY + sCardSeparatorGap + sCardMetaFontSize;
|
|
24265
24643
|
for (const meta of tagMeta) {
|
|
24266
24644
|
cg.append("text").attr("x", cx + sCardPaddingX).attr("y", metaY).attr("font-size", sCardMetaFontSize).attr("fill", onCardText).text(`${meta.label}: `);
|
|
24267
|
-
const
|
|
24268
|
-
cg.append("text").attr("x", cx + sCardPaddingX +
|
|
24645
|
+
const labelWidth2 = (meta.label.length + 2) * sCardMetaFontSize * 0.6;
|
|
24646
|
+
cg.append("text").attr("x", cx + sCardPaddingX + labelWidth2).attr("y", metaY).attr("font-size", sCardMetaFontSize).attr("fill", onCardText).text(meta.value);
|
|
24269
24647
|
metaY += sCardMetaLineHeight;
|
|
24270
24648
|
}
|
|
24271
24649
|
for (const detail of card.details) {
|
|
@@ -24609,8 +24987,8 @@ function renderSwimlaneCard(parent, cardLayout, tagGroups, activeTagGroup, palet
|
|
|
24609
24987
|
let metaY = separatorY + sCardSeparatorGap + sCardMetaFontSize;
|
|
24610
24988
|
for (const meta of tagMeta) {
|
|
24611
24989
|
cg.append("text").attr("x", cx + sCardPaddingX).attr("y", metaY).attr("font-size", sCardMetaFontSize).attr("fill", palette.textMuted).text(`${meta.label}: `);
|
|
24612
|
-
const
|
|
24613
|
-
cg.append("text").attr("x", cx + sCardPaddingX +
|
|
24990
|
+
const labelWidth2 = (meta.label.length + 2) * sCardMetaFontSize * 0.6;
|
|
24991
|
+
cg.append("text").attr("x", cx + sCardPaddingX + labelWidth2).attr("y", metaY).attr("font-size", sCardMetaFontSize).attr("fill", onCardText).text(meta.value);
|
|
24614
24992
|
metaY += sCardMetaLineHeight;
|
|
24615
24993
|
}
|
|
24616
24994
|
for (const detail of card.details) {
|
|
@@ -25445,8 +25823,8 @@ function classifyEREntities(tables, relationships) {
|
|
|
25445
25823
|
}
|
|
25446
25824
|
}
|
|
25447
25825
|
const mmParticipants = /* @__PURE__ */ new Set();
|
|
25448
|
-
for (const [id,
|
|
25449
|
-
if (
|
|
25826
|
+
for (const [id, neighbors2] of tableStarNeighbors) {
|
|
25827
|
+
if (neighbors2.size >= 2) mmParticipants.add(id);
|
|
25450
25828
|
}
|
|
25451
25829
|
const indegreeValues = Object.values(indegreeMap);
|
|
25452
25830
|
const mean = indegreeValues.reduce((a, b) => a + b, 0) / indegreeValues.length;
|
|
@@ -26117,7 +26495,8 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26117
26495
|
controlsExpanded,
|
|
26118
26496
|
onToggleDescriptions,
|
|
26119
26497
|
onToggleControlsExpand,
|
|
26120
|
-
exportMode = false
|
|
26498
|
+
exportMode = false,
|
|
26499
|
+
controlsHost
|
|
26121
26500
|
} = options ?? {};
|
|
26122
26501
|
d3Selection6.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
26123
26502
|
const width = exportDims?.width ?? container.clientWidth;
|
|
@@ -26135,7 +26514,11 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26135
26514
|
const sGroupLabelZone = sctx.structural(GROUP_LABEL_ZONE);
|
|
26136
26515
|
const sTitleFontSize = sctx.text(TITLE_FONT_SIZE);
|
|
26137
26516
|
const sTitleY = sctx.structural(TITLE_Y);
|
|
26138
|
-
const
|
|
26517
|
+
const reserveHasDescriptions = parsed.nodes.some(
|
|
26518
|
+
(n) => n.description && n.description.length > 0
|
|
26519
|
+
);
|
|
26520
|
+
const willRenderLegend = parsed.tagGroups.length > 0 || reserveHasDescriptions && controlsHost !== "app";
|
|
26521
|
+
const sLegendHeight = willRenderLegend ? sctx.structural(
|
|
26139
26522
|
getMaxLegendReservedHeight(
|
|
26140
26523
|
{
|
|
26141
26524
|
groups: parsed.tagGroups,
|
|
@@ -26144,7 +26527,7 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26144
26527
|
},
|
|
26145
26528
|
width
|
|
26146
26529
|
)
|
|
26147
|
-
);
|
|
26530
|
+
) : 0;
|
|
26148
26531
|
const activeGroup = resolveActiveTagGroup(
|
|
26149
26532
|
parsed.tagGroups,
|
|
26150
26533
|
parsed.options["active-tag"],
|
|
@@ -26459,10 +26842,10 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26459
26842
|
const hasDescriptions = parsed.nodes.some(
|
|
26460
26843
|
(n) => n.description && n.description.length > 0
|
|
26461
26844
|
);
|
|
26462
|
-
const hasLegend = parsed.tagGroups.length > 0 || hasDescriptions;
|
|
26845
|
+
const hasLegend = parsed.tagGroups.length > 0 || hasDescriptions && controlsHost !== "app";
|
|
26463
26846
|
if (hasLegend) {
|
|
26464
26847
|
let controlsGroup;
|
|
26465
|
-
if (hasDescriptions && onToggleDescriptions) {
|
|
26848
|
+
if (hasDescriptions && (onToggleDescriptions || controlsHost === "app")) {
|
|
26466
26849
|
controlsGroup = {
|
|
26467
26850
|
toggles: [
|
|
26468
26851
|
{
|
|
@@ -26480,7 +26863,14 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26480
26863
|
groups: parsed.tagGroups,
|
|
26481
26864
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
26482
26865
|
mode: exportMode ? "export" : "preview",
|
|
26483
|
-
|
|
26866
|
+
// Keep inactive sibling tag groups visible as collapsed pills so the user
|
|
26867
|
+
// can click one to flip the active colouring dimension (preview only —
|
|
26868
|
+
// export shows just the active group). Without this, declaring a second
|
|
26869
|
+
// tag group (e.g. Team) leaves it invisible whenever another group is
|
|
26870
|
+
// active. The app's BoxesAndLinesPreview already wires pill clicks.
|
|
26871
|
+
showInactivePills: true,
|
|
26872
|
+
...controlsGroup !== void 0 && { controlsGroup },
|
|
26873
|
+
...controlsHost !== void 0 && { controlsHost }
|
|
26484
26874
|
};
|
|
26485
26875
|
const legendState = {
|
|
26486
26876
|
activeGroup,
|
|
@@ -27728,8 +28118,9 @@ function renderMindmap(container, parsed, layout, palette, isDark, onClickItem,
|
|
|
27728
28118
|
const containerHeight = exportDims?.height ?? (container.getBoundingClientRect().height || 600);
|
|
27729
28119
|
d3Selection7.select(container).selectAll("*").remove();
|
|
27730
28120
|
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);
|
|
28121
|
+
const appHosted = options?.controlsHost === "app";
|
|
27731
28122
|
const hasControls = !!options?.onToggleColorByDepth || !!options?.onToggleDescriptions;
|
|
27732
|
-
const hasLegend = parsed.tagGroups.length > 0 || hasControls;
|
|
28123
|
+
const hasLegend = parsed.tagGroups.length > 0 || hasControls && !appHosted;
|
|
27733
28124
|
const fixedLegend = !isExport && hasLegend;
|
|
27734
28125
|
const legendReserve = fixedLegend ? getMaxLegendReservedHeight(
|
|
27735
28126
|
{
|
|
@@ -27823,7 +28214,10 @@ function renderMindmap(container, parsed, layout, palette, isDark, onClickItem,
|
|
|
27823
28214
|
}),
|
|
27824
28215
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
27825
28216
|
mode: options?.exportMode ? "export" : "preview",
|
|
27826
|
-
...controlsToggles !== void 0 && { controlsGroup: controlsToggles }
|
|
28217
|
+
...controlsToggles !== void 0 && { controlsGroup: controlsToggles },
|
|
28218
|
+
...options?.controlsHost !== void 0 && {
|
|
28219
|
+
controlsHost: options.controlsHost
|
|
28220
|
+
}
|
|
27827
28221
|
};
|
|
27828
28222
|
const legendState = {
|
|
27829
28223
|
activeGroup: options?.colorByDepth ? null : activeTagGroup !== void 0 ? activeTagGroup : parsed.options["active-tag"] ?? null,
|
|
@@ -28267,8 +28661,8 @@ function computeFieldAlignX(children) {
|
|
|
28267
28661
|
for (const child of children) {
|
|
28268
28662
|
if (child.metadata["_labelField"] === "true" && child.children.length >= 2) {
|
|
28269
28663
|
const labelEl = child.children[0];
|
|
28270
|
-
const
|
|
28271
|
-
maxLabelWidth = Math.max(maxLabelWidth,
|
|
28664
|
+
const labelWidth2 = labelEl.label.length * CHAR_WIDTH5;
|
|
28665
|
+
maxLabelWidth = Math.max(maxLabelWidth, labelWidth2);
|
|
28272
28666
|
labelFieldCount++;
|
|
28273
28667
|
}
|
|
28274
28668
|
}
|
|
@@ -33232,7 +33626,7 @@ function hasRoles(node) {
|
|
|
33232
33626
|
function computeNodeWidth2(node, expanded, options) {
|
|
33233
33627
|
const badgeVal = node.computedConcurrentInvocations === 0 && node.computedInstances > 1 ? node.computedInstances : 0;
|
|
33234
33628
|
const badgeLen = badgeVal > 0 ? `${badgeVal}x`.length + 2 : 0;
|
|
33235
|
-
const
|
|
33629
|
+
const labelWidth2 = (node.label.length + badgeLen) * CHAR_WIDTH7 + PADDING_X3;
|
|
33236
33630
|
const allKeys = [];
|
|
33237
33631
|
if (node.computedRps > 0) allKeys.push("RPS");
|
|
33238
33632
|
if (expanded) {
|
|
@@ -33276,7 +33670,7 @@ function computeNodeWidth2(node, expanded, options) {
|
|
|
33276
33670
|
allKeys.push("overflow");
|
|
33277
33671
|
}
|
|
33278
33672
|
}
|
|
33279
|
-
if (allKeys.length === 0) return Math.max(MIN_NODE_WIDTH2,
|
|
33673
|
+
if (allKeys.length === 0) return Math.max(MIN_NODE_WIDTH2, labelWidth2);
|
|
33280
33674
|
const maxKeyLen = Math.max(...allKeys.map((k) => k.length));
|
|
33281
33675
|
let maxRowWidth = 0;
|
|
33282
33676
|
if (node.computedRps > 0) {
|
|
@@ -33364,7 +33758,7 @@ function computeNodeWidth2(node, expanded, options) {
|
|
|
33364
33758
|
truncated.length * META_CHAR_WIDTH3 + PADDING_X3
|
|
33365
33759
|
);
|
|
33366
33760
|
}
|
|
33367
|
-
return Math.max(MIN_NODE_WIDTH2,
|
|
33761
|
+
return Math.max(MIN_NODE_WIDTH2, labelWidth2, maxRowWidth + 20, descWidth);
|
|
33368
33762
|
}
|
|
33369
33763
|
function computeNodeHeight2(node, expanded, options) {
|
|
33370
33764
|
const propCount = countDisplayProps(node, expanded, options);
|
|
@@ -34913,8 +35307,9 @@ function computeInfraLegendGroups(nodes, tagGroups, palette, edges) {
|
|
|
34913
35307
|
}
|
|
34914
35308
|
return groups;
|
|
34915
35309
|
}
|
|
34916
|
-
function renderLegend3(rootSvg, legendGroups, totalWidth, legendY, palette, isDark, activeGroup, playback, exportMode = false) {
|
|
35310
|
+
function renderLegend3(rootSvg, legendGroups, totalWidth, legendY, palette, isDark, activeGroup, playback, exportMode = false, controlsHost) {
|
|
34917
35311
|
if (legendGroups.length === 0 && !playback) return;
|
|
35312
|
+
const appHostedPlayback = controlsHost === "app" && !!playback;
|
|
34918
35313
|
const legendG = rootSvg.append("g").attr("transform", `translate(0, ${legendY})`);
|
|
34919
35314
|
if (activeGroup) {
|
|
34920
35315
|
legendG.attr("data-legend-active", activeGroup.toLowerCase());
|
|
@@ -34923,14 +35318,29 @@ function renderLegend3(rootSvg, legendGroups, totalWidth, legendY, palette, isDa
|
|
|
34923
35318
|
name: g.name,
|
|
34924
35319
|
entries: g.entries.map((e) => ({ value: e.value, color: e.color }))
|
|
34925
35320
|
}));
|
|
34926
|
-
if (playback) {
|
|
35321
|
+
if (playback && !appHostedPlayback) {
|
|
34927
35322
|
allGroups.push({ name: "Playback", entries: [] });
|
|
34928
35323
|
}
|
|
34929
35324
|
const legendConfig = {
|
|
34930
35325
|
groups: allGroups,
|
|
34931
35326
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
34932
35327
|
mode: exportMode ? "export" : "preview",
|
|
34933
|
-
showEmptyGroups: true
|
|
35328
|
+
showEmptyGroups: true,
|
|
35329
|
+
...appHostedPlayback && {
|
|
35330
|
+
controlsHost: "app",
|
|
35331
|
+
controlsGroup: {
|
|
35332
|
+
toggles: [
|
|
35333
|
+
{
|
|
35334
|
+
id: "playback",
|
|
35335
|
+
type: "toggle",
|
|
35336
|
+
label: "Playback",
|
|
35337
|
+
active: true,
|
|
35338
|
+
onToggle: () => {
|
|
35339
|
+
}
|
|
35340
|
+
}
|
|
35341
|
+
]
|
|
35342
|
+
}
|
|
35343
|
+
}
|
|
34934
35344
|
};
|
|
34935
35345
|
const legendState = { activeGroup };
|
|
34936
35346
|
renderLegendD3(
|
|
@@ -34981,8 +35391,9 @@ function renderLegend3(rootSvg, legendGroups, totalWidth, legendY, palette, isDa
|
|
|
34981
35391
|
}
|
|
34982
35392
|
}
|
|
34983
35393
|
}
|
|
34984
|
-
function renderInfra(container, layout, palette, isDark, title, titleLineNumber, tagGroups, activeGroup, animate, playback, expandedNodeIds, exportMode, collapsedNodes) {
|
|
35394
|
+
function renderInfra(container, layout, palette, isDark, title, titleLineNumber, tagGroups, activeGroup, animate, playback, expandedNodeIds, exportMode, collapsedNodes, controlsHost) {
|
|
34985
35395
|
d3Selection11.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
35396
|
+
const appHostedPlayback = controlsHost === "app" && !!playback;
|
|
34986
35397
|
const ctx = ScaleContext.identity();
|
|
34987
35398
|
const sc = buildScaledConstants(ctx);
|
|
34988
35399
|
const legendGroups = computeInfraLegendGroups(
|
|
@@ -34991,7 +35402,7 @@ function renderInfra(container, layout, palette, isDark, title, titleLineNumber,
|
|
|
34991
35402
|
palette,
|
|
34992
35403
|
layout.edges
|
|
34993
35404
|
);
|
|
34994
|
-
const hasLegend = legendGroups.length > 0 || !!playback;
|
|
35405
|
+
const hasLegend = legendGroups.length > 0 || !!playback && !appHostedPlayback;
|
|
34995
35406
|
const fixedLegend = !exportMode && hasLegend;
|
|
34996
35407
|
const legendDynamicH = hasLegend ? getMaxLegendReservedHeight(
|
|
34997
35408
|
{
|
|
@@ -35135,7 +35546,8 @@ function renderInfra(container, layout, palette, isDark, title, titleLineNumber,
|
|
|
35135
35546
|
isDark,
|
|
35136
35547
|
activeGroup ?? null,
|
|
35137
35548
|
playback ?? void 0,
|
|
35138
|
-
exportMode
|
|
35549
|
+
exportMode,
|
|
35550
|
+
controlsHost
|
|
35139
35551
|
);
|
|
35140
35552
|
legendSvg.selectAll(".infra-legend-group").style("pointer-events", "auto");
|
|
35141
35553
|
} else {
|
|
@@ -35148,7 +35560,8 @@ function renderInfra(container, layout, palette, isDark, title, titleLineNumber,
|
|
|
35148
35560
|
isDark,
|
|
35149
35561
|
activeGroup ?? null,
|
|
35150
35562
|
playback ?? void 0,
|
|
35151
|
-
exportMode
|
|
35563
|
+
exportMode,
|
|
35564
|
+
controlsHost
|
|
35152
35565
|
);
|
|
35153
35566
|
}
|
|
35154
35567
|
}
|
|
@@ -42783,6 +43196,9 @@ function renderTechRadar(container, parsed, palette, isDark, onClickItem, export
|
|
|
42783
43196
|
onToggle: (active) => options.onToggleListing(active)
|
|
42784
43197
|
}
|
|
42785
43198
|
]
|
|
43199
|
+
},
|
|
43200
|
+
...options.controlsHost !== void 0 && {
|
|
43201
|
+
controlsHost: options.controlsHost
|
|
42786
43202
|
}
|
|
42787
43203
|
};
|
|
42788
43204
|
const legendState = {
|
|
@@ -44606,7 +45022,7 @@ function computeCycleLayout(parsed, options) {
|
|
|
44606
45022
|
const circleNodes = parsed.options["circle-nodes"] === "true";
|
|
44607
45023
|
const nodeDims = parsed.nodes.map((node) => {
|
|
44608
45024
|
const hasDesc = !hideDescriptions && node.description.length > 0;
|
|
44609
|
-
const
|
|
45025
|
+
const labelWidth2 = Math.max(
|
|
44610
45026
|
MIN_NODE_WIDTH4,
|
|
44611
45027
|
node.label.length * LABEL_CHAR_W + NODE_PAD_X * 2
|
|
44612
45028
|
);
|
|
@@ -44615,12 +45031,12 @@ function computeCycleLayout(parsed, options) {
|
|
|
44615
45031
|
}
|
|
44616
45032
|
if (!hasDesc) {
|
|
44617
45033
|
return {
|
|
44618
|
-
width: Math.min(MAX_NODE_WIDTH3,
|
|
45034
|
+
width: Math.min(MAX_NODE_WIDTH3, labelWidth2),
|
|
44619
45035
|
height: PLAIN_NODE_HEIGHT,
|
|
44620
45036
|
wrappedDesc: []
|
|
44621
45037
|
};
|
|
44622
45038
|
}
|
|
44623
|
-
return chooseDescribedRectDims(node.description,
|
|
45039
|
+
return chooseDescribedRectDims(node.description, labelWidth2);
|
|
44624
45040
|
});
|
|
44625
45041
|
if (circleNodes) {
|
|
44626
45042
|
const maxDiam = Math.max(...nodeDims.map((d) => d.width));
|
|
@@ -44816,10 +45232,10 @@ function computeCycleLayout(parsed, options) {
|
|
|
44816
45232
|
scale
|
|
44817
45233
|
};
|
|
44818
45234
|
}
|
|
44819
|
-
function chooseDescribedRectDims(description,
|
|
45235
|
+
function chooseDescribedRectDims(description, labelWidth2) {
|
|
44820
45236
|
const minW = Math.min(
|
|
44821
45237
|
MAX_NODE_WIDTH3,
|
|
44822
|
-
Math.max(MIN_NODE_WIDTH4,
|
|
45238
|
+
Math.max(MIN_NODE_WIDTH4, labelWidth2, DESC_MIN_WIDTH)
|
|
44823
45239
|
);
|
|
44824
45240
|
let best = null;
|
|
44825
45241
|
let bestScore = Infinity;
|
|
@@ -45247,7 +45663,8 @@ function renderCycle(container, parsed, palette, isDark, onClickItem, exportDims
|
|
|
45247
45663
|
const hideDescriptions = (renderOptions?.hideDescriptions ?? false) || parsed.options["no-descriptions"] === "true" || viewState?.hd === true;
|
|
45248
45664
|
const showDescriptions = !hideDescriptions;
|
|
45249
45665
|
const hasDescriptions = parsed.nodes.some((n) => n.description.length > 0) || parsed.edges.some((e) => e.description.length > 0);
|
|
45250
|
-
const
|
|
45666
|
+
const appHostedControls = renderOptions?.controlsHost === "app";
|
|
45667
|
+
const hasLegend = !appHostedControls && hasDescriptions && !!renderOptions?.onToggleDescriptions;
|
|
45251
45668
|
const showTitle = !!parsed.title && parsed.options["no-title"] !== "on";
|
|
45252
45669
|
const legendOffset = hasLegend ? sLegendHeight : 0;
|
|
45253
45670
|
const layoutHeight = height - (showTitle ? sTitleAreaHeight : 0) - legendOffset;
|
|
@@ -45284,7 +45701,10 @@ function renderCycle(container, parsed, palette, isDark, onClickItem, exportDims
|
|
|
45284
45701
|
groups: [],
|
|
45285
45702
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
45286
45703
|
mode: renderOptions?.exportMode ? "export" : "preview",
|
|
45287
|
-
controlsGroup
|
|
45704
|
+
controlsGroup,
|
|
45705
|
+
...renderOptions?.controlsHost !== void 0 && {
|
|
45706
|
+
controlsHost: renderOptions.controlsHost
|
|
45707
|
+
}
|
|
45288
45708
|
};
|
|
45289
45709
|
const legendState = {
|
|
45290
45710
|
activeGroup: null,
|
|
@@ -45555,6 +45975,107 @@ function featureIndex(topo) {
|
|
|
45555
45975
|
}
|
|
45556
45976
|
return idx;
|
|
45557
45977
|
}
|
|
45978
|
+
function buildAdjacency(topo) {
|
|
45979
|
+
const cached = adjacencyCache.get(topo);
|
|
45980
|
+
if (cached) return cached;
|
|
45981
|
+
const geometries = geomObject(topo).geometries;
|
|
45982
|
+
const nb = (0, import_topojson_client.neighbors)(geometries);
|
|
45983
|
+
const sets = /* @__PURE__ */ new Map();
|
|
45984
|
+
geometries.forEach((g, i) => {
|
|
45985
|
+
if (!g.type || g.type === "null") return;
|
|
45986
|
+
let set = sets.get(g.id);
|
|
45987
|
+
if (!set) {
|
|
45988
|
+
set = /* @__PURE__ */ new Set();
|
|
45989
|
+
sets.set(g.id, set);
|
|
45990
|
+
}
|
|
45991
|
+
for (const j of nb[i] ?? []) {
|
|
45992
|
+
const nid = geometries[j]?.id;
|
|
45993
|
+
if (nid && nid !== g.id) set.add(nid);
|
|
45994
|
+
}
|
|
45995
|
+
});
|
|
45996
|
+
const out = /* @__PURE__ */ new Map();
|
|
45997
|
+
for (const [iso, set] of sets) out.set(iso, [...set].sort());
|
|
45998
|
+
adjacencyCache.set(topo, out);
|
|
45999
|
+
return out;
|
|
46000
|
+
}
|
|
46001
|
+
function decodeFeatures(topo) {
|
|
46002
|
+
return geomObject(topo).geometries.map((g) => {
|
|
46003
|
+
const f = (0, import_topojson_client.feature)(topo, g);
|
|
46004
|
+
return {
|
|
46005
|
+
type: "Feature",
|
|
46006
|
+
id: g.id,
|
|
46007
|
+
properties: g.properties,
|
|
46008
|
+
geometry: f.geometry
|
|
46009
|
+
};
|
|
46010
|
+
});
|
|
46011
|
+
}
|
|
46012
|
+
function pointInRing(lon, lat, ring) {
|
|
46013
|
+
let inside = false;
|
|
46014
|
+
for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
|
|
46015
|
+
const xi = ring[i][0];
|
|
46016
|
+
const yi = ring[i][1];
|
|
46017
|
+
const xj = ring[j][0];
|
|
46018
|
+
const yj = ring[j][1];
|
|
46019
|
+
const intersect = yi > lat !== yj > lat && lon < (xj - xi) * (lat - yi) / (yj - yi) + xi;
|
|
46020
|
+
if (intersect) inside = !inside;
|
|
46021
|
+
}
|
|
46022
|
+
return inside;
|
|
46023
|
+
}
|
|
46024
|
+
function pointOnRingEdge(lon, lat, ring) {
|
|
46025
|
+
for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
|
|
46026
|
+
const xi = ring[i][0];
|
|
46027
|
+
const yi = ring[i][1];
|
|
46028
|
+
const xj = ring[j][0];
|
|
46029
|
+
const yj = ring[j][1];
|
|
46030
|
+
if (lon < Math.min(xi, xj) - EDGE_EPS || lon > Math.max(xi, xj) + EDGE_EPS)
|
|
46031
|
+
continue;
|
|
46032
|
+
if (lat < Math.min(yi, yj) - EDGE_EPS || lat > Math.max(yi, yj) + EDGE_EPS)
|
|
46033
|
+
continue;
|
|
46034
|
+
const cross = (xj - xi) * (lat - yi) - (yj - yi) * (lon - xi);
|
|
46035
|
+
if (Math.abs(cross) <= EDGE_EPS) return true;
|
|
46036
|
+
}
|
|
46037
|
+
return false;
|
|
46038
|
+
}
|
|
46039
|
+
function pointInGeometry(geometry, lon, lat) {
|
|
46040
|
+
const g = geometry;
|
|
46041
|
+
if (!g) return false;
|
|
46042
|
+
const polys = g.type === "Polygon" ? [g.coordinates] : g.type === "MultiPolygon" ? g.coordinates : [];
|
|
46043
|
+
for (const rings of polys) {
|
|
46044
|
+
if (!rings.length) continue;
|
|
46045
|
+
if (pointOnRingEdge(lon, lat, rings[0])) return true;
|
|
46046
|
+
if (!pointInRing(lon, lat, rings[0])) continue;
|
|
46047
|
+
let inHole = false;
|
|
46048
|
+
for (let h = 1; h < rings.length; h++) {
|
|
46049
|
+
if (pointInRing(lon, lat, rings[h]) && !pointOnRingEdge(lon, lat, rings[h])) {
|
|
46050
|
+
inHole = true;
|
|
46051
|
+
break;
|
|
46052
|
+
}
|
|
46053
|
+
}
|
|
46054
|
+
if (!inHole) return true;
|
|
46055
|
+
}
|
|
46056
|
+
return false;
|
|
46057
|
+
}
|
|
46058
|
+
function regionAt(lonLat, countries, states) {
|
|
46059
|
+
const lon = lonLat[0];
|
|
46060
|
+
const lat = lonLat[1];
|
|
46061
|
+
let country = null;
|
|
46062
|
+
for (const f of countries) {
|
|
46063
|
+
if (pointInGeometry(f.geometry, lon, lat)) {
|
|
46064
|
+
country = { iso: f.id, name: f.properties.name };
|
|
46065
|
+
break;
|
|
46066
|
+
}
|
|
46067
|
+
}
|
|
46068
|
+
let state = null;
|
|
46069
|
+
if (country?.iso === "US" && states) {
|
|
46070
|
+
for (const f of states) {
|
|
46071
|
+
if (pointInGeometry(f.geometry, lon, lat)) {
|
|
46072
|
+
state = { iso: f.id, name: f.properties.name };
|
|
46073
|
+
break;
|
|
46074
|
+
}
|
|
46075
|
+
}
|
|
46076
|
+
}
|
|
46077
|
+
return { country, state };
|
|
46078
|
+
}
|
|
45558
46079
|
function featureBbox(topo, geomId) {
|
|
45559
46080
|
const geom = geomObject(topo).geometries.find((g) => g.id === geomId);
|
|
45560
46081
|
if (!geom) return null;
|
|
@@ -45566,6 +46087,74 @@ function featureBbox(topo, geomId) {
|
|
|
45566
46087
|
[b[1][0], b[1][1]]
|
|
45567
46088
|
];
|
|
45568
46089
|
}
|
|
46090
|
+
function explodePolygons(gj) {
|
|
46091
|
+
const g = gj.geometry ?? gj;
|
|
46092
|
+
const t = g.type;
|
|
46093
|
+
const coords = g.coordinates;
|
|
46094
|
+
if (t === "Polygon") {
|
|
46095
|
+
return [
|
|
46096
|
+
{ type: "Feature", geometry: { type: "Polygon", coordinates: coords } }
|
|
46097
|
+
];
|
|
46098
|
+
}
|
|
46099
|
+
if (t === "MultiPolygon") {
|
|
46100
|
+
return coords.map((rings) => ({
|
|
46101
|
+
type: "Feature",
|
|
46102
|
+
geometry: { type: "Polygon", coordinates: rings }
|
|
46103
|
+
}));
|
|
46104
|
+
}
|
|
46105
|
+
return [];
|
|
46106
|
+
}
|
|
46107
|
+
function bboxGap(a, b) {
|
|
46108
|
+
const lonGap = Math.max(0, a[0][0] - b[1][0], b[0][0] - a[1][0]);
|
|
46109
|
+
const latGap = Math.max(0, a[0][1] - b[1][1], b[0][1] - a[1][1]);
|
|
46110
|
+
return Math.max(lonGap, latGap);
|
|
46111
|
+
}
|
|
46112
|
+
function featureBboxPrimary(topo, geomId) {
|
|
46113
|
+
const geom = geomObject(topo).geometries.find((g) => g.id === geomId);
|
|
46114
|
+
if (!geom) return null;
|
|
46115
|
+
const gj = (0, import_topojson_client.feature)(topo, geom);
|
|
46116
|
+
const parts = explodePolygons(gj);
|
|
46117
|
+
if (parts.length <= 1) return featureBbox(topo, geomId);
|
|
46118
|
+
const polys = parts.map((p) => {
|
|
46119
|
+
const b = (0, import_d3_geo.geoBounds)(p);
|
|
46120
|
+
if (!b || !Number.isFinite(b[0][0])) return null;
|
|
46121
|
+
const wraps = b[1][0] < b[0][0];
|
|
46122
|
+
const bbox = [
|
|
46123
|
+
[b[0][0], b[0][1]],
|
|
46124
|
+
[b[1][0], b[1][1]]
|
|
46125
|
+
];
|
|
46126
|
+
return { bbox, area: (0, import_d3_geo.geoArea)(p), wraps };
|
|
46127
|
+
}).filter(
|
|
46128
|
+
(p) => p !== null
|
|
46129
|
+
);
|
|
46130
|
+
if (polys.length <= 1 || polys.some((p) => p.wraps))
|
|
46131
|
+
return featureBbox(topo, geomId);
|
|
46132
|
+
const maxArea = Math.max(...polys.map((p) => p.area));
|
|
46133
|
+
const anchor = polys.find((p) => p.area === maxArea);
|
|
46134
|
+
const cluster = [
|
|
46135
|
+
[anchor.bbox[0][0], anchor.bbox[0][1]],
|
|
46136
|
+
[anchor.bbox[1][0], anchor.bbox[1][1]]
|
|
46137
|
+
];
|
|
46138
|
+
const remaining = polys.filter((p) => p !== anchor);
|
|
46139
|
+
let added = true;
|
|
46140
|
+
while (added) {
|
|
46141
|
+
added = false;
|
|
46142
|
+
for (let i = remaining.length - 1; i >= 0; i--) {
|
|
46143
|
+
const p = remaining[i];
|
|
46144
|
+
const near = bboxGap(p.bbox, cluster) <= DETACH_GAP_DEG;
|
|
46145
|
+
const large = p.area >= DETACH_AREA_FRAC * maxArea;
|
|
46146
|
+
if (near || large) {
|
|
46147
|
+
cluster[0][0] = Math.min(cluster[0][0], p.bbox[0][0]);
|
|
46148
|
+
cluster[0][1] = Math.min(cluster[0][1], p.bbox[0][1]);
|
|
46149
|
+
cluster[1][0] = Math.max(cluster[1][0], p.bbox[1][0]);
|
|
46150
|
+
cluster[1][1] = Math.max(cluster[1][1], p.bbox[1][1]);
|
|
46151
|
+
remaining.splice(i, 1);
|
|
46152
|
+
added = true;
|
|
46153
|
+
}
|
|
46154
|
+
}
|
|
46155
|
+
}
|
|
46156
|
+
return cluster;
|
|
46157
|
+
}
|
|
45569
46158
|
function unionExtent(boxes, points) {
|
|
45570
46159
|
const lats = [];
|
|
45571
46160
|
const lons = [];
|
|
@@ -45604,13 +46193,17 @@ function unionLongitudes(lons) {
|
|
|
45604
46193
|
}
|
|
45605
46194
|
return { west: pts[gapIdx], east: pts[gapIdx - 1] + 360 };
|
|
45606
46195
|
}
|
|
45607
|
-
var import_topojson_client, import_d3_geo, fold;
|
|
46196
|
+
var import_topojson_client, import_d3_geo, fold, adjacencyCache, EDGE_EPS, DETACH_GAP_DEG, DETACH_AREA_FRAC;
|
|
45608
46197
|
var init_geo = __esm({
|
|
45609
46198
|
"src/map/geo.ts"() {
|
|
45610
46199
|
"use strict";
|
|
45611
46200
|
import_topojson_client = require("topojson-client");
|
|
45612
46201
|
import_d3_geo = require("d3-geo");
|
|
45613
46202
|
fold = (s) => s.normalize("NFD").replace(/\p{Diacritic}/gu, "").toLowerCase().trim();
|
|
46203
|
+
adjacencyCache = /* @__PURE__ */ new WeakMap();
|
|
46204
|
+
EDGE_EPS = 1e-9;
|
|
46205
|
+
DETACH_GAP_DEG = 10;
|
|
46206
|
+
DETACH_AREA_FRAC = 0.25;
|
|
45614
46207
|
}
|
|
45615
46208
|
});
|
|
45616
46209
|
|
|
@@ -45628,6 +46221,12 @@ function looksUS(lat, lon) {
|
|
|
45628
46221
|
if (lat < 15 || lat > 72) return false;
|
|
45629
46222
|
return lon >= -180 && lon <= -64 || lon >= 172;
|
|
45630
46223
|
}
|
|
46224
|
+
function looksNorthAmericaNeighbor(lat, lon) {
|
|
46225
|
+
return lat >= 14 && lat <= 72 && lon >= -141 && lon <= -52;
|
|
46226
|
+
}
|
|
46227
|
+
function isWholeSphere(bb) {
|
|
46228
|
+
return bb[0][0] <= -179 && bb[1][0] >= 179 && bb[0][1] <= -89 && bb[1][1] >= 89;
|
|
46229
|
+
}
|
|
45631
46230
|
function resolveMap(parsed, data) {
|
|
45632
46231
|
const diagnostics = [...parsed.diagnostics];
|
|
45633
46232
|
const err = (line12, message, code) => {
|
|
@@ -45638,9 +46237,6 @@ function resolveMap(parsed, data) {
|
|
|
45638
46237
|
};
|
|
45639
46238
|
const result = {
|
|
45640
46239
|
title: parsed.title,
|
|
45641
|
-
...parsed.directives.subtitle !== void 0 && {
|
|
45642
|
-
subtitle: parsed.directives.subtitle
|
|
45643
|
-
},
|
|
45644
46240
|
...parsed.directives.caption !== void 0 && {
|
|
45645
46241
|
caption: parsed.directives.caption
|
|
45646
46242
|
},
|
|
@@ -45650,7 +46246,7 @@ function resolveMap(parsed, data) {
|
|
|
45650
46246
|
// renderer's job (step 4) — the resolver only carries `tags` + `tagGroups`
|
|
45651
46247
|
// through; it never resolves a tag value to a palette color (#10).
|
|
45652
46248
|
directives: { ...parsed.directives },
|
|
45653
|
-
basemaps: { world: "
|
|
46249
|
+
basemaps: { world: "detail", subdivisions: [] },
|
|
45654
46250
|
regions: [],
|
|
45655
46251
|
pois: [],
|
|
45656
46252
|
edges: [],
|
|
@@ -45659,7 +46255,8 @@ function resolveMap(parsed, data) {
|
|
|
45659
46255
|
[-180, -85],
|
|
45660
46256
|
[180, 85]
|
|
45661
46257
|
],
|
|
45662
|
-
projection: "
|
|
46258
|
+
projection: "equirectangular",
|
|
46259
|
+
poiFrameContainers: [],
|
|
45663
46260
|
diagnostics,
|
|
45664
46261
|
error: parsed.error
|
|
45665
46262
|
};
|
|
@@ -45669,7 +46266,10 @@ function resolveMap(parsed, data) {
|
|
|
45669
46266
|
...[...countryIndex.values()].map((v) => v.name),
|
|
45670
46267
|
...[...usStateIndex.values()].map((v) => v.name)
|
|
45671
46268
|
];
|
|
45672
|
-
const
|
|
46269
|
+
const localeRaw = parsed.directives.locale?.toUpperCase();
|
|
46270
|
+
const localeCountry = localeRaw ? localeRaw.split("-")[0] : void 0;
|
|
46271
|
+
const localeSubdivision = localeRaw && /^[A-Z]{2}-/.test(localeRaw) ? localeRaw : void 0;
|
|
46272
|
+
const usScoped = localeCountry === "US" || parsed.regions.some((r) => {
|
|
45673
46273
|
const f = fold(r.name);
|
|
45674
46274
|
return usStateIndex.has(f) && !countryIndex.has(f);
|
|
45675
46275
|
}) || parsed.regions.some(
|
|
@@ -45714,12 +46314,12 @@ function resolveMap(parsed, data) {
|
|
|
45714
46314
|
chosen = { ...inState, layer: "us-state" };
|
|
45715
46315
|
} else {
|
|
45716
46316
|
chosen = { ...inCountry, layer: "country" };
|
|
46317
|
+
warn(
|
|
46318
|
+
r.lineNumber,
|
|
46319
|
+
`"${r.name}" is both a country and a US state \u2014 resolved as ${chosen.layer} (${chosen.id}). Pin it with an ISO code (${inState.id} / ${inCountry.id}) or name + scope ("${r.name} US" / "${r.name} ${inCountry.id}").`,
|
|
46320
|
+
"W_MAP_REGION_AMBIGUOUS"
|
|
46321
|
+
);
|
|
45717
46322
|
}
|
|
45718
|
-
warn(
|
|
45719
|
-
r.lineNumber,
|
|
45720
|
-
`"${r.name}" is both a country and a US state \u2014 resolved as ${chosen.layer} (${chosen.id}). Pin it with an ISO code (${inState.id} / ${inCountry.id}) or name + scope ("${r.name} US" / "${r.name} ${inCountry.id}").`,
|
|
45721
|
-
"W_MAP_REGION_AMBIGUOUS"
|
|
45722
|
-
);
|
|
45723
46323
|
} else if (inState) {
|
|
45724
46324
|
chosen = { ...inState, layer: "us-state" };
|
|
45725
46325
|
} else if (inCountry) {
|
|
@@ -45743,6 +46343,7 @@ function resolveMap(parsed, data) {
|
|
|
45743
46343
|
name: chosen.name,
|
|
45744
46344
|
layer: chosen.layer,
|
|
45745
46345
|
...r.value !== void 0 && { value: r.value },
|
|
46346
|
+
...r.color !== void 0 && { color: r.color },
|
|
45746
46347
|
tags: r.tags,
|
|
45747
46348
|
meta: r.meta,
|
|
45748
46349
|
lineNumber: r.lineNumber
|
|
@@ -45819,7 +46420,7 @@ function resolveMap(parsed, data) {
|
|
|
45819
46420
|
if (!scope)
|
|
45820
46421
|
warn(
|
|
45821
46422
|
line12,
|
|
45822
|
-
`"${name}" is ambiguous \u2014 resolved to the most-populous match.`,
|
|
46423
|
+
`"${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.`,
|
|
45823
46424
|
"W_MAP_AMBIGUOUS_NAME"
|
|
45824
46425
|
);
|
|
45825
46426
|
}
|
|
@@ -45832,17 +46433,21 @@ function resolveMap(parsed, data) {
|
|
|
45832
46433
|
return fold(pos.name);
|
|
45833
46434
|
};
|
|
45834
46435
|
const poiCountries = [];
|
|
45835
|
-
let
|
|
46436
|
+
let anyUsPoi = false;
|
|
46437
|
+
let anyNonNaPoi = false;
|
|
45836
46438
|
const noteCountry = (iso) => {
|
|
45837
46439
|
if (iso) {
|
|
45838
46440
|
poiCountries.push(iso);
|
|
45839
|
-
if (iso
|
|
46441
|
+
if (iso === "US") anyUsPoi = true;
|
|
46442
|
+
if (iso !== "US" && iso !== "CA" && iso !== "MX") anyNonNaPoi = true;
|
|
45840
46443
|
}
|
|
45841
46444
|
};
|
|
45842
46445
|
const deferred = [];
|
|
45843
46446
|
for (const p of parsed.pois) {
|
|
45844
46447
|
if (p.pos.kind === "coords") {
|
|
45845
|
-
if (
|
|
46448
|
+
if (looksUS(p.pos.lat, p.pos.lon)) anyUsPoi = true;
|
|
46449
|
+
else if (!looksNorthAmericaNeighbor(p.pos.lat, p.pos.lon))
|
|
46450
|
+
anyNonNaPoi = true;
|
|
45846
46451
|
addResolvedPoi(p.pos.lat, p.pos.lon, p);
|
|
45847
46452
|
continue;
|
|
45848
46453
|
}
|
|
@@ -45860,14 +46465,15 @@ function resolveMap(parsed, data) {
|
|
|
45860
46465
|
deferred.push(p);
|
|
45861
46466
|
}
|
|
45862
46467
|
}
|
|
45863
|
-
const inferredCountry =
|
|
46468
|
+
const inferredCountry = localeCountry ?? mostCommonCountry(regions, poiCountries) ?? void 0;
|
|
46469
|
+
const inferredScope = localeSubdivision ?? inferredCountry;
|
|
45864
46470
|
for (const p of deferred) {
|
|
45865
46471
|
if (p.pos.kind !== "name") continue;
|
|
45866
46472
|
const got = lookupName(
|
|
45867
46473
|
p.pos.name,
|
|
45868
46474
|
p.pos.scope,
|
|
45869
46475
|
p.lineNumber,
|
|
45870
|
-
|
|
46476
|
+
inferredScope,
|
|
45871
46477
|
true
|
|
45872
46478
|
);
|
|
45873
46479
|
if (got.kind === "ok") {
|
|
@@ -45884,6 +46490,7 @@ function resolveMap(parsed, data) {
|
|
|
45884
46490
|
lat,
|
|
45885
46491
|
lon,
|
|
45886
46492
|
...p.label !== void 0 && { label: p.label },
|
|
46493
|
+
...p.color !== void 0 && { color: p.color },
|
|
45887
46494
|
tags: p.tags,
|
|
45888
46495
|
meta: p.meta,
|
|
45889
46496
|
lineNumber: p.lineNumber
|
|
@@ -45936,7 +46543,8 @@ function resolveMap(parsed, data) {
|
|
|
45936
46543
|
const meta = sizeValue !== void 0 ? { value: sizeValue } : {};
|
|
45937
46544
|
if (pos.kind === "coords") {
|
|
45938
46545
|
const id = alias ? fold(alias) : `@${pos.lat},${pos.lon}`;
|
|
45939
|
-
if (
|
|
46546
|
+
if (looksUS(pos.lat, pos.lon)) anyUsPoi = true;
|
|
46547
|
+
else if (!looksNorthAmericaNeighbor(pos.lat, pos.lon)) anyNonNaPoi = true;
|
|
45940
46548
|
if (!registry.has(id)) {
|
|
45941
46549
|
registerPoi(
|
|
45942
46550
|
id,
|
|
@@ -45959,7 +46567,7 @@ function resolveMap(parsed, data) {
|
|
|
45959
46567
|
if (registry.has(f)) return f;
|
|
45960
46568
|
const aliased = declaredByName.get(f);
|
|
45961
46569
|
if (aliased) return aliased;
|
|
45962
|
-
const got = lookupName(pos.name, pos.scope, line12,
|
|
46570
|
+
const got = lookupName(pos.name, pos.scope, line12, inferredScope, true);
|
|
45963
46571
|
if (got.kind !== "ok") return null;
|
|
45964
46572
|
noteCountry(got.iso);
|
|
45965
46573
|
registerPoi(
|
|
@@ -46016,9 +46624,12 @@ function resolveMap(parsed, data) {
|
|
|
46016
46624
|
}
|
|
46017
46625
|
routes.push({ stopIds, legs, lineNumber: rt.lineNumber });
|
|
46018
46626
|
}
|
|
46627
|
+
const hasUsContent = usSubdivisionReferenced || anyUsPoi || localeCountry === "US";
|
|
46628
|
+
const usOriented = !anyNonNaPoi && !regions.some(
|
|
46629
|
+
(r) => r.layer === "country" && !["US", "CA", "MX"].includes(r.iso)
|
|
46630
|
+
) && hasUsContent;
|
|
46019
46631
|
const subdivisions = [];
|
|
46020
|
-
if (usSubdivisionReferenced ||
|
|
46021
|
-
subdivisions.push("us-states");
|
|
46632
|
+
if (usSubdivisionReferenced || usOriented) subdivisions.push("us-states");
|
|
46022
46633
|
const regionBoxes = [];
|
|
46023
46634
|
for (const ref of referencedRegionIds) {
|
|
46024
46635
|
const bb = featureBbox(data.usStates, ref.id);
|
|
@@ -46026,7 +46637,7 @@ function resolveMap(parsed, data) {
|
|
|
46026
46637
|
}
|
|
46027
46638
|
for (const r of regions) {
|
|
46028
46639
|
if (r.layer === "country") {
|
|
46029
|
-
const bb =
|
|
46640
|
+
const bb = featureBboxPrimary(data.worldCoarse, r.iso);
|
|
46030
46641
|
if (bb) regionBoxes.push(bb);
|
|
46031
46642
|
}
|
|
46032
46643
|
}
|
|
@@ -46036,23 +46647,56 @@ function resolveMap(parsed, data) {
|
|
|
46036
46647
|
[-180, -85],
|
|
46037
46648
|
[180, 85]
|
|
46038
46649
|
];
|
|
46039
|
-
|
|
46650
|
+
const basePad = regions.length > 0 ? REGION_PAD_FRACTION : PAD_FRACTION;
|
|
46651
|
+
let extent2 = unioned ? pad(unioned, basePad) : DEFAULT_EXTENT;
|
|
46652
|
+
const isPoiOnly = pois.length > 0 && regions.length === 0;
|
|
46653
|
+
const containerRegionIds = [];
|
|
46654
|
+
if (isPoiOnly) {
|
|
46655
|
+
const countries = decodeFeatures(data.worldDetail);
|
|
46656
|
+
const states = decodeFeatures(data.usStates);
|
|
46657
|
+
const seen = /* @__PURE__ */ new Set();
|
|
46658
|
+
const containerBoxes = [];
|
|
46659
|
+
for (const p of pois) {
|
|
46660
|
+
const { country, state } = regionAt([p.lon, p.lat], countries, states);
|
|
46661
|
+
const id = state?.iso ?? country?.iso;
|
|
46662
|
+
if (!id || seen.has(id)) continue;
|
|
46663
|
+
seen.add(id);
|
|
46664
|
+
containerRegionIds.push(id);
|
|
46665
|
+
const bb = state ? featureBbox(data.usStates, id) : featureBboxPrimary(data.worldCoarse, id);
|
|
46666
|
+
if (bb && !isWholeSphere(bb)) containerBoxes.push(bb);
|
|
46667
|
+
}
|
|
46668
|
+
const containerUnion = unionExtent(containerBoxes, points);
|
|
46669
|
+
if (containerUnion) extent2 = pad(containerUnion, PAD_FRACTION);
|
|
46670
|
+
}
|
|
46671
|
+
if (isPoiOnly) {
|
|
46672
|
+
const cx = (extent2[0][0] + extent2[1][0]) / 2;
|
|
46673
|
+
const cy = (extent2[0][1] + extent2[1][1]) / 2;
|
|
46674
|
+
const lon = extent2[1][0] - extent2[0][0];
|
|
46675
|
+
const lat = extent2[1][1] - extent2[0][1];
|
|
46676
|
+
const longer = Math.max(lon, lat);
|
|
46677
|
+
if (longer > 0 && longer < POI_ZOOM_FLOOR_DEG) {
|
|
46678
|
+
const k = POI_ZOOM_FLOOR_DEG / longer;
|
|
46679
|
+
const halfLon = lon * k / 2;
|
|
46680
|
+
const halfLat = lat * k / 2;
|
|
46681
|
+
extent2 = [
|
|
46682
|
+
[cx - halfLon, cy - halfLat],
|
|
46683
|
+
[cx + halfLon, cy + halfLat]
|
|
46684
|
+
];
|
|
46685
|
+
}
|
|
46686
|
+
}
|
|
46040
46687
|
const lonSpan = extent2[1][0] - extent2[0][0];
|
|
46041
46688
|
const latSpan = extent2[1][1] - extent2[0][1];
|
|
46042
46689
|
const span = Math.max(lonSpan, latSpan);
|
|
46043
|
-
const
|
|
46690
|
+
const maxAbsLat = Math.max(Math.abs(extent2[0][1]), Math.abs(extent2[1][1]));
|
|
46044
46691
|
let projection;
|
|
46045
|
-
|
|
46046
|
-
|
|
46047
|
-
|
|
46048
|
-
} else if (usDominant) {
|
|
46692
|
+
if (isPoiOnly && usOriented && lonSpan < US_NATIONAL_LON_SPAN) {
|
|
46693
|
+
projection = "mercator";
|
|
46694
|
+
} else if (usOriented) {
|
|
46049
46695
|
projection = "albers-usa";
|
|
46050
|
-
} else if (span > WORLD_SPAN) {
|
|
46696
|
+
} else if (span > WORLD_SPAN || maxAbsLat > MERCATOR_MAX_LAT) {
|
|
46051
46697
|
projection = "equirectangular";
|
|
46052
|
-
} else if (span < MERCATOR_MAX_SPAN) {
|
|
46053
|
-
projection = "mercator";
|
|
46054
46698
|
} else {
|
|
46055
|
-
projection = "
|
|
46699
|
+
projection = "mercator";
|
|
46056
46700
|
}
|
|
46057
46701
|
if (lonSpan >= 180) {
|
|
46058
46702
|
extent2 = [
|
|
@@ -46065,11 +46709,20 @@ function resolveMap(parsed, data) {
|
|
|
46065
46709
|
result.edges = edges;
|
|
46066
46710
|
result.routes = routes;
|
|
46067
46711
|
result.basemaps = {
|
|
46068
|
-
|
|
46712
|
+
// Tier is intentionally pinned to detail (50m) at ALL scales. Diagrammo maps
|
|
46713
|
+
// are presentational (palette tints, relief hachures, POI hubs), not
|
|
46714
|
+
// survey-grade — recognizability > generalization: 110m coarse drops the
|
|
46715
|
+
// Italian boot to a stump at world scale. `WORLD_SPAN` lives on only for the
|
|
46716
|
+
// projection decision (the `usOriented`/`span > WORLD_SPAN` chain above); it
|
|
46717
|
+
// no longer gates basemap resolution.
|
|
46718
|
+
// `worldCoarse` is still loaded — it's the authoritative name/bbox index
|
|
46719
|
+
// (featureIndex, featureBboxPrimary), not dead code.
|
|
46720
|
+
world: "detail",
|
|
46069
46721
|
subdivisions
|
|
46070
46722
|
};
|
|
46071
46723
|
result.extent = extent2;
|
|
46072
46724
|
result.projection = projection;
|
|
46725
|
+
result.poiFrameContainers = containerRegionIds;
|
|
46073
46726
|
result.error = parsed.error ?? firstError(diagnostics);
|
|
46074
46727
|
return result;
|
|
46075
46728
|
}
|
|
@@ -46106,17 +46759,20 @@ function firstError(diags) {
|
|
|
46106
46759
|
const e = diags.find((d) => d.severity === "error");
|
|
46107
46760
|
return e ? formatDgmoError(e) : null;
|
|
46108
46761
|
}
|
|
46109
|
-
var WORLD_SPAN,
|
|
46762
|
+
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;
|
|
46110
46763
|
var init_resolver2 = __esm({
|
|
46111
46764
|
"src/map/resolver.ts"() {
|
|
46112
46765
|
"use strict";
|
|
46113
46766
|
init_diagnostics();
|
|
46114
46767
|
init_geo();
|
|
46115
46768
|
WORLD_SPAN = 90;
|
|
46116
|
-
|
|
46769
|
+
MERCATOR_MAX_LAT = 80;
|
|
46117
46770
|
PAD_FRACTION = 0.05;
|
|
46771
|
+
REGION_PAD_FRACTION = 0.12;
|
|
46118
46772
|
WORLD_LAT_SOUTH = -58;
|
|
46119
46773
|
WORLD_LAT_NORTH = 78;
|
|
46774
|
+
POI_ZOOM_FLOOR_DEG = 7;
|
|
46775
|
+
US_NATIONAL_LON_SPAN = 48;
|
|
46120
46776
|
REGION_ALIASES = {
|
|
46121
46777
|
// Common everyday names → the Natural-Earth display name actually shipped.
|
|
46122
46778
|
"united states": "united states of america",
|
|
@@ -46194,112 +46850,269 @@ var init_resolver2 = __esm({
|
|
|
46194
46850
|
}
|
|
46195
46851
|
});
|
|
46196
46852
|
|
|
46197
|
-
// src/map/
|
|
46198
|
-
|
|
46199
|
-
|
|
46200
|
-
|
|
46853
|
+
// src/map/colorize.ts
|
|
46854
|
+
function assignColors(isos, adjacency) {
|
|
46855
|
+
const sorted = [...isos].sort();
|
|
46856
|
+
const byIso = /* @__PURE__ */ new Map();
|
|
46857
|
+
let maxIndex = -1;
|
|
46858
|
+
for (const iso of sorted) {
|
|
46859
|
+
const taken = /* @__PURE__ */ new Set();
|
|
46860
|
+
for (const n of adjacency.get(iso) ?? []) {
|
|
46861
|
+
const c = byIso.get(n);
|
|
46862
|
+
if (c !== void 0) taken.add(c);
|
|
46863
|
+
}
|
|
46864
|
+
let h = 0;
|
|
46865
|
+
while (taken.has(h)) h++;
|
|
46866
|
+
byIso.set(iso, h);
|
|
46867
|
+
if (h > maxIndex) maxIndex = h;
|
|
46868
|
+
}
|
|
46869
|
+
return { byIso, huesNeeded: maxIndex + 1 };
|
|
46870
|
+
}
|
|
46871
|
+
var init_colorize = __esm({
|
|
46872
|
+
"src/map/colorize.ts"() {
|
|
46873
|
+
"use strict";
|
|
46874
|
+
}
|
|
46201
46875
|
});
|
|
46202
|
-
|
|
46203
|
-
|
|
46204
|
-
|
|
46205
|
-
|
|
46206
|
-
|
|
46207
|
-
|
|
46208
|
-
return
|
|
46209
|
-
}
|
|
46210
|
-
|
|
46211
|
-
|
|
46212
|
-
|
|
46213
|
-
|
|
46214
|
-
|
|
46215
|
-
|
|
46216
|
-
|
|
46217
|
-
|
|
46218
|
-
|
|
46219
|
-
|
|
46876
|
+
|
|
46877
|
+
// src/map/context-labels.ts
|
|
46878
|
+
function tierBand(maxSpanDeg) {
|
|
46879
|
+
if (maxSpanDeg >= 90) return "world";
|
|
46880
|
+
if (maxSpanDeg >= 20) return "continental";
|
|
46881
|
+
if (maxSpanDeg >= 5) return "regional";
|
|
46882
|
+
return "local";
|
|
46883
|
+
}
|
|
46884
|
+
function labelBudget(width, height, band) {
|
|
46885
|
+
const bandCap = {
|
|
46886
|
+
world: 6,
|
|
46887
|
+
continental: 5,
|
|
46888
|
+
regional: 4,
|
|
46889
|
+
local: 3
|
|
46890
|
+
};
|
|
46891
|
+
const area2 = Math.floor(Math.sqrt(Math.max(0, width * height)) / 150);
|
|
46892
|
+
return Math.max(0, Math.min(area2, bandCap[band]));
|
|
46893
|
+
}
|
|
46894
|
+
function waterEligible(tier, kind, band) {
|
|
46895
|
+
switch (band) {
|
|
46896
|
+
case "world":
|
|
46897
|
+
return tier <= 1 && (kind === "ocean" || kind === "sea");
|
|
46898
|
+
case "continental":
|
|
46899
|
+
return tier <= 2;
|
|
46900
|
+
case "regional":
|
|
46901
|
+
return tier <= 3;
|
|
46902
|
+
case "local":
|
|
46903
|
+
return tier <= 4;
|
|
46904
|
+
}
|
|
46905
|
+
}
|
|
46906
|
+
function insideViewport(p, width, height) {
|
|
46907
|
+
return !!p && Number.isFinite(p[0]) && Number.isFinite(p[1]) && p[0] >= 0 && p[0] <= width && p[1] >= 0 && p[1] <= height;
|
|
46908
|
+
}
|
|
46909
|
+
function labelWidth(text, letterSpacing) {
|
|
46910
|
+
const spacing = letterSpacing > 0 ? Math.max(0, text.length - 1) * letterSpacing : 0;
|
|
46911
|
+
return measureLegendText(text, FONT) + spacing + 2 * PADX;
|
|
46912
|
+
}
|
|
46913
|
+
function wrapLabel2(text, letterSpacing) {
|
|
46914
|
+
const words = text.split(/\s+/).filter(Boolean);
|
|
46915
|
+
if (words.length <= 1) return [text];
|
|
46916
|
+
const maxLines = words.length >= 4 ? 3 : 2;
|
|
46917
|
+
const n = words.length;
|
|
46918
|
+
let best = null;
|
|
46919
|
+
for (let mask = 0; mask < 1 << n - 1; mask++) {
|
|
46920
|
+
const lines = [];
|
|
46921
|
+
let cur = [words[0]];
|
|
46922
|
+
for (let i = 1; i < n; i++) {
|
|
46923
|
+
if (mask & 1 << i - 1) {
|
|
46924
|
+
lines.push(cur.join(" "));
|
|
46925
|
+
cur = [words[i]];
|
|
46926
|
+
} else cur.push(words[i]);
|
|
46220
46927
|
}
|
|
46928
|
+
lines.push(cur.join(" "));
|
|
46929
|
+
if (lines.length > maxLines) continue;
|
|
46930
|
+
const cost = Math.round(
|
|
46931
|
+
Math.max(...lines.map((l) => labelWidth(l, letterSpacing)))
|
|
46932
|
+
);
|
|
46933
|
+
const head = labelWidth(lines[0], letterSpacing);
|
|
46934
|
+
if (!best || cost < best.cost || cost === best.cost && lines.length < best.lines.length || cost === best.cost && lines.length === best.lines.length && head > best.head)
|
|
46935
|
+
best = { lines, cost, head };
|
|
46221
46936
|
}
|
|
46222
|
-
|
|
46223
|
-
`map data assets not found near ${baseDir} (looked in ${CANDIDATE_DIRS.join(", ")}). Run \`pnpm build:map-data\` and \`pnpm build\`.`
|
|
46224
|
-
);
|
|
46937
|
+
return best?.lines ?? [text];
|
|
46225
46938
|
}
|
|
46226
|
-
function
|
|
46227
|
-
const
|
|
46228
|
-
|
|
46229
|
-
|
|
46230
|
-
}
|
|
46231
|
-
return data;
|
|
46939
|
+
function rectAround(cx, cy, lines, letterSpacing) {
|
|
46940
|
+
const w = Math.max(...lines.map((l) => labelWidth(l, letterSpacing)));
|
|
46941
|
+
const h = (lines.length - 1) * LINE_HEIGHT + FONT + 2 * PADY;
|
|
46942
|
+
return { x: cx - w / 2, y: cy - h / 2, w, h };
|
|
46232
46943
|
}
|
|
46233
|
-
function
|
|
46234
|
-
|
|
46235
|
-
const url = import_meta.url;
|
|
46236
|
-
if (url) return nb.dirname(nb.fileURLToPath(url));
|
|
46237
|
-
} catch {
|
|
46238
|
-
}
|
|
46239
|
-
if (typeof __dirname !== "undefined") return __dirname;
|
|
46240
|
-
return process.cwd();
|
|
46944
|
+
function rectFits(r, width, height) {
|
|
46945
|
+
return r.x >= 0 && r.y >= 0 && r.x + r.w <= width && r.y + r.h <= height;
|
|
46241
46946
|
}
|
|
46242
|
-
function
|
|
46243
|
-
|
|
46244
|
-
|
|
46245
|
-
|
|
46246
|
-
|
|
46247
|
-
|
|
46248
|
-
|
|
46249
|
-
|
|
46250
|
-
|
|
46251
|
-
|
|
46252
|
-
|
|
46253
|
-
|
|
46254
|
-
|
|
46255
|
-
|
|
46256
|
-
|
|
46257
|
-
|
|
46258
|
-
|
|
46259
|
-
|
|
46260
|
-
|
|
46261
|
-
|
|
46262
|
-
|
|
46263
|
-
|
|
46264
|
-
|
|
46265
|
-
|
|
46266
|
-
|
|
46267
|
-
|
|
46268
|
-
|
|
46269
|
-
|
|
46270
|
-
|
|
46271
|
-
|
|
46272
|
-
|
|
46273
|
-
|
|
46274
|
-
|
|
46947
|
+
function overlapsPadded(a, b, pad2) {
|
|
46948
|
+
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;
|
|
46949
|
+
}
|
|
46950
|
+
function placeContextLabels(args) {
|
|
46951
|
+
const {
|
|
46952
|
+
projection,
|
|
46953
|
+
dLonSpan,
|
|
46954
|
+
dLatSpan,
|
|
46955
|
+
width,
|
|
46956
|
+
height,
|
|
46957
|
+
waterBodies,
|
|
46958
|
+
countries,
|
|
46959
|
+
palette,
|
|
46960
|
+
project,
|
|
46961
|
+
collides,
|
|
46962
|
+
overLand
|
|
46963
|
+
} = args;
|
|
46964
|
+
void projection;
|
|
46965
|
+
const band = tierBand(Math.max(dLonSpan, dLatSpan));
|
|
46966
|
+
const budget = labelBudget(width, height, band);
|
|
46967
|
+
if (budget <= 0) return [];
|
|
46968
|
+
const waterColor = mix(palette.colors.blue, palette.textMuted, 50);
|
|
46969
|
+
const countryColor = palette.textMuted;
|
|
46970
|
+
const haloColor = palette.bg;
|
|
46971
|
+
const candidates = [];
|
|
46972
|
+
const center = [width / 2, height / 2];
|
|
46973
|
+
for (const e of waterBodies?.entries ?? []) {
|
|
46974
|
+
const [lat, lon, name, tier, kind, alt] = e;
|
|
46975
|
+
if (!waterEligible(tier, kind, band)) continue;
|
|
46976
|
+
const wlines = wrapLabel2(name, WATER_LETTER_SPACING);
|
|
46977
|
+
const anchorsLngLat = [[lon, lat]];
|
|
46978
|
+
for (const a of alt ?? []) anchorsLngLat.push([a[1], a[0]]);
|
|
46979
|
+
let best = null;
|
|
46980
|
+
let bestD = Infinity;
|
|
46981
|
+
let nearestProj = null;
|
|
46982
|
+
let nearestProjD = Infinity;
|
|
46983
|
+
for (const [aLon, aLat] of anchorsLngLat) {
|
|
46984
|
+
const p = project(aLon, aLat);
|
|
46985
|
+
if (!p || !Number.isFinite(p[0]) || !Number.isFinite(p[1])) continue;
|
|
46986
|
+
const d = (p[0] - center[0]) ** 2 + (p[1] - center[1]) ** 2;
|
|
46987
|
+
if (d < nearestProjD) {
|
|
46988
|
+
nearestProjD = d;
|
|
46989
|
+
nearestProj = p;
|
|
46990
|
+
}
|
|
46991
|
+
if (!insideViewport(p, width, height)) continue;
|
|
46992
|
+
if (d < bestD) {
|
|
46993
|
+
bestD = d;
|
|
46994
|
+
best = p;
|
|
46995
|
+
}
|
|
46996
|
+
}
|
|
46997
|
+
if (!best && tier === 0 && nearestProj) {
|
|
46998
|
+
const overX = Math.max(0, -nearestProj[0], nearestProj[0] - width);
|
|
46999
|
+
const overY = Math.max(0, -nearestProj[1], nearestProj[1] - height);
|
|
47000
|
+
if (overX <= width * EDGE_CLAMP_OVERSHOOT && overY <= height * EDGE_CLAMP_OVERSHOOT) {
|
|
47001
|
+
const halfW = Math.max(...wlines.map((l) => labelWidth(l, WATER_LETTER_SPACING))) / 2;
|
|
47002
|
+
const halfH = ((wlines.length - 1) * LINE_HEIGHT + FONT + 2 * PADY) / 2;
|
|
47003
|
+
const m = EDGE_CLAMP_MARGIN;
|
|
47004
|
+
best = [
|
|
47005
|
+
Math.min(Math.max(nearestProj[0], halfW + m), width - halfW - m),
|
|
47006
|
+
Math.min(Math.max(nearestProj[1], halfH + m), height - halfH - m)
|
|
47007
|
+
];
|
|
47008
|
+
}
|
|
47009
|
+
}
|
|
47010
|
+
if (!best) continue;
|
|
47011
|
+
candidates.push({
|
|
47012
|
+
text: name,
|
|
47013
|
+
lines: wlines,
|
|
47014
|
+
cx: best[0],
|
|
47015
|
+
cy: best[1],
|
|
47016
|
+
italic: true,
|
|
47017
|
+
letterSpacing: WATER_LETTER_SPACING,
|
|
47018
|
+
color: waterColor,
|
|
47019
|
+
// Water before any country (×1000), then by tier, then kind, then name.
|
|
47020
|
+
sort: tier * 10 + KIND_ORDER[kind]
|
|
46275
47021
|
});
|
|
46276
|
-
}
|
|
46277
|
-
|
|
46278
|
-
|
|
46279
|
-
|
|
46280
|
-
|
|
47022
|
+
}
|
|
47023
|
+
const ranked = countries.map((c) => {
|
|
47024
|
+
const [x0, y0, x1, y1] = c.bbox;
|
|
47025
|
+
const w = x1 - x0;
|
|
47026
|
+
const h = y1 - y0;
|
|
47027
|
+
return { c, w, h, area: w * h };
|
|
47028
|
+
}).filter((r) => Number.isFinite(r.area) && r.area > 0).sort((a, b) => b.area - a.area);
|
|
47029
|
+
let ci = 0;
|
|
47030
|
+
for (const r of ranked) {
|
|
47031
|
+
const { c, w, h } = r;
|
|
47032
|
+
if (w > width * 0.66 || h > height * 0.66) continue;
|
|
47033
|
+
if (!insideViewport(c.anchor, width, height)) continue;
|
|
47034
|
+
const text = c.name;
|
|
47035
|
+
const tw = labelWidth(text, 0);
|
|
47036
|
+
if (tw > w || FONT + 2 * PADY > h) continue;
|
|
47037
|
+
candidates.push({
|
|
47038
|
+
text,
|
|
47039
|
+
lines: [text],
|
|
47040
|
+
cx: c.anchor[0],
|
|
47041
|
+
cy: c.anchor[1],
|
|
47042
|
+
italic: false,
|
|
47043
|
+
letterSpacing: 0,
|
|
47044
|
+
color: countryColor,
|
|
47045
|
+
// Always after every water body (+1e6); larger area = earlier.
|
|
47046
|
+
sort: 1e6 + ci++
|
|
47047
|
+
});
|
|
47048
|
+
}
|
|
47049
|
+
candidates.sort((a, b) => a.sort - b.sort);
|
|
47050
|
+
const placed = [];
|
|
47051
|
+
const placedRects = [];
|
|
47052
|
+
for (const cand of candidates) {
|
|
47053
|
+
if (placed.length >= budget) break;
|
|
47054
|
+
const rect = rectAround(cand.cx, cand.cy, cand.lines, cand.letterSpacing);
|
|
47055
|
+
if (!rectFits(rect, width, height)) continue;
|
|
47056
|
+
if (cand.italic && overLand) {
|
|
47057
|
+
const inset = 2;
|
|
47058
|
+
const top = cand.cy - (cand.lines.length - 1) / 2 * LINE_HEIGHT;
|
|
47059
|
+
const touchesLand = cand.lines.some((line12, li) => {
|
|
47060
|
+
const lw = labelWidth(line12, cand.letterSpacing);
|
|
47061
|
+
const x0 = cand.cx - lw / 2 + inset;
|
|
47062
|
+
const x1 = cand.cx + lw / 2 - inset;
|
|
47063
|
+
const xs = [x0, (x0 + cand.cx) / 2, cand.cx, (cand.cx + x1) / 2, x1];
|
|
47064
|
+
const base = top + li * LINE_HEIGHT;
|
|
47065
|
+
return [base, base - FONT * 0.4, base - FONT * 0.8].some(
|
|
47066
|
+
(y) => xs.some((x) => overLand(x, y))
|
|
47067
|
+
);
|
|
47068
|
+
});
|
|
47069
|
+
if (touchesLand) continue;
|
|
47070
|
+
}
|
|
47071
|
+
if (collides(rect)) continue;
|
|
47072
|
+
if (placedRects.some((r) => overlapsPadded(rect, r, CONTEXT_PAD))) continue;
|
|
47073
|
+
placedRects.push(rect);
|
|
47074
|
+
placed.push({
|
|
47075
|
+
x: cand.cx,
|
|
47076
|
+
y: cand.cy,
|
|
47077
|
+
text: cand.text,
|
|
47078
|
+
anchor: "middle",
|
|
47079
|
+
color: cand.color,
|
|
47080
|
+
// No halo: the bg-coloured outline reads as a ghost box behind the text
|
|
47081
|
+
// over the tinted water/land. Context labels are muted enough to sit
|
|
47082
|
+
// cleanly on the basemap without one.
|
|
47083
|
+
halo: false,
|
|
47084
|
+
haloColor,
|
|
47085
|
+
italic: cand.italic,
|
|
47086
|
+
letterSpacing: cand.letterSpacing,
|
|
47087
|
+
...cand.lines.length > 1 ? { lines: cand.lines } : {},
|
|
47088
|
+
lineNumber: 0
|
|
47089
|
+
});
|
|
47090
|
+
}
|
|
47091
|
+
return placed;
|
|
46281
47092
|
}
|
|
46282
|
-
var
|
|
46283
|
-
var
|
|
46284
|
-
"src/map/
|
|
47093
|
+
var FONT, LINE_HEIGHT, PADX, PADY, WATER_LETTER_SPACING, CONTEXT_PAD, EDGE_CLAMP_MARGIN, EDGE_CLAMP_OVERSHOOT, KIND_ORDER;
|
|
47094
|
+
var init_context_labels = __esm({
|
|
47095
|
+
"src/map/context-labels.ts"() {
|
|
46285
47096
|
"use strict";
|
|
46286
|
-
|
|
46287
|
-
|
|
46288
|
-
|
|
46289
|
-
|
|
46290
|
-
|
|
46291
|
-
|
|
46292
|
-
|
|
46293
|
-
|
|
46294
|
-
|
|
46295
|
-
|
|
47097
|
+
init_color_utils();
|
|
47098
|
+
init_legend_constants();
|
|
47099
|
+
FONT = 11;
|
|
47100
|
+
LINE_HEIGHT = FONT + 2;
|
|
47101
|
+
PADX = 4;
|
|
47102
|
+
PADY = 3;
|
|
47103
|
+
WATER_LETTER_SPACING = 1.5;
|
|
47104
|
+
CONTEXT_PAD = 4;
|
|
47105
|
+
EDGE_CLAMP_MARGIN = 8;
|
|
47106
|
+
EDGE_CLAMP_OVERSHOOT = 0.35;
|
|
47107
|
+
KIND_ORDER = {
|
|
47108
|
+
ocean: 0,
|
|
47109
|
+
sea: 1,
|
|
47110
|
+
gulf: 2,
|
|
47111
|
+
bay: 3,
|
|
47112
|
+
strait: 4,
|
|
47113
|
+
channel: 5,
|
|
47114
|
+
sound: 6
|
|
46296
47115
|
};
|
|
46297
|
-
CANDIDATE_DIRS = [
|
|
46298
|
-
"./data",
|
|
46299
|
-
"./map-data",
|
|
46300
|
-
"../map-data",
|
|
46301
|
-
"../src/map/data"
|
|
46302
|
-
];
|
|
46303
47116
|
}
|
|
46304
47117
|
});
|
|
46305
47118
|
|
|
@@ -46308,12 +47121,34 @@ function geomObject2(topo) {
|
|
|
46308
47121
|
const key = Object.keys(topo.objects)[0];
|
|
46309
47122
|
return topo.objects[key];
|
|
46310
47123
|
}
|
|
47124
|
+
function mergeFeatures(a, b) {
|
|
47125
|
+
const polysOf = (f) => {
|
|
47126
|
+
const g = f.geometry;
|
|
47127
|
+
if (!g) return null;
|
|
47128
|
+
if (g.type === "Polygon") return [g.coordinates];
|
|
47129
|
+
if (g.type === "MultiPolygon") return g.coordinates;
|
|
47130
|
+
return null;
|
|
47131
|
+
};
|
|
47132
|
+
const pa = polysOf(a);
|
|
47133
|
+
const pb = polysOf(b);
|
|
47134
|
+
if (!pa || !pb) return a;
|
|
47135
|
+
return {
|
|
47136
|
+
...a,
|
|
47137
|
+
geometry: { type: "MultiPolygon", coordinates: [...pa, ...pb] }
|
|
47138
|
+
};
|
|
47139
|
+
}
|
|
46311
47140
|
function decodeLayer(topo) {
|
|
47141
|
+
const cached = decodeCache.get(topo);
|
|
47142
|
+
if (cached) return cached;
|
|
46312
47143
|
const out = /* @__PURE__ */ new Map();
|
|
46313
47144
|
for (const g of geomObject2(topo).geometries) {
|
|
46314
47145
|
const f = (0, import_topojson_client2.feature)(topo, g);
|
|
46315
|
-
|
|
47146
|
+
if (!f.geometry) continue;
|
|
47147
|
+
const tagged = { ...f, id: g.id };
|
|
47148
|
+
const existing = out.get(g.id);
|
|
47149
|
+
out.set(g.id, existing ? mergeFeatures(existing, tagged) : tagged);
|
|
46316
47150
|
}
|
|
47151
|
+
decodeCache.set(topo, out);
|
|
46317
47152
|
return out;
|
|
46318
47153
|
}
|
|
46319
47154
|
function projectionFor(family) {
|
|
@@ -46322,38 +47157,35 @@ function projectionFor(family) {
|
|
|
46322
47157
|
return usConusProjection();
|
|
46323
47158
|
case "mercator":
|
|
46324
47159
|
return (0, import_d3_geo2.geoMercator)();
|
|
47160
|
+
case "equal-earth":
|
|
47161
|
+
return (0, import_d3_geo2.geoEqualEarth)();
|
|
47162
|
+
case "equirectangular":
|
|
47163
|
+
return (0, import_d3_geo2.geoEquirectangular)();
|
|
46325
47164
|
case "natural-earth":
|
|
46326
47165
|
return (0, import_d3_geo2.geoNaturalEarth1)();
|
|
46327
|
-
case "equirectangular":
|
|
46328
47166
|
default:
|
|
46329
47167
|
return (0, import_d3_geo2.geoEquirectangular)();
|
|
46330
47168
|
}
|
|
46331
47169
|
}
|
|
46332
|
-
function mapBackgroundColor(palette, isDark = false,
|
|
46333
|
-
|
|
46334
|
-
|
|
46335
|
-
|
|
46336
|
-
|
|
46337
|
-
|
|
46338
|
-
);
|
|
46339
|
-
return mix(palette.colors.blue, palette.bg, WATER_TINT);
|
|
47170
|
+
function mapBackgroundColor(palette, isDark = false, _dataActive = false) {
|
|
47171
|
+
return mix(
|
|
47172
|
+
palette.colors.blue,
|
|
47173
|
+
palette.bg,
|
|
47174
|
+
isDark ? WATER_TINT_DARK : WATER_TINT_LIGHT
|
|
47175
|
+
);
|
|
46340
47176
|
}
|
|
46341
|
-
function mapNeutralLandColor(palette, isDark,
|
|
46342
|
-
if (dataActive)
|
|
46343
|
-
return isDark ? mix(palette.colors.gray, palette.bg, MUTED_LAND_DARK) : palette.bg;
|
|
47177
|
+
function mapNeutralLandColor(palette, isDark, _dataActive = false) {
|
|
46344
47178
|
return mix(
|
|
46345
47179
|
palette.colors.green,
|
|
46346
47180
|
palette.bg,
|
|
46347
47181
|
isDark ? LAND_TINT_DARK : LAND_TINT_LIGHT
|
|
46348
47182
|
);
|
|
46349
47183
|
}
|
|
46350
|
-
function
|
|
46351
|
-
const { palette, isDark } = opts;
|
|
46352
|
-
const { width, height } = size;
|
|
47184
|
+
function buildMapProjection(resolved, data) {
|
|
46353
47185
|
const wantsUsStates = resolved.basemaps.subdivisions.includes("us-states");
|
|
46354
|
-
const usCrisp = resolved.projection === "albers-usa" && wantsUsStates && !!data.naLand;
|
|
47186
|
+
const usCrisp = (resolved.projection === "albers-usa" || resolved.projection === "mercator") && wantsUsStates && !!data.naLand;
|
|
46355
47187
|
const worldTopo = usCrisp ? data.worldDetail : resolved.basemaps.world === "detail" ? data.worldDetail : data.worldCoarse;
|
|
46356
|
-
const worldLayer = decodeLayer(worldTopo);
|
|
47188
|
+
const worldLayer = new Map(decodeLayer(worldTopo));
|
|
46357
47189
|
if (usCrisp && data.naLand) {
|
|
46358
47190
|
const [nbW, nbS, nbE, nbN] = [-140, 10, -52, 66];
|
|
46359
47191
|
const crisp = decodeLayer(data.naLand);
|
|
@@ -46362,17 +47194,110 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46362
47194
|
if (!base) continue;
|
|
46363
47195
|
const [[bw, bs], [be, bn]] = (0, import_d3_geo2.geoBounds)(base);
|
|
46364
47196
|
if (bw >= nbW && be <= nbE && bs >= nbS && bn <= nbN)
|
|
46365
|
-
worldLayer.set(iso, cf);
|
|
47197
|
+
worldLayer.set(iso, { ...cf, properties: base.properties });
|
|
46366
47198
|
}
|
|
46367
47199
|
}
|
|
46368
47200
|
const usLayer = wantsUsStates ? decodeLayer(data.usStates) : null;
|
|
47201
|
+
const extentOutline = () => {
|
|
47202
|
+
const [[w, s], [e, n]] = resolved.extent;
|
|
47203
|
+
const N = 16;
|
|
47204
|
+
const coords = [];
|
|
47205
|
+
for (let i = 0; i <= N; i++) {
|
|
47206
|
+
const t = i / N;
|
|
47207
|
+
const lon = w + (e - w) * t;
|
|
47208
|
+
const lat = s + (n - s) * t;
|
|
47209
|
+
coords.push([lon, s], [lon, n], [w, lat], [e, lat]);
|
|
47210
|
+
}
|
|
47211
|
+
return {
|
|
47212
|
+
type: "Feature",
|
|
47213
|
+
properties: {},
|
|
47214
|
+
geometry: { type: "MultiPoint", coordinates: coords }
|
|
47215
|
+
};
|
|
47216
|
+
};
|
|
47217
|
+
let fitFeatures;
|
|
47218
|
+
if (resolved.projection === "albers-usa" && usLayer) {
|
|
47219
|
+
fitFeatures = [...usLayer.entries()].filter(([iso]) => !US_NON_CONUS.has(iso)).map(([, f]) => f);
|
|
47220
|
+
const neighborPoints = resolved.pois.filter((p) => !inAlaska(p.lon, p.lat) && !inHawaii(p.lon, p.lat)).map((p) => [p.lon, p.lat]);
|
|
47221
|
+
if (neighborPoints.length > 0) {
|
|
47222
|
+
fitFeatures.push({
|
|
47223
|
+
type: "Feature",
|
|
47224
|
+
properties: {},
|
|
47225
|
+
geometry: { type: "MultiPoint", coordinates: neighborPoints }
|
|
47226
|
+
});
|
|
47227
|
+
}
|
|
47228
|
+
for (const r of resolved.regions) {
|
|
47229
|
+
if (r.layer === "country" && (r.iso === "CA" || r.iso === "MX")) {
|
|
47230
|
+
const cf = worldLayer.get(r.iso);
|
|
47231
|
+
if (cf) fitFeatures.push(cf);
|
|
47232
|
+
}
|
|
47233
|
+
}
|
|
47234
|
+
} else {
|
|
47235
|
+
fitFeatures = [extentOutline()];
|
|
47236
|
+
}
|
|
47237
|
+
const fitTarget = { type: "FeatureCollection", features: fitFeatures };
|
|
47238
|
+
const projection = projectionFor(resolved.projection);
|
|
47239
|
+
if (resolved.projection !== "albers-usa") {
|
|
47240
|
+
let centerLon = (resolved.extent[0][0] + resolved.extent[1][0]) / 2;
|
|
47241
|
+
if (centerLon > 180) centerLon -= 360;
|
|
47242
|
+
projection.rotate([-centerLon, 0]);
|
|
47243
|
+
}
|
|
47244
|
+
const fitGB = (0, import_d3_geo2.geoBounds)(fitTarget);
|
|
47245
|
+
const fitIsGlobal = fitGB[1][0] - fitGB[0][0] >= 270 || fitGB[1][1] - fitGB[0][1] >= 130;
|
|
47246
|
+
return {
|
|
47247
|
+
projection,
|
|
47248
|
+
fitTarget,
|
|
47249
|
+
fitIsGlobal,
|
|
47250
|
+
worldLayer,
|
|
47251
|
+
usLayer,
|
|
47252
|
+
usCrisp,
|
|
47253
|
+
wantsUsStates,
|
|
47254
|
+
worldTopo
|
|
47255
|
+
};
|
|
47256
|
+
}
|
|
47257
|
+
function parsePathRings(d) {
|
|
47258
|
+
const rings = [];
|
|
47259
|
+
let cur = [];
|
|
47260
|
+
const re = /([MLZ])([^MLZ]*)/g;
|
|
47261
|
+
let m;
|
|
47262
|
+
while (m = re.exec(d)) {
|
|
47263
|
+
if (m[1] === "Z") {
|
|
47264
|
+
if (cur.length) rings.push(cur);
|
|
47265
|
+
cur = [];
|
|
47266
|
+
continue;
|
|
47267
|
+
}
|
|
47268
|
+
if (m[1] === "M" && cur.length) {
|
|
47269
|
+
rings.push(cur);
|
|
47270
|
+
cur = [];
|
|
47271
|
+
}
|
|
47272
|
+
const nums = m[2].split(/[ ,]+/).map(Number);
|
|
47273
|
+
for (let i = 0; i + 1 < nums.length; i += 2) {
|
|
47274
|
+
const x = nums[i];
|
|
47275
|
+
const y = nums[i + 1];
|
|
47276
|
+
if (Number.isFinite(x) && Number.isFinite(y)) cur.push([x, y]);
|
|
47277
|
+
}
|
|
47278
|
+
}
|
|
47279
|
+
if (cur.length) rings.push(cur);
|
|
47280
|
+
return rings;
|
|
47281
|
+
}
|
|
47282
|
+
function layoutMap(resolved, data, size, opts) {
|
|
47283
|
+
const { palette, isDark } = opts;
|
|
47284
|
+
const { width, height } = size;
|
|
47285
|
+
const {
|
|
47286
|
+
projection,
|
|
47287
|
+
fitTarget,
|
|
47288
|
+
fitIsGlobal,
|
|
47289
|
+
worldLayer,
|
|
47290
|
+
usLayer,
|
|
47291
|
+
usCrisp,
|
|
47292
|
+
worldTopo
|
|
47293
|
+
} = buildMapProjection(resolved, data);
|
|
46369
47294
|
const usContext = usLayer !== null;
|
|
46370
47295
|
const regionStroke = isDark ? mix(palette.bg, palette.text, 78) : mix(palette.text, palette.bg, 78);
|
|
46371
47296
|
const values = resolved.regions.filter((r) => r.value !== void 0).map((r) => r.value);
|
|
46372
|
-
const
|
|
46373
|
-
const rampMin =
|
|
46374
|
-
const rampMax =
|
|
46375
|
-
const rampHue = palette.colors.red;
|
|
47297
|
+
const allNonNegative = values.length > 0 && values.every((v) => v >= 0);
|
|
47298
|
+
const rampMin = allNonNegative ? 0 : Math.min(...values);
|
|
47299
|
+
const rampMax = Math.max(...values);
|
|
47300
|
+
const rampHue = resolveColor(resolved.directives.regionMetricColor ?? "", palette) ?? palette.colors.red;
|
|
46376
47301
|
const hasRamp = values.length > 0;
|
|
46377
47302
|
const VALUE_NAME = hasRamp ? resolved.directives.regionMetric?.trim() || "Value" : null;
|
|
46378
47303
|
const matchColorGroup = (v) => {
|
|
@@ -46392,14 +47317,48 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46392
47317
|
activeGroup = VALUE_NAME ?? (resolved.tagGroups.length > 0 ? resolved.tagGroups[0].name : null);
|
|
46393
47318
|
}
|
|
46394
47319
|
const activeIsScore = VALUE_NAME !== null && activeGroup === VALUE_NAME;
|
|
46395
|
-
const mutedBasemap =
|
|
47320
|
+
const mutedBasemap = activeGroup !== null;
|
|
46396
47321
|
const neutralFill = mapNeutralLandColor(palette, isDark, mutedBasemap);
|
|
46397
47322
|
const water = mapBackgroundColor(palette, isDark, mutedBasemap);
|
|
47323
|
+
const lakeStroke = mix(regionStroke, water, 45);
|
|
46398
47324
|
const foreignFill = mix(
|
|
46399
47325
|
palette.colors.gray,
|
|
46400
47326
|
palette.bg,
|
|
46401
47327
|
mutedBasemap ? isDark ? MUTED_FOREIGN_DARK : MUTED_FOREIGN_LIGHT : isDark ? FOREIGN_TINT_DARK : FOREIGN_TINT_LIGHT
|
|
46402
47328
|
);
|
|
47329
|
+
const colorizeActive = resolved.directives.noColorize !== true && !hasRamp && resolved.tagGroups.length === 0;
|
|
47330
|
+
const colorByIso = /* @__PURE__ */ new Map();
|
|
47331
|
+
if (colorizeActive) {
|
|
47332
|
+
const adjacency = /* @__PURE__ */ new Map();
|
|
47333
|
+
const addEdges = (src) => {
|
|
47334
|
+
for (const [iso, ns] of src) {
|
|
47335
|
+
const cur = adjacency.get(iso);
|
|
47336
|
+
if (cur) cur.push(...ns);
|
|
47337
|
+
else adjacency.set(iso, [...ns]);
|
|
47338
|
+
}
|
|
47339
|
+
};
|
|
47340
|
+
addEdges(buildAdjacency(worldTopo));
|
|
47341
|
+
if (usLayer) {
|
|
47342
|
+
addEdges(buildAdjacency(data.usStates));
|
|
47343
|
+
for (const [country, states] of Object.entries(FOREIGN_BORDER)) {
|
|
47344
|
+
const cn = adjacency.get(country);
|
|
47345
|
+
if (!cn) continue;
|
|
47346
|
+
for (const st of states) {
|
|
47347
|
+
const sn = adjacency.get(st);
|
|
47348
|
+
if (!sn) continue;
|
|
47349
|
+
cn.push(st);
|
|
47350
|
+
sn.push(country);
|
|
47351
|
+
}
|
|
47352
|
+
}
|
|
47353
|
+
}
|
|
47354
|
+
const { byIso, huesNeeded } = assignColors(
|
|
47355
|
+
[...adjacency.keys()],
|
|
47356
|
+
adjacency
|
|
47357
|
+
);
|
|
47358
|
+
const tints = politicalTints(palette, huesNeeded, isDark);
|
|
47359
|
+
for (const [iso, idx] of byIso) colorByIso.set(iso, tints[idx]);
|
|
47360
|
+
}
|
|
47361
|
+
const colorizeStroke = (fill2) => mix(fill2, palette.text, 35);
|
|
46403
47362
|
const rampBase = isDark ? mix(palette.surface, palette.text, 28) : palette.bg;
|
|
46404
47363
|
const fillForValue = (s) => {
|
|
46405
47364
|
const t = rampMax > rampMin ? (s - rampMin) / (rampMax - rampMin) : 1;
|
|
@@ -46424,47 +47383,26 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46424
47383
|
isDark ? TAG_TINT_DARK : TAG_TINT_LIGHT
|
|
46425
47384
|
);
|
|
46426
47385
|
};
|
|
47386
|
+
const directFill = (name) => {
|
|
47387
|
+
const hex = name ? resolveColor(name, palette) : null;
|
|
47388
|
+
if (!hex) return null;
|
|
47389
|
+
return mix(hex, palette.bg, isDark ? TAG_TINT_DARK : TAG_TINT_LIGHT);
|
|
47390
|
+
};
|
|
46427
47391
|
const regionFill = (r) => {
|
|
47392
|
+
const direct = directFill(r.color);
|
|
47393
|
+
if (direct) return direct;
|
|
46428
47394
|
if (activeIsScore) {
|
|
46429
47395
|
return r.value !== void 0 ? fillForValue(r.value) : neutralFill;
|
|
46430
47396
|
}
|
|
47397
|
+
if (colorizeActive) return (r.iso && colorByIso.get(r.iso)) ?? neutralFill;
|
|
46431
47398
|
return tagFill(r.tags, activeGroup) ?? neutralFill;
|
|
46432
47399
|
};
|
|
46433
47400
|
const regionById = new Map(resolved.regions.map((r) => [r.iso, r]));
|
|
46434
|
-
const
|
|
46435
|
-
const [[w, s], [e, n]] = resolved.extent;
|
|
46436
|
-
const N = 16;
|
|
46437
|
-
const coords = [];
|
|
46438
|
-
for (let i = 0; i <= N; i++) {
|
|
46439
|
-
const t = i / N;
|
|
46440
|
-
const lon = w + (e - w) * t;
|
|
46441
|
-
const lat = s + (n - s) * t;
|
|
46442
|
-
coords.push([lon, s], [lon, n], [w, lat], [e, lat]);
|
|
46443
|
-
}
|
|
46444
|
-
return {
|
|
46445
|
-
type: "Feature",
|
|
46446
|
-
properties: {},
|
|
46447
|
-
geometry: { type: "MultiPoint", coordinates: coords }
|
|
46448
|
-
};
|
|
46449
|
-
};
|
|
46450
|
-
let fitFeatures;
|
|
46451
|
-
if (resolved.projection === "albers-usa" && usLayer) {
|
|
46452
|
-
fitFeatures = [...usLayer.entries()].filter(([iso]) => !US_NON_CONUS.has(iso)).map(([, f]) => f);
|
|
46453
|
-
} else {
|
|
46454
|
-
fitFeatures = [extentOutline()];
|
|
46455
|
-
}
|
|
46456
|
-
const fitTarget = { type: "FeatureCollection", features: fitFeatures };
|
|
46457
|
-
const projection = projectionFor(resolved.projection);
|
|
46458
|
-
if (resolved.projection !== "albers-usa") {
|
|
46459
|
-
let centerLon = (resolved.extent[0][0] + resolved.extent[1][0]) / 2;
|
|
46460
|
-
if (centerLon > 180) centerLon -= 360;
|
|
46461
|
-
projection.rotate([-centerLon, 0]);
|
|
46462
|
-
}
|
|
46463
|
-
const TITLE_GAP = 16;
|
|
47401
|
+
const TITLE_GAP2 = 16;
|
|
46464
47402
|
let topPad = FIT_PAD;
|
|
46465
47403
|
if (resolved.title && resolved.pois.length > 0) {
|
|
46466
47404
|
const bannerBottom = (resolved.subtitle ? TITLE_Y + TITLE_FONT_SIZE : TITLE_Y) + TITLE_FONT_SIZE / 2;
|
|
46467
|
-
topPad = Math.max(FIT_PAD, bannerBottom +
|
|
47405
|
+
topPad = Math.max(FIT_PAD, bannerBottom + TITLE_GAP2);
|
|
46468
47406
|
}
|
|
46469
47407
|
const fitBox = [
|
|
46470
47408
|
[FIT_PAD, topPad],
|
|
@@ -46474,11 +47412,10 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46474
47412
|
]
|
|
46475
47413
|
];
|
|
46476
47414
|
projection.fitExtent(fitBox, fitTarget);
|
|
46477
|
-
const fitGB = (0, import_d3_geo2.geoBounds)(fitTarget);
|
|
46478
|
-
const fitIsGlobal = fitGB[1][0] - fitGB[0][0] >= 270 || fitGB[1][1] - fitGB[0][1] >= 130;
|
|
46479
47415
|
let path;
|
|
46480
47416
|
let project;
|
|
46481
|
-
|
|
47417
|
+
let stretchParams = null;
|
|
47418
|
+
if (fitIsGlobal && !opts.preferContain) {
|
|
46482
47419
|
const cb = (0, import_d3_geo2.geoPath)(projection).bounds(fitTarget);
|
|
46483
47420
|
const bx0 = cb[0][0];
|
|
46484
47421
|
const by0 = cb[0][1];
|
|
@@ -46488,6 +47425,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46488
47425
|
const oy = fitBox[0][1];
|
|
46489
47426
|
const sx = cw > 0 ? (fitBox[1][0] - ox) / cw : 1;
|
|
46490
47427
|
const sy = ch > 0 ? (fitBox[1][1] - oy) / ch : 1;
|
|
47428
|
+
stretchParams = { sx, sy, ox, oy, bx0, by0 };
|
|
46491
47429
|
const stretch = (x, y) => [
|
|
46492
47430
|
ox + (x - bx0) * sx,
|
|
46493
47431
|
oy + (y - by0) * sy
|
|
@@ -46519,7 +47457,9 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46519
47457
|
const insets = [];
|
|
46520
47458
|
const insetRegions = [];
|
|
46521
47459
|
const insetLabelSeeds = [];
|
|
46522
|
-
|
|
47460
|
+
const akRef = resolved.regions.some((r) => r.iso === "US-AK") || resolved.pois.some((p) => inAlaska(p.lon, p.lat));
|
|
47461
|
+
const hiRef = resolved.regions.some((r) => r.iso === "US-HI") || resolved.pois.some((p) => inHawaii(p.lon, p.lat));
|
|
47462
|
+
if (resolved.projection === "albers-usa" && usLayer && (akRef || hiRef)) {
|
|
46523
47463
|
const PAD = 8;
|
|
46524
47464
|
const GAP = 12;
|
|
46525
47465
|
const yB = height - FIT_PAD;
|
|
@@ -46550,38 +47490,14 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46550
47490
|
}
|
|
46551
47491
|
return y;
|
|
46552
47492
|
};
|
|
46553
|
-
const
|
|
47493
|
+
const coastFloor = (x0, xr) => {
|
|
46554
47494
|
const n = 24;
|
|
46555
|
-
const pts = [];
|
|
46556
47495
|
let maxY = -Infinity;
|
|
46557
47496
|
for (let i = 0; i <= n; i++) {
|
|
46558
|
-
const
|
|
46559
|
-
|
|
46560
|
-
|
|
46561
|
-
|
|
46562
|
-
if (y > maxY) maxY = y;
|
|
46563
|
-
}
|
|
46564
|
-
}
|
|
46565
|
-
if (pts.length === 0) return () => yB - height * 0.42;
|
|
46566
|
-
let m = 0;
|
|
46567
|
-
if (pts.length >= 2) {
|
|
46568
|
-
let sx = 0, sy = 0, sxx = 0, sxy = 0;
|
|
46569
|
-
for (const [x, y] of pts) {
|
|
46570
|
-
sx += x;
|
|
46571
|
-
sy += y;
|
|
46572
|
-
sxx += x * x;
|
|
46573
|
-
sxy += x * y;
|
|
46574
|
-
}
|
|
46575
|
-
const den = pts.length * sxx - sx * sx;
|
|
46576
|
-
if (den !== 0) m = (pts.length * sxy - sx * sy) / den;
|
|
46577
|
-
}
|
|
46578
|
-
m = Math.max(-0.35, Math.min(0.35, m));
|
|
46579
|
-
let c = -Infinity;
|
|
46580
|
-
for (const [x, y] of pts) {
|
|
46581
|
-
const need = y - m * x + GAP;
|
|
46582
|
-
if (need > c) c = need;
|
|
46583
|
-
}
|
|
46584
|
-
return (x) => m * x + c;
|
|
47497
|
+
const y = at(x0 + (xr - x0) * i / n);
|
|
47498
|
+
if (y > maxY) maxY = y;
|
|
47499
|
+
}
|
|
47500
|
+
return maxY;
|
|
46585
47501
|
};
|
|
46586
47502
|
const placeInset = (iso, proj, boxX, iwReq) => {
|
|
46587
47503
|
const f = usLayer.get(iso);
|
|
@@ -46590,19 +47506,15 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46590
47506
|
const iw = Math.min(iwReq, width - FIT_PAD - x0 - 2 * PAD);
|
|
46591
47507
|
if (iw < 24) return boxX;
|
|
46592
47508
|
const xr = x0 + iw + 2 * PAD;
|
|
46593
|
-
const
|
|
46594
|
-
const
|
|
46595
|
-
const yR = top(xr);
|
|
47509
|
+
const floor = coastFloor(x0, xr);
|
|
47510
|
+
const topGuess = floor > -Infinity ? floor + GAP : yB - height * 0.42;
|
|
46596
47511
|
proj.fitWidth(iw, f);
|
|
46597
47512
|
const bb = (0, import_d3_geo2.geoPath)(proj).bounds(f);
|
|
46598
47513
|
const sh = Number.isFinite(bb[0][0]) ? bb[1][1] - bb[0][1] : iw;
|
|
46599
47514
|
const needH = sh + 2 * PAD;
|
|
46600
|
-
let topFit =
|
|
47515
|
+
let topFit = topGuess;
|
|
46601
47516
|
const bottom = Math.min(topFit + needH, yB);
|
|
46602
47517
|
if (bottom - topFit < needH) topFit = bottom - needH;
|
|
46603
|
-
const lift = topFit - Math.max(yL, yR);
|
|
46604
|
-
const topL = yL + lift;
|
|
46605
|
-
const topR = yR + lift;
|
|
46606
47518
|
proj.fitExtent(
|
|
46607
47519
|
[
|
|
46608
47520
|
[x0 + PAD, topFit + PAD],
|
|
@@ -46612,8 +47524,18 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46612
47524
|
);
|
|
46613
47525
|
const d = (0, import_d3_geo2.geoPath)(proj)(f) ?? "";
|
|
46614
47526
|
if (!d) return xr;
|
|
47527
|
+
let contextLand;
|
|
47528
|
+
if (iso === "US-AK") {
|
|
47529
|
+
const can = worldLayer.get("CA");
|
|
47530
|
+
const cd = can ? (0, import_d3_geo2.geoPath)(proj)(can) ?? "" : "";
|
|
47531
|
+
if (cd)
|
|
47532
|
+
contextLand = {
|
|
47533
|
+
d: cd,
|
|
47534
|
+
fill: colorizeActive ? colorByIso.get("CA") ?? foreignFill : foreignFill
|
|
47535
|
+
};
|
|
47536
|
+
}
|
|
46615
47537
|
const r = regionById.get(iso);
|
|
46616
|
-
let fill2 = neutralFill;
|
|
47538
|
+
let fill2 = colorizeActive ? colorByIso.get(iso) ?? neutralFill : neutralFill;
|
|
46617
47539
|
let lineNumber = -1;
|
|
46618
47540
|
if (r?.layer === "us-state") {
|
|
46619
47541
|
fill2 = regionFill(r);
|
|
@@ -46621,21 +47543,25 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46621
47543
|
}
|
|
46622
47544
|
insets.push({
|
|
46623
47545
|
x: x0,
|
|
46624
|
-
y:
|
|
47546
|
+
y: topFit,
|
|
46625
47547
|
w: xr - x0,
|
|
46626
|
-
h: bottom -
|
|
47548
|
+
h: bottom - topFit,
|
|
46627
47549
|
points: [
|
|
46628
|
-
[x0,
|
|
46629
|
-
[xr,
|
|
47550
|
+
[x0, topFit],
|
|
47551
|
+
[xr, topFit],
|
|
46630
47552
|
[xr, bottom],
|
|
46631
47553
|
[x0, bottom]
|
|
46632
|
-
]
|
|
47554
|
+
],
|
|
47555
|
+
// The FITTED inset projection (just fit to this box) — captured so the
|
|
47556
|
+
// geo-query can invert pixels inside the frame back to AK/HI coords.
|
|
47557
|
+
projection: proj,
|
|
47558
|
+
...contextLand && { contextLand }
|
|
46633
47559
|
});
|
|
46634
47560
|
insetRegions.push({
|
|
46635
47561
|
id: iso,
|
|
46636
47562
|
d,
|
|
46637
47563
|
fill: fill2,
|
|
46638
|
-
stroke: regionStroke,
|
|
47564
|
+
stroke: colorizeActive ? colorizeStroke(fill2) : regionStroke,
|
|
46639
47565
|
lineNumber,
|
|
46640
47566
|
layer: "us-state",
|
|
46641
47567
|
...r?.value !== void 0 && { value: r.value },
|
|
@@ -46648,13 +47574,16 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46648
47574
|
}
|
|
46649
47575
|
return xr;
|
|
46650
47576
|
};
|
|
46651
|
-
|
|
46652
|
-
|
|
46653
|
-
alaskaProjection(),
|
|
46654
|
-
|
|
46655
|
-
|
|
46656
|
-
|
|
46657
|
-
|
|
47577
|
+
let akRight = FIT_PAD;
|
|
47578
|
+
if (akRef)
|
|
47579
|
+
akRight = placeInset("US-AK", alaskaProjection(), FIT_PAD, width * 0.15);
|
|
47580
|
+
if (hiRef)
|
|
47581
|
+
placeInset(
|
|
47582
|
+
"US-HI",
|
|
47583
|
+
hawaiiProjection(),
|
|
47584
|
+
akRef ? akRight + 24 : FIT_PAD,
|
|
47585
|
+
width * 0.1
|
|
47586
|
+
);
|
|
46658
47587
|
}
|
|
46659
47588
|
const conusFit = resolved.projection === "albers-usa" && !!usLayer;
|
|
46660
47589
|
const classifyExtent = conusFit ? (0, import_d3_geo2.geoBounds)(fitTarget) : resolved.extent;
|
|
@@ -46670,15 +47599,24 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46670
47599
|
};
|
|
46671
47600
|
const ringOverlapsView = (ring) => {
|
|
46672
47601
|
let loMin = Infinity, loMax = -Infinity, rawMin = Infinity, rawMax = -Infinity;
|
|
47602
|
+
const lons = [];
|
|
46673
47603
|
for (const [rawLon] of ring) {
|
|
46674
47604
|
const lon = normLon(rawLon);
|
|
47605
|
+
lons.push(lon);
|
|
46675
47606
|
if (lon < loMin) loMin = lon;
|
|
46676
47607
|
if (lon > loMax) loMax = lon;
|
|
46677
47608
|
if (rawLon < rawMin) rawMin = rawLon;
|
|
46678
47609
|
if (rawLon > rawMax) rawMax = rawLon;
|
|
46679
47610
|
}
|
|
46680
|
-
|
|
46681
|
-
|
|
47611
|
+
lons.sort((a, b) => a - b);
|
|
47612
|
+
let maxGap = 0;
|
|
47613
|
+
for (let i = 1; i < lons.length; i++)
|
|
47614
|
+
maxGap = Math.max(maxGap, lons[i] - lons[i - 1]);
|
|
47615
|
+
if (lons.length > 1)
|
|
47616
|
+
maxGap = Math.max(maxGap, lons[0] + 360 - lons[lons.length - 1]);
|
|
47617
|
+
const occupiedArc = 360 - maxGap;
|
|
47618
|
+
if (occupiedArc > 270) return false;
|
|
47619
|
+
if (rawMax - rawMin > 180 && occupiedArc < 90) return false;
|
|
46682
47620
|
let px0 = Infinity, py0 = Infinity, px1 = -Infinity, py1 = -Infinity, anyFinite = false;
|
|
46683
47621
|
for (const [lon, lat] of ring) {
|
|
46684
47622
|
const p = project(lon, lat);
|
|
@@ -46751,7 +47689,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46751
47689
|
const regions = [];
|
|
46752
47690
|
const pushRegionLayer = (layerFeatures, layerKind, shouldCull) => {
|
|
46753
47691
|
for (const [iso, f] of layerFeatures) {
|
|
46754
|
-
if (layerKind === "us-state" && usContext && INSET_STATES.has(iso))
|
|
47692
|
+
if (layerKind === "us-state" && usContext && resolved.projection === "albers-usa" && INSET_STATES.has(iso))
|
|
46755
47693
|
continue;
|
|
46756
47694
|
if (layerKind === "country" && usContext && iso === "US") continue;
|
|
46757
47695
|
if (layerKind === "country" && iso === "AQ" && !regionById.has("AQ"))
|
|
@@ -46763,7 +47701,8 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46763
47701
|
if (!d) continue;
|
|
46764
47702
|
const isThisLayer = r?.layer === layerKind;
|
|
46765
47703
|
const isForeign = layerKind === "country" && usContext && iso !== "US";
|
|
46766
|
-
|
|
47704
|
+
const baseFill = isForeign ? foreignFill : neutralFill;
|
|
47705
|
+
let fill2 = colorizeActive ? colorByIso.get(iso) ?? baseFill : baseFill;
|
|
46767
47706
|
let label;
|
|
46768
47707
|
let lineNumber = -1;
|
|
46769
47708
|
let layer = "base";
|
|
@@ -46772,12 +47711,14 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46772
47711
|
lineNumber = r.lineNumber;
|
|
46773
47712
|
layer = layerKind;
|
|
46774
47713
|
label = r.name;
|
|
47714
|
+
} else {
|
|
47715
|
+
label = f.properties?.name;
|
|
46775
47716
|
}
|
|
46776
47717
|
regions.push({
|
|
46777
47718
|
id: iso,
|
|
46778
47719
|
d,
|
|
46779
47720
|
fill: fill2,
|
|
46780
|
-
stroke: regionStroke,
|
|
47721
|
+
stroke: colorizeActive ? colorizeStroke(fill2) : regionStroke,
|
|
46781
47722
|
lineNumber,
|
|
46782
47723
|
layer,
|
|
46783
47724
|
...label !== void 0 && { label },
|
|
@@ -46799,13 +47740,88 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46799
47740
|
id: "lake",
|
|
46800
47741
|
d,
|
|
46801
47742
|
fill: water,
|
|
46802
|
-
stroke:
|
|
47743
|
+
stroke: lakeStroke,
|
|
46803
47744
|
lineNumber: -1,
|
|
46804
47745
|
layer: "base"
|
|
46805
47746
|
});
|
|
46806
47747
|
}
|
|
46807
47748
|
}
|
|
46808
|
-
const
|
|
47749
|
+
const pointInRings = (px, py, rings) => {
|
|
47750
|
+
let inside = false;
|
|
47751
|
+
for (const ring of rings) {
|
|
47752
|
+
for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
|
|
47753
|
+
const [xi, yi] = ring[i];
|
|
47754
|
+
const [xj, yj] = ring[j];
|
|
47755
|
+
if (yi > py !== yj > py && px < (xj - xi) * (py - yi) / (yj - yi) + xi)
|
|
47756
|
+
inside = !inside;
|
|
47757
|
+
}
|
|
47758
|
+
}
|
|
47759
|
+
return inside;
|
|
47760
|
+
};
|
|
47761
|
+
const fillHitTargets = [...regions, ...insetRegions].map((r) => ({
|
|
47762
|
+
fill: r.fill,
|
|
47763
|
+
rings: parsePathRings(r.d)
|
|
47764
|
+
}));
|
|
47765
|
+
const fillAt = (x, y) => {
|
|
47766
|
+
let hit = water;
|
|
47767
|
+
for (const t of fillHitTargets)
|
|
47768
|
+
if (pointInRings(x, y, t.rings)) hit = t.fill;
|
|
47769
|
+
return hit;
|
|
47770
|
+
};
|
|
47771
|
+
const labelOnFill = (fill2) => {
|
|
47772
|
+
const color = contrastRatio(fill2, palette.textOnFillDark) >= contrastRatio(fill2, palette.textOnFillLight) ? palette.textOnFillDark : palette.textOnFillLight;
|
|
47773
|
+
const haloColor = color === palette.textOnFillLight ? palette.textOnFillDark : palette.textOnFillLight;
|
|
47774
|
+
return {
|
|
47775
|
+
color,
|
|
47776
|
+
halo: contrastRatio(fill2, color) < REGION_LABEL_HALO_RATIO,
|
|
47777
|
+
haloColor
|
|
47778
|
+
};
|
|
47779
|
+
};
|
|
47780
|
+
const reliefAllowed = resolved.directives.noRelief !== true;
|
|
47781
|
+
const relief = [];
|
|
47782
|
+
let reliefHatch = null;
|
|
47783
|
+
if (reliefAllowed && data.mountainRanges) {
|
|
47784
|
+
for (const [, f] of decodeLayer(data.mountainRanges)) {
|
|
47785
|
+
const viewF = isGlobalView ? dropFrameFillers(f) : cullFeatureToView(f);
|
|
47786
|
+
if (!viewF) continue;
|
|
47787
|
+
const area2 = path.area(viewF);
|
|
47788
|
+
if (!Number.isFinite(area2) || area2 < RELIEF_MIN_AREA) continue;
|
|
47789
|
+
const box = path.bounds(viewF);
|
|
47790
|
+
if (box[1][0] - box[0][0] < RELIEF_MIN_DIM || box[1][1] - box[0][1] < RELIEF_MIN_DIM)
|
|
47791
|
+
continue;
|
|
47792
|
+
const d = path(viewF) ?? "";
|
|
47793
|
+
if (!d) continue;
|
|
47794
|
+
relief.push({ d });
|
|
47795
|
+
}
|
|
47796
|
+
if (relief.length) {
|
|
47797
|
+
const darkTone = isDark ? palette.bg : palette.text;
|
|
47798
|
+
const lightTone = isDark ? palette.text : palette.bg;
|
|
47799
|
+
const reliefLandRef = colorizeActive ? isDark ? palette.surface : palette.bg : neutralFill;
|
|
47800
|
+
const landLum = relativeLuminance(reliefLandRef);
|
|
47801
|
+
const tone = Math.abs(landLum - relativeLuminance(darkTone)) > 0.04 ? darkTone : lightTone;
|
|
47802
|
+
reliefHatch = {
|
|
47803
|
+
color: mix(tone, reliefLandRef, RELIEF_HATCH_STRENGTH),
|
|
47804
|
+
spacing: RELIEF_HATCH_SPACING,
|
|
47805
|
+
width: RELIEF_HATCH_WIDTH
|
|
47806
|
+
};
|
|
47807
|
+
}
|
|
47808
|
+
}
|
|
47809
|
+
let coastlineStyle = null;
|
|
47810
|
+
if (resolved.directives.noCoastline !== true) {
|
|
47811
|
+
const minDim = Math.min(width, height);
|
|
47812
|
+
coastlineStyle = {
|
|
47813
|
+
color: mix(regionStroke, water, COASTLINE_STROKE_MIX),
|
|
47814
|
+
// N equal-width rings: distance steps outward by COASTLINE_STEP; opacity
|
|
47815
|
+
// fades linearly from NEAR (innermost) to FAR (outermost).
|
|
47816
|
+
lines: Array.from({ length: COASTLINE_RING_COUNT }, (_, k) => ({
|
|
47817
|
+
d: (COASTLINE_D0 + k * COASTLINE_STEP) * minDim,
|
|
47818
|
+
thickness: COASTLINE_THICKNESS * minDim,
|
|
47819
|
+
opacity: COASTLINE_OPACITY_NEAR + (COASTLINE_OPACITY_FAR - COASTLINE_OPACITY_NEAR) * k / (COASTLINE_RING_COUNT - 1)
|
|
47820
|
+
})),
|
|
47821
|
+
minExtent: (isGlobalView ? COASTLINE_MIN_EXTENT_GLOBAL : COASTLINE_MIN_EXTENT) * minDim
|
|
47822
|
+
};
|
|
47823
|
+
}
|
|
47824
|
+
const riverColor = mix(palette.colors.blue, water, 32);
|
|
46809
47825
|
const rivers = [];
|
|
46810
47826
|
if (data.rivers) {
|
|
46811
47827
|
for (const [, f] of decodeLayer(data.rivers)) {
|
|
@@ -46826,6 +47842,9 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46826
47842
|
return R_MIN + Math.max(0, Math.min(1, t)) * (R_MAX - R_MIN);
|
|
46827
47843
|
};
|
|
46828
47844
|
const poiFill = (p) => {
|
|
47845
|
+
const directHex = p.color ? resolveColor(p.color, palette) : null;
|
|
47846
|
+
if (directHex)
|
|
47847
|
+
return { fill: directHex, stroke: mix(directHex, palette.text, 18) };
|
|
46829
47848
|
for (const group of resolved.tagGroups) {
|
|
46830
47849
|
const val = p.tags[group.name.toLowerCase()];
|
|
46831
47850
|
if (!val) continue;
|
|
@@ -46858,38 +47877,108 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46858
47877
|
const xy = project(p.lon, p.lat);
|
|
46859
47878
|
if (xy) projected.push({ p, xy });
|
|
46860
47879
|
}
|
|
46861
|
-
const
|
|
47880
|
+
const placePoi = (e, cx, cy, clusterId) => {
|
|
47881
|
+
const { fill: fill2, stroke: stroke2 } = poiFill(e.p);
|
|
47882
|
+
poiScreen.set(e.p.id, { cx, cy, r: radiusFor(e.p) });
|
|
47883
|
+
const num = routeNumberById.get(e.p.id);
|
|
47884
|
+
pois.push({
|
|
47885
|
+
id: e.p.id,
|
|
47886
|
+
cx,
|
|
47887
|
+
cy,
|
|
47888
|
+
r: radiusFor(e.p),
|
|
47889
|
+
fill: fill2,
|
|
47890
|
+
stroke: stroke2,
|
|
47891
|
+
lineNumber: e.p.lineNumber,
|
|
47892
|
+
implicit: !!e.p.implicit,
|
|
47893
|
+
isOrigin: originIds.has(e.p.id),
|
|
47894
|
+
...num !== void 0 && { routeNumber: num },
|
|
47895
|
+
...Object.keys(e.p.tags).length > 0 && { tags: e.p.tags },
|
|
47896
|
+
...clusterId !== void 0 && { clusterId }
|
|
47897
|
+
});
|
|
47898
|
+
};
|
|
47899
|
+
const clusters = [];
|
|
47900
|
+
const connected = /* @__PURE__ */ new Set();
|
|
47901
|
+
for (const e of resolved.edges) {
|
|
47902
|
+
connected.add(e.fromId);
|
|
47903
|
+
connected.add(e.toId);
|
|
47904
|
+
}
|
|
47905
|
+
for (const rt of resolved.routes) {
|
|
47906
|
+
rt.stopIds.forEach((id) => connected.add(id));
|
|
47907
|
+
}
|
|
47908
|
+
const radiusOf = (e) => radiusFor(e.p);
|
|
46862
47909
|
for (const e of projected) {
|
|
46863
|
-
|
|
46864
|
-
|
|
46865
|
-
|
|
46866
|
-
|
|
46867
|
-
|
|
46868
|
-
|
|
46869
|
-
|
|
46870
|
-
|
|
46871
|
-
|
|
46872
|
-
|
|
46873
|
-
|
|
46874
|
-
|
|
46875
|
-
|
|
46876
|
-
|
|
46877
|
-
|
|
46878
|
-
|
|
46879
|
-
|
|
46880
|
-
|
|
46881
|
-
|
|
46882
|
-
|
|
46883
|
-
|
|
46884
|
-
|
|
46885
|
-
|
|
46886
|
-
|
|
46887
|
-
|
|
46888
|
-
|
|
46889
|
-
|
|
46890
|
-
|
|
46891
|
-
|
|
46892
|
-
|
|
47910
|
+
if (connected.has(e.p.id)) placePoi(e, e.xy[0], e.xy[1]);
|
|
47911
|
+
}
|
|
47912
|
+
const groups = [];
|
|
47913
|
+
for (const e of projected) {
|
|
47914
|
+
if (connected.has(e.p.id)) continue;
|
|
47915
|
+
const r = radiusOf(e);
|
|
47916
|
+
const near = groups.find(
|
|
47917
|
+
(g) => g.some(
|
|
47918
|
+
(q) => Math.hypot(q.xy[0] - e.xy[0], q.xy[1] - e.xy[1]) < (r + radiusOf(q)) * STACK_OVERLAP
|
|
47919
|
+
)
|
|
47920
|
+
);
|
|
47921
|
+
if (near) near.push(e);
|
|
47922
|
+
else groups.push([e]);
|
|
47923
|
+
}
|
|
47924
|
+
for (const g of groups) {
|
|
47925
|
+
if (g.length === 1) {
|
|
47926
|
+
placePoi(g[0], g[0].xy[0], g[0].xy[1]);
|
|
47927
|
+
continue;
|
|
47928
|
+
}
|
|
47929
|
+
const clusterId = g[0].p.id;
|
|
47930
|
+
const cx0 = g.reduce((s, e) => s + e.xy[0], 0) / g.length;
|
|
47931
|
+
const cy0 = g.reduce((s, e) => s + e.xy[1], 0) / g.length;
|
|
47932
|
+
const maxR = Math.max(...g.map(radiusOf));
|
|
47933
|
+
const sep = 2 * maxR + STACK_RING_GAP;
|
|
47934
|
+
const ringR = Math.max(
|
|
47935
|
+
COLO_R,
|
|
47936
|
+
sep / (2 * Math.sin(Math.PI / Math.max(g.length, 2)))
|
|
47937
|
+
);
|
|
47938
|
+
const positions = g.map((e, i) => {
|
|
47939
|
+
if (g.length <= STACK_RING_MAX) {
|
|
47940
|
+
const ang2 = -Math.PI / 2 + i * 2 * Math.PI / g.length;
|
|
47941
|
+
return {
|
|
47942
|
+
e,
|
|
47943
|
+
mx: cx0 + Math.cos(ang2) * ringR,
|
|
47944
|
+
my: cy0 + Math.sin(ang2) * ringR
|
|
47945
|
+
};
|
|
47946
|
+
}
|
|
47947
|
+
const ang = i * GOLDEN_ANGLE;
|
|
47948
|
+
const rr = ringR * Math.sqrt((i + 1) / g.length);
|
|
47949
|
+
return { e, mx: cx0 + Math.cos(ang) * rr, my: cy0 + Math.sin(ang) * rr };
|
|
47950
|
+
});
|
|
47951
|
+
let minX = cx0 - maxR;
|
|
47952
|
+
let maxX = cx0 + maxR;
|
|
47953
|
+
let minY = cy0 - maxR;
|
|
47954
|
+
let maxY = cy0 + maxR;
|
|
47955
|
+
for (const { mx, my, e } of positions) {
|
|
47956
|
+
const r = radiusOf(e);
|
|
47957
|
+
minX = Math.min(minX, mx - r);
|
|
47958
|
+
maxX = Math.max(maxX, mx + r);
|
|
47959
|
+
minY = Math.min(minY, my - r);
|
|
47960
|
+
maxY = Math.max(maxY, my + r);
|
|
47961
|
+
}
|
|
47962
|
+
let dx = 0;
|
|
47963
|
+
let dy = 0;
|
|
47964
|
+
if (minX + dx < 2) dx = 2 - minX;
|
|
47965
|
+
if (maxX + dx > width - 2) dx = width - 2 - maxX;
|
|
47966
|
+
if (minY + dy < 2) dy = 2 - minY;
|
|
47967
|
+
if (maxY + dy > height - 2) dy = height - 2 - maxY;
|
|
47968
|
+
const legsOut = [];
|
|
47969
|
+
for (const { e, mx, my } of positions) {
|
|
47970
|
+
const fx = mx + dx;
|
|
47971
|
+
const fy = my + dy;
|
|
47972
|
+
placePoi(e, fx, fy, clusterId);
|
|
47973
|
+
legsOut.push({ x2: fx, y2: fy, color: poiFill(e.p).fill });
|
|
47974
|
+
}
|
|
47975
|
+
clusters.push({
|
|
47976
|
+
id: clusterId,
|
|
47977
|
+
cx: cx0 + dx,
|
|
47978
|
+
cy: cy0 + dy,
|
|
47979
|
+
count: g.length,
|
|
47980
|
+
hitR: ringR + maxR + 6,
|
|
47981
|
+
legs: legsOut
|
|
46893
47982
|
});
|
|
46894
47983
|
}
|
|
46895
47984
|
const legs = [];
|
|
@@ -46939,16 +48028,26 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46939
48028
|
if (!a || !b) continue;
|
|
46940
48029
|
const mx = (a.cx + b.cx) / 2;
|
|
46941
48030
|
const my = (a.cy + b.cy) / 2;
|
|
48031
|
+
const bow = {
|
|
48032
|
+
curved: leg.style === "arc",
|
|
48033
|
+
offset: 0,
|
|
48034
|
+
labelX: mx,
|
|
48035
|
+
labelY: my - 4
|
|
48036
|
+
};
|
|
48037
|
+
const routeLabelStyle = leg.label !== void 0 ? labelOnFill(fillAt(bow.labelX, bow.labelY)) : void 0;
|
|
46942
48038
|
legs.push({
|
|
46943
|
-
d: legPath(a, b,
|
|
48039
|
+
d: legPath(a, b, bow.curved, bow.offset),
|
|
46944
48040
|
width: routeWidthFor(Number(leg.value)),
|
|
46945
48041
|
color: mix(palette.text, palette.bg, 72),
|
|
46946
48042
|
arrow: true,
|
|
46947
48043
|
lineNumber: leg.lineNumber,
|
|
46948
48044
|
...leg.label !== void 0 && {
|
|
46949
48045
|
label: leg.label,
|
|
46950
|
-
labelX:
|
|
46951
|
-
labelY:
|
|
48046
|
+
labelX: bow.labelX,
|
|
48047
|
+
labelY: bow.labelY,
|
|
48048
|
+
labelColor: routeLabelStyle.color,
|
|
48049
|
+
labelHalo: routeLabelStyle.halo,
|
|
48050
|
+
labelHaloColor: routeLabelStyle.haloColor
|
|
46952
48051
|
}
|
|
46953
48052
|
});
|
|
46954
48053
|
}
|
|
@@ -46976,20 +48075,29 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46976
48075
|
const a = poiScreen.get(e.fromId);
|
|
46977
48076
|
const b = poiScreen.get(e.toId);
|
|
46978
48077
|
if (!a || !b) return;
|
|
46979
|
-
const
|
|
46980
|
-
const offset = n > 1 ? (i - (n - 1) / 2) * FAN_STEP : 0;
|
|
48078
|
+
const fanOffset = n > 1 ? (i - (n - 1) / 2) * FAN_STEP : 0;
|
|
46981
48079
|
const mx = (a.cx + b.cx) / 2;
|
|
46982
48080
|
const my = (a.cy + b.cy) / 2;
|
|
48081
|
+
const bow = {
|
|
48082
|
+
curved: e.style === "arc" || n > 1,
|
|
48083
|
+
offset: fanOffset,
|
|
48084
|
+
labelX: mx,
|
|
48085
|
+
labelY: my - 4
|
|
48086
|
+
};
|
|
48087
|
+
const edgeLabelStyle = e.label !== void 0 ? labelOnFill(fillAt(bow.labelX, bow.labelY)) : void 0;
|
|
46983
48088
|
legs.push({
|
|
46984
|
-
d: legPath(a, b, curved, offset),
|
|
48089
|
+
d: legPath(a, b, bow.curved, bow.offset),
|
|
46985
48090
|
width: widthFor(e),
|
|
46986
48091
|
color: mix(palette.text, palette.bg, 66),
|
|
46987
48092
|
arrow: e.directed,
|
|
46988
48093
|
lineNumber: e.lineNumber,
|
|
46989
48094
|
...e.label !== void 0 && {
|
|
46990
48095
|
label: e.label,
|
|
46991
|
-
labelX:
|
|
46992
|
-
labelY:
|
|
48096
|
+
labelX: bow.labelX,
|
|
48097
|
+
labelY: bow.labelY,
|
|
48098
|
+
labelColor: edgeLabelStyle.color,
|
|
48099
|
+
labelHalo: edgeLabelStyle.halo,
|
|
48100
|
+
labelHaloColor: edgeLabelStyle.haloColor
|
|
46993
48101
|
}
|
|
46994
48102
|
});
|
|
46995
48103
|
});
|
|
@@ -47031,25 +48139,25 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47031
48139
|
}
|
|
47032
48140
|
}
|
|
47033
48141
|
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));
|
|
47034
|
-
const
|
|
48142
|
+
const showRegionLabels = resolved.directives.noRegionLabels !== true;
|
|
48143
|
+
const isCompact = width < COMPACT_WIDTH_PX;
|
|
47035
48144
|
const LABEL_PADX = 6;
|
|
47036
48145
|
const LABEL_PADY = 3;
|
|
47037
|
-
const labelW = (text) => measureLegendText(text,
|
|
47038
|
-
const labelH =
|
|
48146
|
+
const labelW = (text) => measureLegendText(text, FONT2) + 2 * LABEL_PADX;
|
|
48147
|
+
const labelH = FONT2 + 2 * LABEL_PADY;
|
|
47039
48148
|
const pushRegionLabel = (x, y, text, fill2, lineNumber) => {
|
|
47040
|
-
const color =
|
|
47041
|
-
|
|
47042
|
-
|
|
47043
|
-
|
|
48149
|
+
const { color, haloColor } = labelOnFill(fill2);
|
|
48150
|
+
const halfW = measureLegendText(text, FONT2) / 2;
|
|
48151
|
+
const overflows = [y - FONT2 * 0.55, y - FONT2 * 0.1].some(
|
|
48152
|
+
(sy) => fillAt(x - halfW, sy) !== fill2 || fillAt(x + halfW, sy) !== fill2
|
|
47044
48153
|
);
|
|
47045
|
-
const haloColor = color === palette.textOnFillLight ? palette.textOnFillDark : palette.textOnFillLight;
|
|
47046
48154
|
labels.push({
|
|
47047
48155
|
x,
|
|
47048
48156
|
y,
|
|
47049
48157
|
text,
|
|
47050
48158
|
anchor: "middle",
|
|
47051
48159
|
color,
|
|
47052
|
-
halo:
|
|
48160
|
+
halo: overflows,
|
|
47053
48161
|
haloColor,
|
|
47054
48162
|
lineNumber
|
|
47055
48163
|
});
|
|
@@ -47058,21 +48166,50 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47058
48166
|
US: [-98.5, 39.5]
|
|
47059
48167
|
// CONUS geographic centre (near Lebanon, Kansas)
|
|
47060
48168
|
};
|
|
47061
|
-
|
|
47062
|
-
|
|
47063
|
-
|
|
47064
|
-
|
|
47065
|
-
|
|
48169
|
+
const REGION_LABEL_GAP = 2;
|
|
48170
|
+
const regionLabelRect = (cx, cy, text) => {
|
|
48171
|
+
const w = measureLegendText(text, FONT2) + 2 * REGION_LABEL_GAP;
|
|
48172
|
+
return { x: cx - w / 2, y: cy - FONT2 / 2, w, h: FONT2 };
|
|
48173
|
+
};
|
|
48174
|
+
if (showRegionLabels) {
|
|
48175
|
+
const frameContainers = new Set(resolved.poiFrameContainers);
|
|
48176
|
+
const entries = regions.map((r) => {
|
|
48177
|
+
const isContainer = frameContainers.has(r.id);
|
|
48178
|
+
if (r.layer === "base" && !isContainer || r.label === void 0)
|
|
48179
|
+
return null;
|
|
48180
|
+
const isUsState = r.layer === "us-state" || r.id.startsWith("US-");
|
|
48181
|
+
const f = isUsState ? usLayer?.get(r.id) : worldLayer.get(r.id);
|
|
48182
|
+
if (!f) return null;
|
|
47066
48183
|
const [[x0, y0], [x1, y1]] = path.bounds(f);
|
|
47067
|
-
const
|
|
47068
|
-
|
|
47069
|
-
const
|
|
48184
|
+
const boxW = x1 - x0;
|
|
48185
|
+
const boxH = y1 - y0;
|
|
48186
|
+
const abbrev = isUsState ? r.id.replace(/^US-/, "") : void 0;
|
|
48187
|
+
const candidates = abbrev !== void 0 ? isCompact ? [abbrev, r.label] : [r.label, abbrev] : [r.label];
|
|
48188
|
+
const anchor = !isUsState ? WORLD_LABEL_ANCHORS[r.id] : void 0;
|
|
47070
48189
|
const c = anchor ? project(anchor[0], anchor[1]) : path.centroid(f);
|
|
47071
|
-
if (!c || !Number.isFinite(c[0]))
|
|
48190
|
+
if (!c || !Number.isFinite(c[0])) return null;
|
|
48191
|
+
return { r, c, boxW, boxH, area: boxW * boxH, candidates };
|
|
48192
|
+
}).filter((e) => e !== null).sort((a, b) => b.area - a.area || a.r.lineNumber - b.r.lineNumber);
|
|
48193
|
+
const placedRegionRects = [];
|
|
48194
|
+
const POI_LABEL_PAD = 14;
|
|
48195
|
+
const poiObstacles = pois.map((p) => ({
|
|
48196
|
+
x: p.cx - p.r - POI_LABEL_PAD,
|
|
48197
|
+
y: p.cy - p.r - POI_LABEL_PAD,
|
|
48198
|
+
w: 2 * (p.r + POI_LABEL_PAD),
|
|
48199
|
+
h: 2 * (p.r + POI_LABEL_PAD)
|
|
48200
|
+
}));
|
|
48201
|
+
for (const { r, c, boxW, boxH, candidates } of entries) {
|
|
48202
|
+
const text = candidates.find((t) => {
|
|
48203
|
+
if (labelW(t) > boxW || labelH > boxH) return false;
|
|
48204
|
+
const rect = regionLabelRect(c[0], c[1], t);
|
|
48205
|
+
return !placedRegionRects.some((p) => rectsOverlap(rect, p)) && !poiObstacles.some((o) => rectsOverlap(rect, o));
|
|
48206
|
+
});
|
|
48207
|
+
if (text === void 0) continue;
|
|
48208
|
+
placedRegionRects.push(regionLabelRect(c[0], c[1], text));
|
|
47072
48209
|
pushRegionLabel(c[0], c[1], text, r.fill, r.lineNumber);
|
|
47073
48210
|
}
|
|
47074
48211
|
for (const seed of insetLabelSeeds) {
|
|
47075
|
-
const text =
|
|
48212
|
+
const text = isCompact ? seed.iso.replace(/^US-/, "") : seed.name;
|
|
47076
48213
|
const src = regionById.get(seed.iso);
|
|
47077
48214
|
pushRegionLabel(
|
|
47078
48215
|
seed.x,
|
|
@@ -47083,22 +48220,26 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47083
48220
|
);
|
|
47084
48221
|
}
|
|
47085
48222
|
}
|
|
47086
|
-
|
|
47087
|
-
|
|
47088
|
-
const ordered = [...pois].sort(
|
|
47089
|
-
(a, b) => a.lineNumber - b.lineNumber || (a.id < b.id ? -1 : 1)
|
|
47090
|
-
);
|
|
48223
|
+
if (resolved.directives.noPoiLabels !== true) {
|
|
48224
|
+
const ordered = [...pois].filter((p) => p.clusterId === void 0).sort((a, b) => a.lineNumber - b.lineNumber || (a.id < b.id ? -1 : 1));
|
|
47091
48225
|
const poiById = new Map(resolved.pois.map((q) => [q.id, q]));
|
|
47092
48226
|
const labelText = (p) => {
|
|
47093
48227
|
const src = poiById.get(p.id);
|
|
47094
48228
|
return src?.label ?? src?.name ?? p.id;
|
|
47095
48229
|
};
|
|
47096
|
-
const poiLabH =
|
|
48230
|
+
const poiLabH = FONT2 * 1.25;
|
|
47097
48231
|
const labelInfo = (p) => {
|
|
47098
48232
|
const text = labelText(p);
|
|
47099
|
-
return { text, w: measureLegendText(text,
|
|
48233
|
+
return { text, w: measureLegendText(text, FONT2) };
|
|
47100
48234
|
};
|
|
47101
48235
|
const GAP = 3;
|
|
48236
|
+
const clusterMembersById = /* @__PURE__ */ new Map();
|
|
48237
|
+
for (const p of pois) {
|
|
48238
|
+
if (p.clusterId === void 0) continue;
|
|
48239
|
+
const arr = clusterMembersById.get(p.clusterId);
|
|
48240
|
+
if (arr) arr.push(p);
|
|
48241
|
+
else clusterMembersById.set(p.clusterId, [p]);
|
|
48242
|
+
}
|
|
47102
48243
|
const inlineRect = (p, w, side) => {
|
|
47103
48244
|
switch (side) {
|
|
47104
48245
|
case "right":
|
|
@@ -47128,11 +48269,11 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47128
48269
|
const x = side === "right" ? rect.x : side === "left" ? rect.x + w : p.cx;
|
|
47129
48270
|
labels.push({
|
|
47130
48271
|
x,
|
|
47131
|
-
y: rect.y + poiLabH / 2 +
|
|
48272
|
+
y: rect.y + poiLabH / 2 + FONT2 / 3,
|
|
47132
48273
|
text,
|
|
47133
48274
|
anchor,
|
|
47134
48275
|
color: palette.text,
|
|
47135
|
-
halo:
|
|
48276
|
+
halo: false,
|
|
47136
48277
|
haloColor: palette.bg,
|
|
47137
48278
|
poiId: p.id,
|
|
47138
48279
|
lineNumber: p.lineNumber
|
|
@@ -47143,43 +48284,60 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47143
48284
|
return rect.x >= 0 && rect.x + rect.w <= width && rect.y >= 0 && rect.y + rect.h <= height && !collides(rect);
|
|
47144
48285
|
};
|
|
47145
48286
|
const GROUP_R = 30;
|
|
47146
|
-
const
|
|
48287
|
+
const groups2 = [];
|
|
47147
48288
|
for (const p of ordered) {
|
|
47148
|
-
const near =
|
|
48289
|
+
const near = groups2.find(
|
|
47149
48290
|
(g) => g.some((q) => Math.hypot(q.cx - p.cx, q.cy - p.cy) < GROUP_R)
|
|
47150
48291
|
);
|
|
47151
48292
|
if (near) near.push(p);
|
|
47152
|
-
else
|
|
48293
|
+
else groups2.push([p]);
|
|
47153
48294
|
}
|
|
47154
48295
|
const ROW_GAP2 = 3;
|
|
47155
48296
|
const step = poiLabH + ROW_GAP2;
|
|
47156
48297
|
const COL_GAP = 16;
|
|
47157
|
-
const
|
|
47158
|
-
|
|
48298
|
+
const makeItems = (group) => group.map((p) => ({ p, ...labelInfo(p) })).sort((a, b) => a.p.cy - b.p.cy || (a.text < b.text ? -1 : 1));
|
|
48299
|
+
const columnRows = (items, side) => {
|
|
47159
48300
|
const left = Math.min(...items.map((o) => o.p.cx - o.p.r));
|
|
47160
48301
|
const right = Math.max(...items.map((o) => o.p.cx + o.p.r));
|
|
47161
|
-
const cyMid = (Math.min(...items.map((o) => o.p.cy)) + Math.max(...items.map((o) => o.p.cy))) / 2;
|
|
47162
48302
|
const maxW = Math.max(...items.map((o) => o.w));
|
|
47163
|
-
const
|
|
47164
|
-
const colX = side === "right" ? right + COL_GAP : left - COL_GAP;
|
|
48303
|
+
const cyMid = (Math.min(...items.map((o) => o.p.cy)) + Math.max(...items.map((o) => o.p.cy))) / 2;
|
|
48304
|
+
const colX = side === "right" ? Math.min(right + COL_GAP, width - 2 - maxW) : Math.max(left - COL_GAP, 2 + maxW);
|
|
47165
48305
|
const totalH = items.length * step;
|
|
47166
48306
|
let startY = cyMid - totalH / 2;
|
|
47167
48307
|
startY = Math.max(2, Math.min(startY, height - totalH - 2));
|
|
47168
|
-
items.
|
|
48308
|
+
return items.map((o, i) => {
|
|
47169
48309
|
const rowCy = startY + i * step + step / 2;
|
|
47170
|
-
|
|
47171
|
-
|
|
47172
|
-
|
|
47173
|
-
|
|
47174
|
-
|
|
47175
|
-
|
|
48310
|
+
return {
|
|
48311
|
+
o,
|
|
48312
|
+
colX,
|
|
48313
|
+
rowCy,
|
|
48314
|
+
rect: {
|
|
48315
|
+
x: side === "right" ? colX : colX - o.w,
|
|
48316
|
+
y: rowCy - poiLabH / 2,
|
|
48317
|
+
w: o.w,
|
|
48318
|
+
h: poiLabH
|
|
48319
|
+
}
|
|
48320
|
+
};
|
|
48321
|
+
});
|
|
48322
|
+
};
|
|
48323
|
+
const wouldColumnBeClean = (items, side) => columnRows(items, side).every(
|
|
48324
|
+
({ rect }) => rect.x >= 0 && rect.x + rect.w <= width && rect.y >= 0 && rect.y + rect.h <= height && !collides(rect)
|
|
48325
|
+
);
|
|
48326
|
+
const defaultColumnSide = (items) => {
|
|
48327
|
+
const right = Math.max(...items.map((o) => o.p.cx + o.p.r));
|
|
48328
|
+
const maxW = Math.max(...items.map((o) => o.w));
|
|
48329
|
+
return right + COL_GAP + maxW <= width - 2 ? "right" : "left";
|
|
48330
|
+
};
|
|
48331
|
+
const commitColumn = (items, side, clusterId) => {
|
|
48332
|
+
for (const { o, colX, rowCy, rect } of columnRows(items, side)) {
|
|
48333
|
+
obstacles.push(rect);
|
|
47176
48334
|
labels.push({
|
|
47177
48335
|
x: colX,
|
|
47178
|
-
y: rowCy +
|
|
48336
|
+
y: rowCy + FONT2 / 3,
|
|
47179
48337
|
text: o.text,
|
|
47180
48338
|
anchor: side === "right" ? "start" : "end",
|
|
47181
48339
|
color: palette.text,
|
|
47182
|
-
halo:
|
|
48340
|
+
halo: false,
|
|
47183
48341
|
haloColor: palette.bg,
|
|
47184
48342
|
leader: {
|
|
47185
48343
|
x1: o.p.cx,
|
|
@@ -47189,24 +48347,141 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47189
48347
|
},
|
|
47190
48348
|
leaderColor: o.p.fill,
|
|
47191
48349
|
poiId: o.p.id,
|
|
47192
|
-
lineNumber: o.p.lineNumber
|
|
48350
|
+
lineNumber: o.p.lineNumber,
|
|
48351
|
+
...clusterId !== void 0 && { clusterMember: clusterId }
|
|
47193
48352
|
});
|
|
48353
|
+
}
|
|
48354
|
+
};
|
|
48355
|
+
const pushHidden = (p) => {
|
|
48356
|
+
const { text, w } = labelInfo(p);
|
|
48357
|
+
let x = p.cx + p.r + GAP;
|
|
48358
|
+
let anchor = "start";
|
|
48359
|
+
if (x + w > width) {
|
|
48360
|
+
x = p.cx - p.r - GAP - w;
|
|
48361
|
+
anchor = "end";
|
|
48362
|
+
}
|
|
48363
|
+
const y = Math.max(0, Math.min(p.cy - poiLabH / 2, height - poiLabH));
|
|
48364
|
+
labels.push({
|
|
48365
|
+
x: anchor === "start" ? x : x + w,
|
|
48366
|
+
y: y + poiLabH / 2 + FONT2 / 3,
|
|
48367
|
+
text,
|
|
48368
|
+
anchor,
|
|
48369
|
+
color: palette.text,
|
|
48370
|
+
halo: false,
|
|
48371
|
+
haloColor: palette.bg,
|
|
48372
|
+
poiId: p.id,
|
|
48373
|
+
hidden: true,
|
|
48374
|
+
lineNumber: p.lineNumber
|
|
47194
48375
|
});
|
|
47195
48376
|
};
|
|
47196
|
-
for (const
|
|
48377
|
+
for (const [clusterId, members] of clusterMembersById) {
|
|
48378
|
+
if (members.length === 0) continue;
|
|
48379
|
+
const items = makeItems(members);
|
|
48380
|
+
const side = wouldColumnBeClean(items, "right") ? "right" : wouldColumnBeClean(items, "left") ? "left" : defaultColumnSide(items);
|
|
48381
|
+
commitColumn(items, side, clusterId);
|
|
48382
|
+
}
|
|
48383
|
+
const maxExtent = MAX_CLUSTER_EXTENT_FACTOR * Math.min(width, height);
|
|
48384
|
+
const clusterPending = [];
|
|
48385
|
+
for (const g of groups2) {
|
|
48386
|
+
const items = makeItems(g);
|
|
47197
48387
|
if (g.length === 1) {
|
|
47198
|
-
const p =
|
|
47199
|
-
const { text, w } = labelInfo(p);
|
|
48388
|
+
const { p, text, w } = items[0];
|
|
47200
48389
|
const side = ["right", "left", "above", "below"].find(
|
|
47201
48390
|
(s) => inlineFits(p, w, s)
|
|
47202
48391
|
);
|
|
47203
|
-
if (side)
|
|
47204
|
-
|
|
47205
|
-
|
|
48392
|
+
if (side) pushInline(p, text, w, side);
|
|
48393
|
+
else commitColumn(items, defaultColumnSide(items));
|
|
48394
|
+
continue;
|
|
48395
|
+
}
|
|
48396
|
+
const left = Math.min(...items.map((o) => o.p.cx - o.p.r));
|
|
48397
|
+
const right = Math.max(...items.map((o) => o.p.cx + o.p.r));
|
|
48398
|
+
const minCy = Math.min(...items.map((o) => o.p.cy));
|
|
48399
|
+
const maxCy = Math.max(...items.map((o) => o.p.cy));
|
|
48400
|
+
const diag = Math.hypot(right - left, maxCy - minCy);
|
|
48401
|
+
if (diag > maxExtent || items.length > MAX_COLUMN_ROWS) {
|
|
48402
|
+
items.forEach((o) => pushHidden(o.p));
|
|
48403
|
+
} else {
|
|
48404
|
+
clusterPending.push(items);
|
|
48405
|
+
}
|
|
48406
|
+
}
|
|
48407
|
+
for (const items of clusterPending) {
|
|
48408
|
+
const side = ["right", "left"].find(
|
|
48409
|
+
(s) => wouldColumnBeClean(items, s)
|
|
48410
|
+
);
|
|
48411
|
+
if (side) commitColumn(items, side);
|
|
48412
|
+
else items.forEach((o) => pushHidden(o.p));
|
|
48413
|
+
}
|
|
48414
|
+
}
|
|
48415
|
+
if (resolved.directives.noContextLabels !== true) {
|
|
48416
|
+
for (const l of labels) {
|
|
48417
|
+
if (l.hidden) continue;
|
|
48418
|
+
const w = labelW(l.text);
|
|
48419
|
+
const x = l.anchor === "start" ? l.x : l.anchor === "end" ? l.x - w : l.x - w / 2;
|
|
48420
|
+
obstacles.push({ x, y: l.y - labelH / 2, w, h: labelH });
|
|
48421
|
+
}
|
|
48422
|
+
for (const box of insets)
|
|
48423
|
+
obstacles.push({ x: box.x, y: box.y, w: box.w, h: box.h });
|
|
48424
|
+
const countryCandidates = [];
|
|
48425
|
+
for (const f of worldLayer.values()) {
|
|
48426
|
+
const iso = typeof f.id === "string" ? f.id : String(f.id ?? "");
|
|
48427
|
+
if (!iso || regionById.has(iso)) continue;
|
|
48428
|
+
let hasReferencedSub = false;
|
|
48429
|
+
for (const k of regionById.keys())
|
|
48430
|
+
if (k.startsWith(iso + "-")) {
|
|
48431
|
+
hasReferencedSub = true;
|
|
48432
|
+
break;
|
|
47206
48433
|
}
|
|
48434
|
+
if (hasReferencedSub) continue;
|
|
48435
|
+
const b = path.bounds(f);
|
|
48436
|
+
const [x0, y0] = b[0];
|
|
48437
|
+
const [x1, y1] = b[1];
|
|
48438
|
+
if (!Number.isFinite(x0) || !Number.isFinite(x1)) continue;
|
|
48439
|
+
const anchorLngLat = WORLD_LABEL_ANCHORS[iso];
|
|
48440
|
+
const a = anchorLngLat ? project(anchorLngLat[0], anchorLngLat[1]) : path.centroid(f);
|
|
48441
|
+
countryCandidates.push({
|
|
48442
|
+
name: f.properties?.name ?? iso,
|
|
48443
|
+
bbox: [x0, y0, x1, y1],
|
|
48444
|
+
anchor: a && Number.isFinite(a[0]) ? [a[0], a[1]] : null
|
|
48445
|
+
});
|
|
48446
|
+
}
|
|
48447
|
+
const framedStateContainers = (resolved.poiFrameContainers ?? []).some(
|
|
48448
|
+
(id) => id.startsWith("US-")
|
|
48449
|
+
);
|
|
48450
|
+
if (usLayer && framedStateContainers) {
|
|
48451
|
+
const containerSet = new Set(resolved.poiFrameContainers);
|
|
48452
|
+
for (const [iso, f] of usLayer) {
|
|
48453
|
+
if (containerSet.has(iso) || regionById.has(iso)) continue;
|
|
48454
|
+
const viewF = cullFeatureToView(f);
|
|
48455
|
+
if (!viewF) continue;
|
|
48456
|
+
const b = path.bounds(viewF);
|
|
48457
|
+
const [x0, y0] = b[0];
|
|
48458
|
+
const [x1, y1] = b[1];
|
|
48459
|
+
if (!Number.isFinite(x0) || !Number.isFinite(x1)) continue;
|
|
48460
|
+
const a = path.centroid(viewF);
|
|
48461
|
+
countryCandidates.push({
|
|
48462
|
+
name: f.properties?.name ?? iso,
|
|
48463
|
+
bbox: [x0, y0, x1, y1],
|
|
48464
|
+
anchor: a && Number.isFinite(a[0]) ? [a[0], a[1]] : null
|
|
48465
|
+
});
|
|
47207
48466
|
}
|
|
47208
|
-
placeColumn(g);
|
|
47209
48467
|
}
|
|
48468
|
+
const contextLabels = placeContextLabels({
|
|
48469
|
+
projection: resolved.projection,
|
|
48470
|
+
dLonSpan,
|
|
48471
|
+
dLatSpan,
|
|
48472
|
+
width,
|
|
48473
|
+
height,
|
|
48474
|
+
waterBodies: data.waterBodies,
|
|
48475
|
+
countries: countryCandidates,
|
|
48476
|
+
palette,
|
|
48477
|
+
project,
|
|
48478
|
+
collides,
|
|
48479
|
+
// Water labels must stay over open water — `fillAt` returns the ocean
|
|
48480
|
+
// backdrop colour off-land and a region fill on-land (lakes/states count
|
|
48481
|
+
// as land here, which is the safe side for an ocean name).
|
|
48482
|
+
overLand: (x, y) => fillAt(x, y) !== water
|
|
48483
|
+
});
|
|
48484
|
+
labels.push(...contextLabels);
|
|
47210
48485
|
}
|
|
47211
48486
|
let legend = null;
|
|
47212
48487
|
if (!resolved.directives.noLegend) {
|
|
@@ -47241,24 +48516,35 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47241
48516
|
...resolved.caption !== void 0 && { caption: resolved.caption },
|
|
47242
48517
|
regions,
|
|
47243
48518
|
rivers,
|
|
48519
|
+
relief,
|
|
48520
|
+
reliefHatch,
|
|
48521
|
+
coastlineStyle,
|
|
47244
48522
|
legs,
|
|
47245
48523
|
pois,
|
|
48524
|
+
clusters,
|
|
47246
48525
|
labels,
|
|
47247
48526
|
legend,
|
|
47248
48527
|
insets,
|
|
47249
|
-
insetRegions
|
|
48528
|
+
insetRegions,
|
|
48529
|
+
projection,
|
|
48530
|
+
stretch: stretchParams,
|
|
48531
|
+
diagnostics: []
|
|
47250
48532
|
};
|
|
47251
48533
|
}
|
|
47252
|
-
var import_d3_geo2, import_topojson_client2, FIT_PAD, RAMP_FLOOR, R_DEFAULT, R_MIN, R_MAX, W_MIN, W_MAX,
|
|
48534
|
+
var import_d3_geo2, import_topojson_client2, FIT_PAD, RAMP_FLOOR, R_DEFAULT, R_MIN, R_MAX, W_MIN, W_MAX, FONT2, MAX_CLUSTER_EXTENT_FACTOR, MAX_COLUMN_ROWS, REGION_LABEL_HALO_RATIO, LAND_TINT_LIGHT, LAND_TINT_DARK, TAG_TINT_LIGHT, TAG_TINT_DARK, WATER_TINT_LIGHT, WATER_TINT_DARK, RIVER_WIDTH, COMPACT_WIDTH_PX, RELIEF_MIN_AREA, RELIEF_MIN_DIM, RELIEF_HATCH_SPACING, RELIEF_HATCH_WIDTH, RELIEF_HATCH_STRENGTH, COASTLINE_RING_COUNT, COASTLINE_D0, COASTLINE_STEP, COASTLINE_THICKNESS, COASTLINE_OPACITY_NEAR, COASTLINE_OPACITY_FAR, COASTLINE_MIN_EXTENT, COASTLINE_MIN_EXTENT_GLOBAL, COASTLINE_STROKE_MIX, FOREIGN_TINT_LIGHT, FOREIGN_TINT_DARK, MUTED_FOREIGN_LIGHT, MUTED_FOREIGN_DARK, COLO_R, GOLDEN_ANGLE, STACK_OVERLAP, STACK_RING_MAX, STACK_RING_GAP, FAN_STEP, ARC_CURVE_FRAC, decodeCache, usConusProjection, alaskaProjection, hawaiiProjection, INSET_STATES, inAlaska, inHawaii, FOREIGN_BORDER, US_NON_CONUS;
|
|
47253
48535
|
var init_layout15 = __esm({
|
|
47254
48536
|
"src/map/layout.ts"() {
|
|
47255
48537
|
"use strict";
|
|
47256
48538
|
import_d3_geo2 = require("d3-geo");
|
|
47257
48539
|
import_topojson_client2 = require("topojson-client");
|
|
47258
48540
|
init_color_utils();
|
|
48541
|
+
init_geo();
|
|
48542
|
+
init_colorize();
|
|
48543
|
+
init_colors();
|
|
47259
48544
|
init_label_layout();
|
|
47260
48545
|
init_legend_constants();
|
|
47261
48546
|
init_title_constants();
|
|
48547
|
+
init_context_labels();
|
|
47262
48548
|
FIT_PAD = 24;
|
|
47263
48549
|
RAMP_FLOOR = 15;
|
|
47264
48550
|
R_DEFAULT = 6;
|
|
@@ -47266,29 +48552,66 @@ var init_layout15 = __esm({
|
|
|
47266
48552
|
R_MAX = 22;
|
|
47267
48553
|
W_MIN = 1.25;
|
|
47268
48554
|
W_MAX = 8;
|
|
47269
|
-
|
|
47270
|
-
|
|
47271
|
-
|
|
47272
|
-
|
|
48555
|
+
FONT2 = 11;
|
|
48556
|
+
MAX_CLUSTER_EXTENT_FACTOR = 0.18;
|
|
48557
|
+
MAX_COLUMN_ROWS = 7;
|
|
48558
|
+
REGION_LABEL_HALO_RATIO = 4.5;
|
|
48559
|
+
LAND_TINT_LIGHT = 12;
|
|
48560
|
+
LAND_TINT_DARK = 24;
|
|
47273
48561
|
TAG_TINT_LIGHT = 60;
|
|
47274
48562
|
TAG_TINT_DARK = 68;
|
|
47275
|
-
|
|
48563
|
+
WATER_TINT_LIGHT = 24;
|
|
48564
|
+
WATER_TINT_DARK = 24;
|
|
47276
48565
|
RIVER_WIDTH = 1.3;
|
|
48566
|
+
COMPACT_WIDTH_PX = 480;
|
|
48567
|
+
RELIEF_MIN_AREA = 12;
|
|
48568
|
+
RELIEF_MIN_DIM = 2;
|
|
48569
|
+
RELIEF_HATCH_SPACING = 2;
|
|
48570
|
+
RELIEF_HATCH_WIDTH = 0.15;
|
|
48571
|
+
RELIEF_HATCH_STRENGTH = 32;
|
|
48572
|
+
COASTLINE_RING_COUNT = 5;
|
|
48573
|
+
COASTLINE_D0 = 16e-4;
|
|
48574
|
+
COASTLINE_STEP = 28e-4;
|
|
48575
|
+
COASTLINE_THICKNESS = 14e-4;
|
|
48576
|
+
COASTLINE_OPACITY_NEAR = 0.5;
|
|
48577
|
+
COASTLINE_OPACITY_FAR = 0.1;
|
|
48578
|
+
COASTLINE_MIN_EXTENT = 6e-4;
|
|
48579
|
+
COASTLINE_MIN_EXTENT_GLOBAL = 6e-4;
|
|
48580
|
+
COASTLINE_STROKE_MIX = 32;
|
|
47277
48581
|
FOREIGN_TINT_LIGHT = 30;
|
|
47278
48582
|
FOREIGN_TINT_DARK = 62;
|
|
47279
|
-
MUTED_WATER_LIGHT = 14;
|
|
47280
|
-
MUTED_WATER_DARK = 10;
|
|
47281
48583
|
MUTED_FOREIGN_LIGHT = 28;
|
|
47282
48584
|
MUTED_FOREIGN_DARK = 16;
|
|
47283
|
-
MUTED_LAND_DARK = 24;
|
|
47284
48585
|
COLO_R = 9;
|
|
47285
48586
|
GOLDEN_ANGLE = 2.399963229728653;
|
|
48587
|
+
STACK_OVERLAP = 1;
|
|
48588
|
+
STACK_RING_MAX = 8;
|
|
48589
|
+
STACK_RING_GAP = 4;
|
|
47286
48590
|
FAN_STEP = 16;
|
|
47287
48591
|
ARC_CURVE_FRAC = 0.18;
|
|
48592
|
+
decodeCache = /* @__PURE__ */ new WeakMap();
|
|
47288
48593
|
usConusProjection = () => (0, import_d3_geo2.geoConicEqualArea)().parallels([29.5, 45.5]).rotate([96, 0]);
|
|
47289
48594
|
alaskaProjection = () => (0, import_d3_geo2.geoConicEqualArea)().rotate([154, 0]).center([-2, 58.5]).parallels([55, 65]);
|
|
47290
48595
|
hawaiiProjection = () => (0, import_d3_geo2.geoMercator)();
|
|
47291
48596
|
INSET_STATES = /* @__PURE__ */ new Set(["US-AK", "US-HI"]);
|
|
48597
|
+
inAlaska = (lon, lat) => lat >= 51 && (lon <= -129 || lon >= 172);
|
|
48598
|
+
inHawaii = (lon, lat) => lat >= 18 && lat <= 23 && lon >= -161 && lon <= -154;
|
|
48599
|
+
FOREIGN_BORDER = {
|
|
48600
|
+
CA: [
|
|
48601
|
+
"US-AK",
|
|
48602
|
+
"US-WA",
|
|
48603
|
+
"US-ID",
|
|
48604
|
+
"US-MT",
|
|
48605
|
+
"US-ND",
|
|
48606
|
+
"US-MN",
|
|
48607
|
+
"US-MI",
|
|
48608
|
+
"US-NY",
|
|
48609
|
+
"US-VT",
|
|
48610
|
+
"US-NH",
|
|
48611
|
+
"US-ME"
|
|
48612
|
+
],
|
|
48613
|
+
MX: ["US-CA", "US-AZ", "US-NM", "US-TX"]
|
|
48614
|
+
};
|
|
47292
48615
|
US_NON_CONUS = /* @__PURE__ */ new Set([
|
|
47293
48616
|
"US-AK",
|
|
47294
48617
|
"US-HI",
|
|
@@ -47307,6 +48630,58 @@ __export(renderer_exports16, {
|
|
|
47307
48630
|
renderMap: () => renderMap,
|
|
47308
48631
|
renderMapForExport: () => renderMapForExport
|
|
47309
48632
|
});
|
|
48633
|
+
function pointInRing2(px, py, ring) {
|
|
48634
|
+
let inside = false;
|
|
48635
|
+
for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
|
|
48636
|
+
const [xi, yi] = ring[i];
|
|
48637
|
+
const [xj, yj] = ring[j];
|
|
48638
|
+
if (yi > py !== yj > py && px < (xj - xi) * (py - yi) / (yj - yi) + xi)
|
|
48639
|
+
inside = !inside;
|
|
48640
|
+
}
|
|
48641
|
+
return inside;
|
|
48642
|
+
}
|
|
48643
|
+
function ringToPath(ring) {
|
|
48644
|
+
let d = "";
|
|
48645
|
+
for (let i = 0; i < ring.length; i++)
|
|
48646
|
+
d += (i ? "L" : "M") + ring[i][0] + "," + ring[i][1];
|
|
48647
|
+
return d + "Z";
|
|
48648
|
+
}
|
|
48649
|
+
function coastlineOuterRings(regions, minExtent) {
|
|
48650
|
+
const paths = [];
|
|
48651
|
+
for (const r of regions) {
|
|
48652
|
+
const rings = parsePathRings(r.d);
|
|
48653
|
+
for (let i = 0; i < rings.length; i++) {
|
|
48654
|
+
const ring = rings[i];
|
|
48655
|
+
if (ring.length < 3) continue;
|
|
48656
|
+
let minX = Infinity;
|
|
48657
|
+
let minY = Infinity;
|
|
48658
|
+
let maxX = -Infinity;
|
|
48659
|
+
let maxY = -Infinity;
|
|
48660
|
+
for (const [x, y] of ring) {
|
|
48661
|
+
if (x < minX) minX = x;
|
|
48662
|
+
if (x > maxX) maxX = x;
|
|
48663
|
+
if (y < minY) minY = y;
|
|
48664
|
+
if (y > maxY) maxY = y;
|
|
48665
|
+
}
|
|
48666
|
+
if (Math.max(maxX - minX, maxY - minY) < minExtent) continue;
|
|
48667
|
+
const [fx, fy] = ring[0];
|
|
48668
|
+
let depth = 0;
|
|
48669
|
+
for (let j = 0; j < rings.length; j++)
|
|
48670
|
+
if (j !== i && pointInRing2(fx, fy, rings[j])) depth++;
|
|
48671
|
+
if (depth % 2 === 1) continue;
|
|
48672
|
+
paths.push(ringToPath(ring));
|
|
48673
|
+
}
|
|
48674
|
+
}
|
|
48675
|
+
return paths;
|
|
48676
|
+
}
|
|
48677
|
+
function appendWaterLines(g, outerRings, style, flatWater) {
|
|
48678
|
+
const d = outerRings.join(" ");
|
|
48679
|
+
const linesOuterFirst = [...style.lines].sort((a, b) => b.d - a.d);
|
|
48680
|
+
for (const line12 of linesOuterFirst) {
|
|
48681
|
+
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");
|
|
48682
|
+
g.append("path").attr("d", d).attr("stroke", flatWater).attr("stroke-width", 2 * line12.d).attr("stroke-linejoin", "round").attr("stroke-linecap", "round");
|
|
48683
|
+
}
|
|
48684
|
+
}
|
|
47310
48685
|
function renderMap(container, resolved, data, palette, isDark, onClickItem, exportDims, activeGroupOverride) {
|
|
47311
48686
|
d3Selection18.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
47312
48687
|
const width = exportDims?.width ?? container.clientWidth;
|
|
@@ -47319,6 +48694,11 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47319
48694
|
{
|
|
47320
48695
|
palette,
|
|
47321
48696
|
isDark,
|
|
48697
|
+
// Export-only: forward the contain-fit request from mapExportDimensions so a
|
|
48698
|
+
// clamped/floored (off-aspect) export canvas letterboxes instead of
|
|
48699
|
+
// stretch-distorting. The in-app preview pane passes no exportDims → unset →
|
|
48700
|
+
// keeps the global stretch-fill.
|
|
48701
|
+
preferContain: exportDims?.preferContain ?? false,
|
|
47322
48702
|
...activeGroupOverride !== void 0 && {
|
|
47323
48703
|
activeGroup: activeGroupOverride
|
|
47324
48704
|
}
|
|
@@ -47332,6 +48712,7 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47332
48712
|
const gRegions = svg.append("g").attr("class", "dgmo-map-regions");
|
|
47333
48713
|
const drawRegion = (g, r, strokeWidth) => {
|
|
47334
48714
|
const p = g.append("path").attr("d", r.d).attr("fill", r.fill).attr("stroke", r.stroke).attr("stroke-width", strokeWidth);
|
|
48715
|
+
if (r.label) p.attr("data-region-name", r.label);
|
|
47335
48716
|
if (r.layer !== "base") {
|
|
47336
48717
|
p.classed("dgmo-map-region", true).attr("data-region", r.id);
|
|
47337
48718
|
if (r.value !== void 0) p.attr("data-value", r.value);
|
|
@@ -47352,6 +48733,52 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47352
48733
|
}
|
|
47353
48734
|
};
|
|
47354
48735
|
for (const r of layout.regions) drawRegion(gRegions, r, 0.5);
|
|
48736
|
+
if (layout.relief.length && layout.reliefHatch) {
|
|
48737
|
+
const h = layout.reliefHatch;
|
|
48738
|
+
const rangeClipId = "dgmo-relief-clip";
|
|
48739
|
+
const landClipId = "dgmo-relief-land";
|
|
48740
|
+
const rangeClip = defs.append("clipPath").attr("id", rangeClipId);
|
|
48741
|
+
for (const s of layout.relief) rangeClip.append("path").attr("d", s.d);
|
|
48742
|
+
const landClip = defs.append("clipPath").attr("id", landClipId);
|
|
48743
|
+
for (const r of layout.regions)
|
|
48744
|
+
if (r.id !== "lake") landClip.append("path").attr("d", r.d);
|
|
48745
|
+
const gRelief = svg.append("g").attr("clip-path", `url(#${landClipId})`).append("g").attr("class", "dgmo-map-relief").attr("clip-path", `url(#${rangeClipId})`).attr("stroke", h.color).attr("stroke-width", h.width).attr("vector-effect", "non-scaling-stroke");
|
|
48746
|
+
for (let y = h.spacing; y < height; y += h.spacing) {
|
|
48747
|
+
gRelief.append("line").attr("x1", 0).attr("y1", y).attr("x2", width).attr("y2", y);
|
|
48748
|
+
}
|
|
48749
|
+
}
|
|
48750
|
+
if (layout.coastlineStyle) {
|
|
48751
|
+
const cs = layout.coastlineStyle;
|
|
48752
|
+
const maskId = "dgmo-map-water-mask";
|
|
48753
|
+
const mask = defs.append("mask").attr("id", maskId).attr("maskUnits", "userSpaceOnUse").attr("x", 0).attr("y", 0).attr("width", width).attr("height", height);
|
|
48754
|
+
mask.append("rect").attr("x", 0).attr("y", 0).attr("width", width).attr("height", height).attr("fill", "white");
|
|
48755
|
+
const landD = layout.regions.filter((r) => r.id !== "lake").map((r) => r.d).join(" ");
|
|
48756
|
+
const lakeD = layout.regions.filter((r) => r.id === "lake").map((r) => r.d).join(" ");
|
|
48757
|
+
if (landD) mask.append("path").attr("d", landD).attr("fill", "black");
|
|
48758
|
+
if (lakeD) mask.append("path").attr("d", lakeD).attr("fill", "white");
|
|
48759
|
+
if (layout.insets.length) {
|
|
48760
|
+
const reach = Math.max(0, ...cs.lines.map((l) => l.d + l.thickness));
|
|
48761
|
+
for (const box of layout.insets) {
|
|
48762
|
+
const d = box.points.map((p, i) => `${i ? "L" : "M"}${p[0]},${p[1]}`).join("") + "Z";
|
|
48763
|
+
mask.append("path").attr("d", d).attr("fill", "black").attr("stroke", "black").attr("stroke-width", 2 * reach).attr("stroke-linejoin", "round");
|
|
48764
|
+
}
|
|
48765
|
+
}
|
|
48766
|
+
const gWater = svg.append("g").attr("class", "dgmo-map-water-lines").attr("fill", "none").attr("mask", `url(#${maskId})`);
|
|
48767
|
+
appendWaterLines(
|
|
48768
|
+
gWater,
|
|
48769
|
+
coastlineOuterRings(layout.regions, cs.minExtent),
|
|
48770
|
+
cs,
|
|
48771
|
+
layout.background
|
|
48772
|
+
);
|
|
48773
|
+
const byStroke = /* @__PURE__ */ new Map();
|
|
48774
|
+
for (const r of layout.regions) {
|
|
48775
|
+
const arr = byStroke.get(r.stroke);
|
|
48776
|
+
if (arr) arr.push(r.d);
|
|
48777
|
+
else byStroke.set(r.stroke, [r.d]);
|
|
48778
|
+
}
|
|
48779
|
+
for (const [stroke2, ds] of byStroke)
|
|
48780
|
+
gWater.append("path").attr("d", ds.join(" ")).attr("stroke", stroke2).attr("stroke-width", 0.5).attr("stroke-linejoin", "round");
|
|
48781
|
+
}
|
|
47355
48782
|
if (layout.rivers.length) {
|
|
47356
48783
|
const gRivers = svg.append("g").attr("class", "dgmo-map-rivers").attr("fill", "none");
|
|
47357
48784
|
for (const r of layout.rivers) {
|
|
@@ -47360,15 +48787,61 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47360
48787
|
}
|
|
47361
48788
|
if (layout.insets.length) {
|
|
47362
48789
|
const insetG = svg.append("g").attr("class", "dgmo-map-insets");
|
|
47363
|
-
|
|
48790
|
+
layout.insets.forEach((box, bi) => {
|
|
47364
48791
|
const d = box.points.map((p, i) => `${i ? "L" : "M"}${p[0]},${p[1]}`).join("") + "Z";
|
|
47365
48792
|
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");
|
|
47366
|
-
|
|
48793
|
+
if (box.contextLand) {
|
|
48794
|
+
const clipId = `dgmo-map-inset-clip-${bi}`;
|
|
48795
|
+
defs.append("clipPath").attr("id", clipId).append("path").attr("d", d);
|
|
48796
|
+
insetG.append("path").attr("d", box.contextLand.d).attr("fill", box.contextLand.fill).attr("clip-path", `url(#${clipId})`);
|
|
48797
|
+
}
|
|
48798
|
+
});
|
|
47367
48799
|
for (const r of layout.insetRegions) drawRegion(insetG, r, 0.5);
|
|
47368
|
-
|
|
48800
|
+
if (layout.coastlineStyle) {
|
|
48801
|
+
const cs = layout.coastlineStyle;
|
|
48802
|
+
const maskId = "dgmo-map-inset-water-mask";
|
|
48803
|
+
const mask = defs.append("mask").attr("id", maskId).attr("maskUnits", "userSpaceOnUse").attr("x", 0).attr("y", 0).attr("width", width).attr("height", height);
|
|
48804
|
+
for (const box of layout.insets) {
|
|
48805
|
+
const d = box.points.map((p, i) => `${i ? "L" : "M"}${p[0]},${p[1]}`).join("") + "Z";
|
|
48806
|
+
mask.append("path").attr("d", d).attr("fill", "white");
|
|
48807
|
+
}
|
|
48808
|
+
layout.insets.forEach((box, bi) => {
|
|
48809
|
+
if (box.contextLand)
|
|
48810
|
+
mask.append("path").attr("d", box.contextLand.d).attr("fill", "black").attr("clip-path", `url(#dgmo-map-inset-clip-${bi})`);
|
|
48811
|
+
});
|
|
48812
|
+
for (const r of layout.insetRegions)
|
|
48813
|
+
if (r.id !== "lake")
|
|
48814
|
+
mask.append("path").attr("d", r.d).attr("fill", "black");
|
|
48815
|
+
for (const r of layout.insetRegions)
|
|
48816
|
+
if (r.id === "lake")
|
|
48817
|
+
mask.append("path").attr("d", r.d).attr("fill", "white");
|
|
48818
|
+
const clipId = "dgmo-map-inset-water-clip";
|
|
48819
|
+
const clip = defs.append("clipPath").attr("id", clipId);
|
|
48820
|
+
for (const box of layout.insets) {
|
|
48821
|
+
const d = box.points.map((p, i) => `${i ? "L" : "M"}${p[0]},${p[1]}`).join("") + "Z";
|
|
48822
|
+
clip.append("path").attr("d", d);
|
|
48823
|
+
}
|
|
48824
|
+
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})`);
|
|
48825
|
+
appendWaterLines(
|
|
48826
|
+
gInsetWater,
|
|
48827
|
+
coastlineOuterRings(layout.insetRegions, cs.minExtent),
|
|
48828
|
+
cs,
|
|
48829
|
+
layout.background
|
|
48830
|
+
);
|
|
48831
|
+
for (const r of layout.insetRegions)
|
|
48832
|
+
gInsetWater.append("path").attr("d", r.d).attr("stroke", r.stroke).attr("stroke-width", 0.5).attr("stroke-linejoin", "round");
|
|
48833
|
+
}
|
|
48834
|
+
}
|
|
48835
|
+
const wireSync = (sel, lineNumber) => {
|
|
48836
|
+
if (lineNumber < 1) return;
|
|
48837
|
+
sel.attr("data-line-number", lineNumber);
|
|
48838
|
+
if (onClickItem)
|
|
48839
|
+
sel.style("cursor", "pointer").on("click", () => onClickItem(lineNumber));
|
|
48840
|
+
};
|
|
47369
48841
|
const gLegs = svg.append("g").attr("class", "dgmo-map-legs").attr("fill", "none");
|
|
47370
48842
|
layout.legs.forEach((leg, i) => {
|
|
47371
48843
|
const p = gLegs.append("path").attr("d", leg.d).attr("stroke", leg.color).attr("stroke-width", leg.width).attr("stroke-linecap", "round");
|
|
48844
|
+
wireSync(p, leg.lineNumber);
|
|
47372
48845
|
if (leg.arrow) {
|
|
47373
48846
|
const id = `dgmo-map-arrow-${i}`;
|
|
47374
48847
|
const s = arrowSize(leg.width);
|
|
@@ -47376,25 +48849,38 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47376
48849
|
p.attr("marker-end", `url(#${id})`);
|
|
47377
48850
|
}
|
|
47378
48851
|
if (leg.label !== void 0 && leg.labelX !== void 0) {
|
|
47379
|
-
emitText(
|
|
48852
|
+
const lt = emitText(
|
|
47380
48853
|
gLegs,
|
|
47381
48854
|
leg.labelX,
|
|
47382
48855
|
leg.labelY ?? 0,
|
|
47383
48856
|
leg.label,
|
|
47384
48857
|
"middle",
|
|
47385
|
-
palette.textMuted,
|
|
47386
|
-
haloColor,
|
|
47387
|
-
true,
|
|
48858
|
+
leg.labelColor ?? palette.textMuted,
|
|
48859
|
+
leg.labelHaloColor ?? haloColor,
|
|
48860
|
+
leg.labelHalo ?? true,
|
|
47388
48861
|
LABEL_FONT - 1
|
|
47389
48862
|
);
|
|
48863
|
+
wireSync(lt, leg.lineNumber);
|
|
47390
48864
|
}
|
|
47391
48865
|
});
|
|
48866
|
+
const gSpider = svg.append("g").attr("class", "dgmo-map-spider");
|
|
48867
|
+
for (const cl of layout.clusters) {
|
|
48868
|
+
if (!exportDims) {
|
|
48869
|
+
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");
|
|
48870
|
+
}
|
|
48871
|
+
for (const leg of cl.legs) {
|
|
48872
|
+
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");
|
|
48873
|
+
}
|
|
48874
|
+
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");
|
|
48875
|
+
}
|
|
47392
48876
|
const gPois = svg.append("g").attr("class", "dgmo-map-pois");
|
|
47393
48877
|
for (const poi of layout.pois) {
|
|
47394
48878
|
if (poi.isOrigin) {
|
|
47395
48879
|
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);
|
|
47396
48880
|
}
|
|
47397
48881
|
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);
|
|
48882
|
+
if (poi.clusterId !== void 0)
|
|
48883
|
+
c.attr("data-cluster-member", poi.clusterId);
|
|
47398
48884
|
if (poi.tags) {
|
|
47399
48885
|
for (const [group, value] of Object.entries(poi.tags)) {
|
|
47400
48886
|
c.attr(`data-tag-${group.toLowerCase()}`, value.toLowerCase());
|
|
@@ -47422,12 +48908,32 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47422
48908
|
}
|
|
47423
48909
|
const gLabels = svg.append("g").attr("class", "dgmo-map-labels");
|
|
47424
48910
|
for (const lab of layout.labels) {
|
|
48911
|
+
if (lab.hidden) {
|
|
48912
|
+
if (exportDims) continue;
|
|
48913
|
+
emitText(
|
|
48914
|
+
gLabels,
|
|
48915
|
+
lab.x,
|
|
48916
|
+
lab.y,
|
|
48917
|
+
lab.text,
|
|
48918
|
+
lab.anchor,
|
|
48919
|
+
lab.color,
|
|
48920
|
+
lab.haloColor,
|
|
48921
|
+
lab.halo,
|
|
48922
|
+
LABEL_FONT,
|
|
48923
|
+
lab.italic,
|
|
48924
|
+
lab.letterSpacing
|
|
48925
|
+
).attr("data-poi", lab.poiId ?? null).attr("data-poi-hidden", "").style("opacity", 0).style("pointer-events", "none");
|
|
48926
|
+
continue;
|
|
48927
|
+
}
|
|
47425
48928
|
if (lab.leader) {
|
|
47426
48929
|
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(
|
|
47427
48930
|
"stroke",
|
|
47428
48931
|
lab.leaderColor ?? mix(palette.textMuted, palette.bg, 60)
|
|
47429
48932
|
).attr("stroke-width", lab.leaderColor ? 1 : 0.75);
|
|
47430
48933
|
if (lab.poiId !== void 0) line12.attr("data-poi", lab.poiId);
|
|
48934
|
+
if (lab.clusterMember !== void 0)
|
|
48935
|
+
line12.attr("data-cluster-member", lab.clusterMember);
|
|
48936
|
+
wireSync(line12, lab.lineNumber);
|
|
47431
48937
|
}
|
|
47432
48938
|
const t = emitText(
|
|
47433
48939
|
gLabels,
|
|
@@ -47438,11 +48944,38 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47438
48944
|
lab.color,
|
|
47439
48945
|
lab.haloColor,
|
|
47440
48946
|
lab.halo,
|
|
47441
|
-
LABEL_FONT
|
|
48947
|
+
LABEL_FONT,
|
|
48948
|
+
lab.italic,
|
|
48949
|
+
lab.letterSpacing,
|
|
48950
|
+
lab.lines
|
|
47442
48951
|
);
|
|
47443
48952
|
if (lab.poiId !== void 0) {
|
|
47444
48953
|
t.attr("data-poi", lab.poiId).style("cursor", "default");
|
|
47445
48954
|
}
|
|
48955
|
+
if (lab.clusterMember !== void 0) {
|
|
48956
|
+
t.attr("data-cluster-member", lab.clusterMember);
|
|
48957
|
+
}
|
|
48958
|
+
wireSync(t, lab.lineNumber);
|
|
48959
|
+
}
|
|
48960
|
+
if (!exportDims && layout.clusters.length) {
|
|
48961
|
+
const gBadge = svg.append("g").attr("class", "dgmo-map-cluster-badges");
|
|
48962
|
+
for (const cl of layout.clusters) {
|
|
48963
|
+
const g = gBadge.append("g").attr("data-cluster", cl.id).style("opacity", 0).style("pointer-events", "none");
|
|
48964
|
+
const R = 9;
|
|
48965
|
+
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);
|
|
48966
|
+
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);
|
|
48967
|
+
emitText(
|
|
48968
|
+
g,
|
|
48969
|
+
cl.cx,
|
|
48970
|
+
cl.cy + 3,
|
|
48971
|
+
String(cl.count),
|
|
48972
|
+
"middle",
|
|
48973
|
+
palette.text,
|
|
48974
|
+
palette.bg,
|
|
48975
|
+
false,
|
|
48976
|
+
LABEL_FONT
|
|
48977
|
+
);
|
|
48978
|
+
}
|
|
47446
48979
|
}
|
|
47447
48980
|
if (layout.legend) {
|
|
47448
48981
|
const legendY = (layout.title ? TITLE_Y + TITLE_FONT_SIZE : 0) + (layout.subtitle ? TITLE_FONT_SIZE : 0) + 8;
|
|
@@ -47476,10 +49009,10 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47476
49009
|
}
|
|
47477
49010
|
}
|
|
47478
49011
|
if (layout.title) {
|
|
47479
|
-
svg.append("text").attr("x", width / 2).attr("y", TITLE_Y).attr("text-anchor", "middle").attr("font-size", TITLE_FONT_SIZE).attr("font-weight", TITLE_FONT_WEIGHT).attr("fill", palette.text).attr("paint-order", "stroke fill").attr("stroke", palette.bg).attr("stroke-width", 4).attr("stroke-linejoin", "round").attr("stroke-opacity", 0.7).text(layout.title);
|
|
49012
|
+
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);
|
|
47480
49013
|
}
|
|
47481
49014
|
if (layout.subtitle) {
|
|
47482
|
-
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);
|
|
49015
|
+
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);
|
|
47483
49016
|
}
|
|
47484
49017
|
if (layout.caption) {
|
|
47485
49018
|
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);
|
|
@@ -47488,10 +49021,21 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47488
49021
|
function renderMapForExport(container, resolved, data, palette, isDark, exportDims) {
|
|
47489
49022
|
renderMap(container, resolved, data, palette, isDark, void 0, exportDims);
|
|
47490
49023
|
}
|
|
47491
|
-
function emitText(g, x, y, text, anchor, color, halo, withHalo, fontSize) {
|
|
47492
|
-
const t = g.append("text").attr("x", x).attr("y", y).attr("text-anchor", anchor).attr("font-size", fontSize).attr("fill", color)
|
|
49024
|
+
function emitText(g, x, y, text, anchor, color, halo, withHalo, fontSize, italic, letterSpacing, lines) {
|
|
49025
|
+
const t = g.append("text").attr("x", x).attr("y", y).attr("text-anchor", anchor).attr("font-size", fontSize).attr("fill", color);
|
|
49026
|
+
if (lines && lines.length > 1) {
|
|
49027
|
+
const lineHeight = fontSize + 2;
|
|
49028
|
+
const startDy = -((lines.length - 1) / 2) * lineHeight;
|
|
49029
|
+
lines.forEach((ln, i) => {
|
|
49030
|
+
t.append("tspan").attr("x", x).attr("dy", i === 0 ? startDy : lineHeight).text(ln);
|
|
49031
|
+
});
|
|
49032
|
+
} else {
|
|
49033
|
+
t.text(text);
|
|
49034
|
+
}
|
|
49035
|
+
if (italic) t.attr("font-style", "italic");
|
|
49036
|
+
if (letterSpacing) t.attr("letter-spacing", letterSpacing);
|
|
47493
49037
|
if (withHalo) {
|
|
47494
|
-
t.attr("paint-order", "stroke fill").attr("stroke", halo).attr("stroke-width",
|
|
49038
|
+
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);
|
|
47495
49039
|
}
|
|
47496
49040
|
return t;
|
|
47497
49041
|
}
|
|
@@ -47509,6 +49053,179 @@ var init_renderer16 = __esm({
|
|
|
47509
49053
|
}
|
|
47510
49054
|
});
|
|
47511
49055
|
|
|
49056
|
+
// src/map/dimensions.ts
|
|
49057
|
+
var dimensions_exports = {};
|
|
49058
|
+
__export(dimensions_exports, {
|
|
49059
|
+
mapContentAspect: () => mapContentAspect,
|
|
49060
|
+
mapExportDimensions: () => mapExportDimensions
|
|
49061
|
+
});
|
|
49062
|
+
function mapContentAspect(resolved, data, ref = REF) {
|
|
49063
|
+
const { projection, fitTarget } = buildMapProjection(resolved, data);
|
|
49064
|
+
projection.fitSize([ref, ref], fitTarget);
|
|
49065
|
+
const b = (0, import_d3_geo3.geoPath)(projection).bounds(fitTarget);
|
|
49066
|
+
const w = b[1][0] - b[0][0];
|
|
49067
|
+
const h = b[1][1] - b[0][1];
|
|
49068
|
+
const aspect = w / h;
|
|
49069
|
+
return Number.isFinite(aspect) && aspect > 0 ? aspect : FALLBACK_ASPECT;
|
|
49070
|
+
}
|
|
49071
|
+
function mapExportDimensions(resolved, data, baseWidth = 1200) {
|
|
49072
|
+
const raw = mapContentAspect(resolved, data);
|
|
49073
|
+
const clamped = Math.max(ASPECT_MIN, Math.min(ASPECT_MAX, raw));
|
|
49074
|
+
const width = baseWidth;
|
|
49075
|
+
let height = Math.round(width / clamped);
|
|
49076
|
+
let chromeReserve = 0;
|
|
49077
|
+
if (resolved.title && resolved.pois.length > 0) {
|
|
49078
|
+
const bannerBottom = (resolved.subtitle ? TITLE_Y + TITLE_FONT_SIZE : TITLE_Y) + TITLE_FONT_SIZE / 2;
|
|
49079
|
+
chromeReserve += Math.max(FIT_PAD2, bannerBottom + TITLE_GAP) - FIT_PAD2;
|
|
49080
|
+
}
|
|
49081
|
+
let floored = false;
|
|
49082
|
+
if (height - chromeReserve < MIN_MAP_BAND) {
|
|
49083
|
+
height = Math.round(chromeReserve + MIN_MAP_BAND);
|
|
49084
|
+
floored = true;
|
|
49085
|
+
}
|
|
49086
|
+
const preferContain = clamped !== raw || floored;
|
|
49087
|
+
return { width, height, preferContain };
|
|
49088
|
+
}
|
|
49089
|
+
var import_d3_geo3, FIT_PAD2, TITLE_GAP, ASPECT_MAX, ASPECT_MIN, MIN_MAP_BAND, FALLBACK_ASPECT, REF;
|
|
49090
|
+
var init_dimensions = __esm({
|
|
49091
|
+
"src/map/dimensions.ts"() {
|
|
49092
|
+
"use strict";
|
|
49093
|
+
import_d3_geo3 = require("d3-geo");
|
|
49094
|
+
init_title_constants();
|
|
49095
|
+
init_layout15();
|
|
49096
|
+
FIT_PAD2 = 24;
|
|
49097
|
+
TITLE_GAP = 16;
|
|
49098
|
+
ASPECT_MAX = 3;
|
|
49099
|
+
ASPECT_MIN = 0.9;
|
|
49100
|
+
MIN_MAP_BAND = 200;
|
|
49101
|
+
FALLBACK_ASPECT = 1.5;
|
|
49102
|
+
REF = 1e3;
|
|
49103
|
+
}
|
|
49104
|
+
});
|
|
49105
|
+
|
|
49106
|
+
// src/map/load-data.ts
|
|
49107
|
+
var load_data_exports = {};
|
|
49108
|
+
__export(load_data_exports, {
|
|
49109
|
+
loadMapData: () => loadMapData
|
|
49110
|
+
});
|
|
49111
|
+
async function loadNodeBuiltins() {
|
|
49112
|
+
const [{ readFile }, { fileURLToPath }, { dirname, resolve }] = await Promise.all([
|
|
49113
|
+
import("fs/promises"),
|
|
49114
|
+
import("url"),
|
|
49115
|
+
import("path")
|
|
49116
|
+
]);
|
|
49117
|
+
return { readFile, fileURLToPath, dirname, resolve };
|
|
49118
|
+
}
|
|
49119
|
+
async function readJson(nb, dir, name) {
|
|
49120
|
+
return JSON.parse(await nb.readFile(nb.resolve(dir, name), "utf8"));
|
|
49121
|
+
}
|
|
49122
|
+
async function firstExistingDir(nb, baseDir) {
|
|
49123
|
+
for (const rel of CANDIDATE_DIRS) {
|
|
49124
|
+
const dir = nb.resolve(baseDir, rel);
|
|
49125
|
+
try {
|
|
49126
|
+
await nb.readFile(nb.resolve(dir, FILES.gazetteer), "utf8");
|
|
49127
|
+
return dir;
|
|
49128
|
+
} catch {
|
|
49129
|
+
}
|
|
49130
|
+
}
|
|
49131
|
+
throw new Error(
|
|
49132
|
+
`map data assets not found near ${baseDir} (looked in ${CANDIDATE_DIRS.join(", ")}). Run \`pnpm build:map-data\` and \`pnpm build\`.`
|
|
49133
|
+
);
|
|
49134
|
+
}
|
|
49135
|
+
function validate(data) {
|
|
49136
|
+
const topoOk = (t) => !!t && t.type === "Topology" && !!t.objects;
|
|
49137
|
+
if (!topoOk(data.worldCoarse) || !topoOk(data.worldDetail) || !topoOk(data.usStates) || !data.gazetteer || !Array.isArray(data.gazetteer.cities) || !data.gazetteer.byName) {
|
|
49138
|
+
throw new Error("map data assets are malformed (failed shape validation)");
|
|
49139
|
+
}
|
|
49140
|
+
return data;
|
|
49141
|
+
}
|
|
49142
|
+
function moduleBaseDir(nb) {
|
|
49143
|
+
try {
|
|
49144
|
+
const url = import_meta.url;
|
|
49145
|
+
if (url) return nb.dirname(nb.fileURLToPath(url));
|
|
49146
|
+
} catch {
|
|
49147
|
+
}
|
|
49148
|
+
if (typeof __dirname !== "undefined") return __dirname;
|
|
49149
|
+
return process.cwd();
|
|
49150
|
+
}
|
|
49151
|
+
function loadMapData() {
|
|
49152
|
+
cache ??= (async () => {
|
|
49153
|
+
const nb = await loadNodeBuiltins();
|
|
49154
|
+
const dir = await firstExistingDir(nb, moduleBaseDir(nb));
|
|
49155
|
+
const [
|
|
49156
|
+
worldCoarse,
|
|
49157
|
+
worldDetail,
|
|
49158
|
+
usStates,
|
|
49159
|
+
lakes,
|
|
49160
|
+
rivers,
|
|
49161
|
+
mountainRanges,
|
|
49162
|
+
naLand,
|
|
49163
|
+
naLakes,
|
|
49164
|
+
waterBodies,
|
|
49165
|
+
gazetteer
|
|
49166
|
+
] = await Promise.all([
|
|
49167
|
+
// worldCoarse (110m) is LOAD-BEARING but NOT a render source: the world
|
|
49168
|
+
// basemap renders from worldDetail (50m) at all scales (resolver pins
|
|
49169
|
+
// basemaps.world = 'detail'). Coarse stays as the authoritative region
|
|
49170
|
+
// name index + dominant-landmass bbox source in resolver.ts. Do not drop it.
|
|
49171
|
+
readJson(nb, dir, FILES.worldCoarse),
|
|
49172
|
+
readJson(nb, dir, FILES.worldDetail),
|
|
49173
|
+
readJson(nb, dir, FILES.usStates),
|
|
49174
|
+
// Lakes/rivers/mountain/NA/water assets are optional — older bundles may predate them.
|
|
49175
|
+
readJson(nb, dir, FILES.lakes).catch(() => void 0),
|
|
49176
|
+
readJson(nb, dir, FILES.rivers).catch(() => void 0),
|
|
49177
|
+
readJson(nb, dir, FILES.mountainRanges).catch(
|
|
49178
|
+
() => void 0
|
|
49179
|
+
),
|
|
49180
|
+
readJson(nb, dir, FILES.naLand).catch(() => void 0),
|
|
49181
|
+
readJson(nb, dir, FILES.naLakes).catch(() => void 0),
|
|
49182
|
+
readJson(nb, dir, FILES.waterBodies).catch(() => void 0),
|
|
49183
|
+
readJson(nb, dir, FILES.gazetteer)
|
|
49184
|
+
]);
|
|
49185
|
+
return validate({
|
|
49186
|
+
worldCoarse,
|
|
49187
|
+
worldDetail,
|
|
49188
|
+
usStates,
|
|
49189
|
+
gazetteer,
|
|
49190
|
+
...lakes && { lakes },
|
|
49191
|
+
...rivers && { rivers },
|
|
49192
|
+
...mountainRanges && { mountainRanges },
|
|
49193
|
+
...naLand && { naLand },
|
|
49194
|
+
...naLakes && { naLakes },
|
|
49195
|
+
...waterBodies && { waterBodies }
|
|
49196
|
+
});
|
|
49197
|
+
})().catch((e) => {
|
|
49198
|
+
cache = void 0;
|
|
49199
|
+
throw e;
|
|
49200
|
+
});
|
|
49201
|
+
return cache;
|
|
49202
|
+
}
|
|
49203
|
+
var import_meta, FILES, CANDIDATE_DIRS, cache;
|
|
49204
|
+
var init_load_data = __esm({
|
|
49205
|
+
"src/map/load-data.ts"() {
|
|
49206
|
+
"use strict";
|
|
49207
|
+
import_meta = {};
|
|
49208
|
+
FILES = {
|
|
49209
|
+
worldCoarse: "world-coarse.json",
|
|
49210
|
+
worldDetail: "world-detail.json",
|
|
49211
|
+
usStates: "us-states.json",
|
|
49212
|
+
lakes: "lakes.json",
|
|
49213
|
+
rivers: "rivers.json",
|
|
49214
|
+
mountainRanges: "mountain-ranges.json",
|
|
49215
|
+
naLand: "na-land.json",
|
|
49216
|
+
naLakes: "na-lakes.json",
|
|
49217
|
+
waterBodies: "water-bodies.json",
|
|
49218
|
+
gazetteer: "gazetteer.json"
|
|
49219
|
+
};
|
|
49220
|
+
CANDIDATE_DIRS = [
|
|
49221
|
+
"./data",
|
|
49222
|
+
"./map-data",
|
|
49223
|
+
"../map-data",
|
|
49224
|
+
"../src/map/data"
|
|
49225
|
+
];
|
|
49226
|
+
}
|
|
49227
|
+
});
|
|
49228
|
+
|
|
47512
49229
|
// src/pyramid/renderer.ts
|
|
47513
49230
|
var renderer_exports17 = {};
|
|
47514
49231
|
__export(renderer_exports17, {
|
|
@@ -49510,8 +51227,8 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
|
|
|
49510
51227
|
const lines = splitParticipantLabel(p.label, LABEL_MAX_CHARS);
|
|
49511
51228
|
if (lines.length === 0) continue;
|
|
49512
51229
|
const widest = Math.max(...lines.map((l) => l.length));
|
|
49513
|
-
const
|
|
49514
|
-
uniformBoxWidth = Math.max(uniformBoxWidth,
|
|
51230
|
+
const labelWidth2 = widest * LABEL_CHAR_WIDTH + 10;
|
|
51231
|
+
uniformBoxWidth = Math.max(uniformBoxWidth, labelWidth2);
|
|
49515
51232
|
}
|
|
49516
51233
|
uniformBoxWidth = Math.min(MAX_BOX_WIDTH, uniformBoxWidth);
|
|
49517
51234
|
const effectiveGap = Math.max(PARTICIPANT_GAP, uniformBoxWidth + 30);
|
|
@@ -52206,15 +53923,15 @@ function renderArcDiagram(container, parsed, palette, _isDark, onClickItem, expo
|
|
|
52206
53923
|
textColor,
|
|
52207
53924
|
onClickItem
|
|
52208
53925
|
);
|
|
52209
|
-
const
|
|
52210
|
-
for (const node of nodes)
|
|
53926
|
+
const neighbors2 = /* @__PURE__ */ new Map();
|
|
53927
|
+
for (const node of nodes) neighbors2.set(node, /* @__PURE__ */ new Set());
|
|
52211
53928
|
for (const link of links) {
|
|
52212
|
-
|
|
52213
|
-
|
|
53929
|
+
neighbors2.get(link.source).add(link.target);
|
|
53930
|
+
neighbors2.get(link.target).add(link.source);
|
|
52214
53931
|
}
|
|
52215
53932
|
const FADE_OPACITY3 = 0.1;
|
|
52216
53933
|
function handleMouseEnter(hovered) {
|
|
52217
|
-
const connected =
|
|
53934
|
+
const connected = neighbors2.get(hovered);
|
|
52218
53935
|
g.selectAll(".arc-link").each(function() {
|
|
52219
53936
|
const el = d3Selection23.select(this);
|
|
52220
53937
|
const src = el.attr("data-source");
|
|
@@ -54149,7 +55866,7 @@ function renderVenn(container, parsed, palette, _isDark, onClickItem, exportDims
|
|
|
54149
55866
|
8,
|
|
54150
55867
|
Math.floor(OVERLAP_WRAP_TARGET_W / OVERLAP_CH_W)
|
|
54151
55868
|
);
|
|
54152
|
-
function
|
|
55869
|
+
function wrapLabel3(text, maxChars) {
|
|
54153
55870
|
const words = text.split(/\s+/).filter(Boolean);
|
|
54154
55871
|
const lines = [];
|
|
54155
55872
|
let cur = "";
|
|
@@ -54195,7 +55912,7 @@ function renderVenn(container, parsed, palette, _isDark, onClickItem, exportDims
|
|
|
54195
55912
|
if (!ov.label) continue;
|
|
54196
55913
|
const idxs = ov.sets.map((s) => vennSets.findIndex((vs) => vs.name === s));
|
|
54197
55914
|
if (idxs.some((idx) => idx < 0)) continue;
|
|
54198
|
-
const lines =
|
|
55915
|
+
const lines = wrapLabel3(ov.label, MAX_WRAP_CHARS);
|
|
54199
55916
|
wrappedOverlapLabels.set(ov, lines);
|
|
54200
55917
|
const dir = predictOverlapDirRaw(idxs);
|
|
54201
55918
|
const longest = lines.reduce((m, l) => Math.max(m, l.length), 0);
|
|
@@ -55632,25 +57349,29 @@ async function renderForExport(content, theme, palette, viewState, options) {
|
|
|
55632
57349
|
if (detectedType === "map") {
|
|
55633
57350
|
const { parseMap: parseMap2 } = await Promise.resolve().then(() => (init_parser12(), parser_exports11));
|
|
55634
57351
|
const { resolveMap: resolveMap2 } = await Promise.resolve().then(() => (init_resolver2(), resolver_exports));
|
|
55635
|
-
const { loadMapData: loadMapData2 } = await Promise.resolve().then(() => (init_load_data(), load_data_exports));
|
|
55636
57352
|
const { renderMapForExport: renderMapForExport2 } = await Promise.resolve().then(() => (init_renderer16(), renderer_exports16));
|
|
57353
|
+
const { mapExportDimensions: mapExportDimensions2 } = await Promise.resolve().then(() => (init_dimensions(), dimensions_exports));
|
|
55637
57354
|
const effectivePalette2 = await resolveExportPalette(theme, palette);
|
|
55638
57355
|
const mapParsed = parseMap2(content);
|
|
55639
|
-
let mapData;
|
|
55640
|
-
|
|
55641
|
-
|
|
55642
|
-
|
|
55643
|
-
|
|
57356
|
+
let mapData = options?.mapData;
|
|
57357
|
+
if (!mapData) {
|
|
57358
|
+
const { loadMapData: loadMapData2 } = await Promise.resolve().then(() => (init_load_data(), load_data_exports));
|
|
57359
|
+
try {
|
|
57360
|
+
mapData = await loadMapData2();
|
|
57361
|
+
} catch {
|
|
57362
|
+
return "";
|
|
57363
|
+
}
|
|
55644
57364
|
}
|
|
55645
57365
|
const mapResolved = resolveMap2(mapParsed, mapData);
|
|
55646
|
-
const
|
|
57366
|
+
const dims2 = mapExportDimensions2(mapResolved, mapData, EXPORT_WIDTH);
|
|
57367
|
+
const container2 = createExportContainer(dims2.width, dims2.height);
|
|
55647
57368
|
renderMapForExport2(
|
|
55648
57369
|
container2,
|
|
55649
57370
|
mapResolved,
|
|
55650
57371
|
mapData,
|
|
55651
57372
|
effectivePalette2,
|
|
55652
57373
|
theme === "dark",
|
|
55653
|
-
|
|
57374
|
+
dims2
|
|
55654
57375
|
);
|
|
55655
57376
|
return finalizeSvgExport(container2, theme, effectivePalette2);
|
|
55656
57377
|
}
|
|
@@ -56514,7 +58235,8 @@ async function render(content, options) {
|
|
|
56514
58235
|
...options?.c4Container !== void 0 && {
|
|
56515
58236
|
c4Container: options.c4Container
|
|
56516
58237
|
},
|
|
56517
|
-
...options?.tagGroup !== void 0 && { tagGroup: options.tagGroup }
|
|
58238
|
+
...options?.tagGroup !== void 0 && { tagGroup: options.tagGroup },
|
|
58239
|
+
...options?.mapData !== void 0 && { mapData: options.mapData }
|
|
56518
58240
|
});
|
|
56519
58241
|
if (chartType === "map") {
|
|
56520
58242
|
try {
|
|
@@ -56525,7 +58247,7 @@ async function render(content, options) {
|
|
|
56525
58247
|
Promise.resolve().then(() => (init_load_data(), load_data_exports))
|
|
56526
58248
|
]
|
|
56527
58249
|
);
|
|
56528
|
-
const data = await loadMapData2();
|
|
58250
|
+
const data = options?.mapData ?? await loadMapData2();
|
|
56529
58251
|
diagnostics = [...resolveMap2(parseMap2(content), data).diagnostics];
|
|
56530
58252
|
} catch {
|
|
56531
58253
|
}
|