@diagrammo/dgmo 0.21.1 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -6
- package/dist/advanced.cjs +2003 -466
- package/dist/advanced.d.cts +5714 -0
- package/dist/advanced.d.ts +5714 -0
- package/dist/advanced.js +1999 -466
- package/dist/auto.cjs +2048 -449
- package/dist/auto.d.cts +39 -0
- package/dist/auto.d.ts +39 -0
- package/dist/auto.js +121 -121
- package/dist/auto.mjs +2050 -450
- package/dist/cli.cjs +170 -170
- package/dist/editor.cjs +13 -16
- package/dist/editor.js +13 -16
- package/dist/highlight.cjs +15 -13
- package/dist/highlight.js +15 -13
- package/dist/index.cjs +2032 -435
- package/dist/index.d.cts +339 -0
- package/dist/index.d.ts +339 -0
- package/dist/index.js +2034 -436
- package/dist/internal.cjs +2003 -466
- package/dist/internal.d.cts +5714 -0
- package/dist/internal.d.ts +5714 -0
- package/dist/internal.js +1999 -466
- package/dist/map-data/water-bodies.json +1 -0
- package/docs/language-reference.md +20 -9
- package/gallery/fixtures/map-categorical-world.dgmo +16 -0
- package/gallery/fixtures/map-categorical.dgmo +0 -1
- package/gallery/fixtures/map-choropleth.dgmo +0 -1
- package/gallery/fixtures/map-coastline.dgmo +7 -0
- package/gallery/fixtures/map-colorize.dgmo +11 -0
- package/gallery/fixtures/map-direct-color.dgmo +0 -1
- package/gallery/fixtures/map-reference-world.dgmo +11 -0
- package/gallery/fixtures/map-region-scope.dgmo +0 -3
- package/gallery/fixtures/map-route.dgmo +0 -1
- package/package.json +1 -1
- package/src/advanced.ts +12 -1
- package/src/boxes-and-lines/renderer.ts +39 -12
- package/src/cli.ts +1 -1
- package/src/completion.ts +32 -25
- package/src/cycle/renderer.ts +14 -1
- package/src/d3.ts +8 -2
- package/src/editor/highlight-api.ts +4 -0
- package/src/editor/keywords.ts +13 -16
- package/src/infra/renderer.ts +35 -7
- package/src/map/colorize.ts +54 -0
- package/src/map/context-labels.ts +429 -0
- package/src/map/data/types.ts +34 -0
- package/src/map/data/water-bodies.json +1 -0
- package/src/map/dimensions.ts +117 -0
- package/src/map/geo-query.ts +21 -3
- package/src/map/geo.ts +47 -1
- package/src/map/layout.ts +1300 -251
- package/src/map/load-data.ts +10 -2
- package/src/map/parser.ts +42 -116
- package/src/map/renderer.ts +512 -13
- package/src/map/resolved-types.ts +16 -2
- package/src/map/resolver.ts +208 -59
- package/src/map/types.ts +30 -32
- package/src/mindmap/renderer.ts +10 -1
- package/src/palettes/atlas.ts +77 -0
- package/src/palettes/blueprint.ts +73 -0
- package/src/palettes/color-utils.ts +58 -1
- package/src/palettes/index.ts +12 -3
- package/src/palettes/slate.ts +73 -0
- package/src/palettes/tidewater.ts +73 -0
- package/src/render.ts +8 -1
- package/src/tech-radar/renderer.ts +3 -0
- package/src/tech-radar/types.ts +3 -0
- package/src/utils/d3-types.ts +5 -0
- package/src/utils/legend-layout.ts +21 -4
- package/src/utils/legend-types.ts +7 -0
- package/src/utils/reserved-key-registry.ts +3 -0
- package/src/palettes/bold.ts +0 -67
package/dist/index.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,24 +16364,6 @@ 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
16367
|
case "region-metric": {
|
|
15954
16368
|
dup(d.regionMetric);
|
|
15955
16369
|
const { label: rmLabel, colorName: rmColor } = peelTrailingColorName(value);
|
|
@@ -15965,91 +16379,43 @@ function parseMap(content) {
|
|
|
15965
16379
|
dup(d.flowMetric);
|
|
15966
16380
|
d.flowMetric = value;
|
|
15967
16381
|
break;
|
|
15968
|
-
case "
|
|
15969
|
-
dup(d.
|
|
15970
|
-
|
|
15971
|
-
const s = parseScale(value, line12);
|
|
15972
|
-
if (s) d.scale = s;
|
|
15973
|
-
}
|
|
15974
|
-
break;
|
|
15975
|
-
case "region-labels":
|
|
15976
|
-
dup(d.regionLabels);
|
|
15977
|
-
if (value && !["full", "abbrev", "off"].includes(value))
|
|
15978
|
-
pushWarning(
|
|
15979
|
-
line12,
|
|
15980
|
-
`Unknown region-labels "${value}" (expected full | abbrev | off).`
|
|
15981
|
-
);
|
|
15982
|
-
d.regionLabels = value;
|
|
15983
|
-
break;
|
|
15984
|
-
case "poi-labels":
|
|
15985
|
-
dup(d.poiLabels);
|
|
15986
|
-
if (value && !["off", "auto", "all"].includes(value))
|
|
15987
|
-
pushWarning(
|
|
15988
|
-
line12,
|
|
15989
|
-
`Unknown poi-labels "${value}" (expected off | auto | all).`
|
|
15990
|
-
);
|
|
15991
|
-
d.poiLabels = value;
|
|
15992
|
-
break;
|
|
15993
|
-
case "default-country":
|
|
15994
|
-
dup(d.defaultCountry);
|
|
15995
|
-
d.defaultCountry = value;
|
|
15996
|
-
break;
|
|
15997
|
-
case "default-state":
|
|
15998
|
-
dup(d.defaultState);
|
|
15999
|
-
d.defaultState = value;
|
|
16382
|
+
case "locale":
|
|
16383
|
+
dup(d.locale);
|
|
16384
|
+
d.locale = value;
|
|
16000
16385
|
break;
|
|
16001
16386
|
case "active-tag":
|
|
16002
16387
|
dup(d.activeTag);
|
|
16003
16388
|
d.activeTag = value;
|
|
16004
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. ──
|
|
16005
16396
|
case "no-legend":
|
|
16006
16397
|
d.noLegend = true;
|
|
16007
16398
|
break;
|
|
16008
|
-
case "no-
|
|
16009
|
-
d.
|
|
16399
|
+
case "no-coastline":
|
|
16400
|
+
d.noCoastline = true;
|
|
16010
16401
|
break;
|
|
16011
|
-
case "relief":
|
|
16012
|
-
d.
|
|
16402
|
+
case "no-relief":
|
|
16403
|
+
d.noRelief = true;
|
|
16013
16404
|
break;
|
|
16014
|
-
case "
|
|
16015
|
-
|
|
16016
|
-
if (d.basemapStyle !== void 0 && d.basemapStyle !== key)
|
|
16017
|
-
pushWarning(
|
|
16018
|
-
line12,
|
|
16019
|
-
`Conflicting basemap dress \u2014 "${d.basemapStyle}" then "${key}"; last wins.`
|
|
16020
|
-
);
|
|
16021
|
-
d.basemapStyle = key;
|
|
16405
|
+
case "no-context-labels":
|
|
16406
|
+
d.noContextLabels = true;
|
|
16022
16407
|
break;
|
|
16023
|
-
case "
|
|
16024
|
-
|
|
16025
|
-
d.subtitle = value;
|
|
16408
|
+
case "no-region-labels":
|
|
16409
|
+
d.noRegionLabels = true;
|
|
16026
16410
|
break;
|
|
16027
|
-
case "
|
|
16028
|
-
|
|
16029
|
-
|
|
16411
|
+
case "no-poi-labels":
|
|
16412
|
+
d.noPoiLabels = true;
|
|
16413
|
+
break;
|
|
16414
|
+
case "no-colorize":
|
|
16415
|
+
d.noColorize = true;
|
|
16030
16416
|
break;
|
|
16031
16417
|
}
|
|
16032
16418
|
}
|
|
16033
|
-
function parseScale(value, line12) {
|
|
16034
|
-
const toks = value.split(/\s+/).filter(Boolean);
|
|
16035
|
-
const min = Number(toks[0]);
|
|
16036
|
-
const max = Number(toks[1]);
|
|
16037
|
-
if (!Number.isFinite(min) || !Number.isFinite(max)) {
|
|
16038
|
-
pushError(line12, `scale requires numeric <min> <max> (got "${value}").`);
|
|
16039
|
-
return null;
|
|
16040
|
-
}
|
|
16041
|
-
const scale = { min, max };
|
|
16042
|
-
if (toks[2] === "center") {
|
|
16043
|
-
const c = Number(toks[3]);
|
|
16044
|
-
if (Number.isFinite(c)) scale.center = c;
|
|
16045
|
-
else
|
|
16046
|
-
pushError(
|
|
16047
|
-
line12,
|
|
16048
|
-
`scale center requires a number (got "${toks[3] ?? ""}").`
|
|
16049
|
-
);
|
|
16050
|
-
}
|
|
16051
|
-
return scale;
|
|
16052
|
-
}
|
|
16053
16419
|
function handleTag(trimmed, line12) {
|
|
16054
16420
|
const m = matchTagBlockHeading(trimmed);
|
|
16055
16421
|
if (!m) {
|
|
@@ -16249,13 +16615,15 @@ function parseMap(content) {
|
|
|
16249
16615
|
pushError(line12, `Edge has an empty endpoint: "${trimmed}".`);
|
|
16250
16616
|
continue;
|
|
16251
16617
|
}
|
|
16252
|
-
const
|
|
16618
|
+
const isLast = k === links.length - 1;
|
|
16619
|
+
const meta = isLast ? lastSplit.meta : {};
|
|
16620
|
+
const style = links[k].style === "arc" ? "arc" : "straight";
|
|
16253
16621
|
edges.push({
|
|
16254
16622
|
from,
|
|
16255
16623
|
to,
|
|
16256
16624
|
...links[k].label !== void 0 && { label: links[k].label },
|
|
16257
16625
|
directed: links[k].directed,
|
|
16258
|
-
style
|
|
16626
|
+
style,
|
|
16259
16627
|
meta,
|
|
16260
16628
|
lineNumber: line12
|
|
16261
16629
|
});
|
|
@@ -16341,22 +16709,19 @@ var init_parser12 = __esm({
|
|
|
16341
16709
|
LEG_ARROW_RE = /^(-[^>]*?->|->|~[^>]*?~>|~>|--)\s+(.+)$/;
|
|
16342
16710
|
AT_RE = /(^|[\s,])at\s*:/i;
|
|
16343
16711
|
DIRECTIVE_SET = /* @__PURE__ */ new Set([
|
|
16344
|
-
"region",
|
|
16345
|
-
"projection",
|
|
16346
16712
|
"region-metric",
|
|
16347
16713
|
"poi-metric",
|
|
16348
16714
|
"flow-metric",
|
|
16349
|
-
"
|
|
16350
|
-
"region-labels",
|
|
16351
|
-
"poi-labels",
|
|
16352
|
-
"default-country",
|
|
16353
|
-
"default-state",
|
|
16715
|
+
"locale",
|
|
16354
16716
|
"active-tag",
|
|
16717
|
+
"caption",
|
|
16355
16718
|
"no-legend",
|
|
16356
|
-
"no-
|
|
16357
|
-
"relief",
|
|
16358
|
-
"
|
|
16359
|
-
"
|
|
16719
|
+
"no-coastline",
|
|
16720
|
+
"no-relief",
|
|
16721
|
+
"no-context-labels",
|
|
16722
|
+
"no-region-labels",
|
|
16723
|
+
"no-poi-labels",
|
|
16724
|
+
"no-colorize"
|
|
16360
16725
|
]);
|
|
16361
16726
|
}
|
|
16362
16727
|
});
|
|
@@ -24277,8 +24642,8 @@ function renderKanban(container, parsed, palette, isDark, options) {
|
|
|
24277
24642
|
let metaY = separatorY + sCardSeparatorGap + sCardMetaFontSize;
|
|
24278
24643
|
for (const meta of tagMeta) {
|
|
24279
24644
|
cg.append("text").attr("x", cx + sCardPaddingX).attr("y", metaY).attr("font-size", sCardMetaFontSize).attr("fill", onCardText).text(`${meta.label}: `);
|
|
24280
|
-
const
|
|
24281
|
-
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);
|
|
24282
24647
|
metaY += sCardMetaLineHeight;
|
|
24283
24648
|
}
|
|
24284
24649
|
for (const detail of card.details) {
|
|
@@ -24622,8 +24987,8 @@ function renderSwimlaneCard(parent, cardLayout, tagGroups, activeTagGroup, palet
|
|
|
24622
24987
|
let metaY = separatorY + sCardSeparatorGap + sCardMetaFontSize;
|
|
24623
24988
|
for (const meta of tagMeta) {
|
|
24624
24989
|
cg.append("text").attr("x", cx + sCardPaddingX).attr("y", metaY).attr("font-size", sCardMetaFontSize).attr("fill", palette.textMuted).text(`${meta.label}: `);
|
|
24625
|
-
const
|
|
24626
|
-
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);
|
|
24627
24992
|
metaY += sCardMetaLineHeight;
|
|
24628
24993
|
}
|
|
24629
24994
|
for (const detail of card.details) {
|
|
@@ -25458,8 +25823,8 @@ function classifyEREntities(tables, relationships) {
|
|
|
25458
25823
|
}
|
|
25459
25824
|
}
|
|
25460
25825
|
const mmParticipants = /* @__PURE__ */ new Set();
|
|
25461
|
-
for (const [id,
|
|
25462
|
-
if (
|
|
25826
|
+
for (const [id, neighbors2] of tableStarNeighbors) {
|
|
25827
|
+
if (neighbors2.size >= 2) mmParticipants.add(id);
|
|
25463
25828
|
}
|
|
25464
25829
|
const indegreeValues = Object.values(indegreeMap);
|
|
25465
25830
|
const mean = indegreeValues.reduce((a, b) => a + b, 0) / indegreeValues.length;
|
|
@@ -26130,7 +26495,8 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26130
26495
|
controlsExpanded,
|
|
26131
26496
|
onToggleDescriptions,
|
|
26132
26497
|
onToggleControlsExpand,
|
|
26133
|
-
exportMode = false
|
|
26498
|
+
exportMode = false,
|
|
26499
|
+
controlsHost
|
|
26134
26500
|
} = options ?? {};
|
|
26135
26501
|
d3Selection6.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
26136
26502
|
const width = exportDims?.width ?? container.clientWidth;
|
|
@@ -26148,7 +26514,11 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26148
26514
|
const sGroupLabelZone = sctx.structural(GROUP_LABEL_ZONE);
|
|
26149
26515
|
const sTitleFontSize = sctx.text(TITLE_FONT_SIZE);
|
|
26150
26516
|
const sTitleY = sctx.structural(TITLE_Y);
|
|
26151
|
-
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(
|
|
26152
26522
|
getMaxLegendReservedHeight(
|
|
26153
26523
|
{
|
|
26154
26524
|
groups: parsed.tagGroups,
|
|
@@ -26157,7 +26527,7 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26157
26527
|
},
|
|
26158
26528
|
width
|
|
26159
26529
|
)
|
|
26160
|
-
);
|
|
26530
|
+
) : 0;
|
|
26161
26531
|
const activeGroup = resolveActiveTagGroup(
|
|
26162
26532
|
parsed.tagGroups,
|
|
26163
26533
|
parsed.options["active-tag"],
|
|
@@ -26472,10 +26842,10 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26472
26842
|
const hasDescriptions = parsed.nodes.some(
|
|
26473
26843
|
(n) => n.description && n.description.length > 0
|
|
26474
26844
|
);
|
|
26475
|
-
const hasLegend = parsed.tagGroups.length > 0 || hasDescriptions;
|
|
26845
|
+
const hasLegend = parsed.tagGroups.length > 0 || hasDescriptions && controlsHost !== "app";
|
|
26476
26846
|
if (hasLegend) {
|
|
26477
26847
|
let controlsGroup;
|
|
26478
|
-
if (hasDescriptions && onToggleDescriptions) {
|
|
26848
|
+
if (hasDescriptions && (onToggleDescriptions || controlsHost === "app")) {
|
|
26479
26849
|
controlsGroup = {
|
|
26480
26850
|
toggles: [
|
|
26481
26851
|
{
|
|
@@ -26493,7 +26863,14 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26493
26863
|
groups: parsed.tagGroups,
|
|
26494
26864
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
26495
26865
|
mode: exportMode ? "export" : "preview",
|
|
26496
|
-
|
|
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 }
|
|
26497
26874
|
};
|
|
26498
26875
|
const legendState = {
|
|
26499
26876
|
activeGroup,
|
|
@@ -27741,8 +28118,9 @@ function renderMindmap(container, parsed, layout, palette, isDark, onClickItem,
|
|
|
27741
28118
|
const containerHeight = exportDims?.height ?? (container.getBoundingClientRect().height || 600);
|
|
27742
28119
|
d3Selection7.select(container).selectAll("*").remove();
|
|
27743
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";
|
|
27744
28122
|
const hasControls = !!options?.onToggleColorByDepth || !!options?.onToggleDescriptions;
|
|
27745
|
-
const hasLegend = parsed.tagGroups.length > 0 || hasControls;
|
|
28123
|
+
const hasLegend = parsed.tagGroups.length > 0 || hasControls && !appHosted;
|
|
27746
28124
|
const fixedLegend = !isExport && hasLegend;
|
|
27747
28125
|
const legendReserve = fixedLegend ? getMaxLegendReservedHeight(
|
|
27748
28126
|
{
|
|
@@ -27836,7 +28214,10 @@ function renderMindmap(container, parsed, layout, palette, isDark, onClickItem,
|
|
|
27836
28214
|
}),
|
|
27837
28215
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
27838
28216
|
mode: options?.exportMode ? "export" : "preview",
|
|
27839
|
-
...controlsToggles !== void 0 && { controlsGroup: controlsToggles }
|
|
28217
|
+
...controlsToggles !== void 0 && { controlsGroup: controlsToggles },
|
|
28218
|
+
...options?.controlsHost !== void 0 && {
|
|
28219
|
+
controlsHost: options.controlsHost
|
|
28220
|
+
}
|
|
27840
28221
|
};
|
|
27841
28222
|
const legendState = {
|
|
27842
28223
|
activeGroup: options?.colorByDepth ? null : activeTagGroup !== void 0 ? activeTagGroup : parsed.options["active-tag"] ?? null,
|
|
@@ -28280,8 +28661,8 @@ function computeFieldAlignX(children) {
|
|
|
28280
28661
|
for (const child of children) {
|
|
28281
28662
|
if (child.metadata["_labelField"] === "true" && child.children.length >= 2) {
|
|
28282
28663
|
const labelEl = child.children[0];
|
|
28283
|
-
const
|
|
28284
|
-
maxLabelWidth = Math.max(maxLabelWidth,
|
|
28664
|
+
const labelWidth2 = labelEl.label.length * CHAR_WIDTH5;
|
|
28665
|
+
maxLabelWidth = Math.max(maxLabelWidth, labelWidth2);
|
|
28285
28666
|
labelFieldCount++;
|
|
28286
28667
|
}
|
|
28287
28668
|
}
|
|
@@ -33245,7 +33626,7 @@ function hasRoles(node) {
|
|
|
33245
33626
|
function computeNodeWidth2(node, expanded, options) {
|
|
33246
33627
|
const badgeVal = node.computedConcurrentInvocations === 0 && node.computedInstances > 1 ? node.computedInstances : 0;
|
|
33247
33628
|
const badgeLen = badgeVal > 0 ? `${badgeVal}x`.length + 2 : 0;
|
|
33248
|
-
const
|
|
33629
|
+
const labelWidth2 = (node.label.length + badgeLen) * CHAR_WIDTH7 + PADDING_X3;
|
|
33249
33630
|
const allKeys = [];
|
|
33250
33631
|
if (node.computedRps > 0) allKeys.push("RPS");
|
|
33251
33632
|
if (expanded) {
|
|
@@ -33289,7 +33670,7 @@ function computeNodeWidth2(node, expanded, options) {
|
|
|
33289
33670
|
allKeys.push("overflow");
|
|
33290
33671
|
}
|
|
33291
33672
|
}
|
|
33292
|
-
if (allKeys.length === 0) return Math.max(MIN_NODE_WIDTH2,
|
|
33673
|
+
if (allKeys.length === 0) return Math.max(MIN_NODE_WIDTH2, labelWidth2);
|
|
33293
33674
|
const maxKeyLen = Math.max(...allKeys.map((k) => k.length));
|
|
33294
33675
|
let maxRowWidth = 0;
|
|
33295
33676
|
if (node.computedRps > 0) {
|
|
@@ -33377,7 +33758,7 @@ function computeNodeWidth2(node, expanded, options) {
|
|
|
33377
33758
|
truncated.length * META_CHAR_WIDTH3 + PADDING_X3
|
|
33378
33759
|
);
|
|
33379
33760
|
}
|
|
33380
|
-
return Math.max(MIN_NODE_WIDTH2,
|
|
33761
|
+
return Math.max(MIN_NODE_WIDTH2, labelWidth2, maxRowWidth + 20, descWidth);
|
|
33381
33762
|
}
|
|
33382
33763
|
function computeNodeHeight2(node, expanded, options) {
|
|
33383
33764
|
const propCount = countDisplayProps(node, expanded, options);
|
|
@@ -34926,8 +35307,9 @@ function computeInfraLegendGroups(nodes, tagGroups, palette, edges) {
|
|
|
34926
35307
|
}
|
|
34927
35308
|
return groups;
|
|
34928
35309
|
}
|
|
34929
|
-
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) {
|
|
34930
35311
|
if (legendGroups.length === 0 && !playback) return;
|
|
35312
|
+
const appHostedPlayback = controlsHost === "app" && !!playback;
|
|
34931
35313
|
const legendG = rootSvg.append("g").attr("transform", `translate(0, ${legendY})`);
|
|
34932
35314
|
if (activeGroup) {
|
|
34933
35315
|
legendG.attr("data-legend-active", activeGroup.toLowerCase());
|
|
@@ -34936,14 +35318,29 @@ function renderLegend3(rootSvg, legendGroups, totalWidth, legendY, palette, isDa
|
|
|
34936
35318
|
name: g.name,
|
|
34937
35319
|
entries: g.entries.map((e) => ({ value: e.value, color: e.color }))
|
|
34938
35320
|
}));
|
|
34939
|
-
if (playback) {
|
|
35321
|
+
if (playback && !appHostedPlayback) {
|
|
34940
35322
|
allGroups.push({ name: "Playback", entries: [] });
|
|
34941
35323
|
}
|
|
34942
35324
|
const legendConfig = {
|
|
34943
35325
|
groups: allGroups,
|
|
34944
35326
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
34945
35327
|
mode: exportMode ? "export" : "preview",
|
|
34946
|
-
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
|
+
}
|
|
34947
35344
|
};
|
|
34948
35345
|
const legendState = { activeGroup };
|
|
34949
35346
|
renderLegendD3(
|
|
@@ -34994,8 +35391,9 @@ function renderLegend3(rootSvg, legendGroups, totalWidth, legendY, palette, isDa
|
|
|
34994
35391
|
}
|
|
34995
35392
|
}
|
|
34996
35393
|
}
|
|
34997
|
-
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) {
|
|
34998
35395
|
d3Selection11.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
35396
|
+
const appHostedPlayback = controlsHost === "app" && !!playback;
|
|
34999
35397
|
const ctx = ScaleContext.identity();
|
|
35000
35398
|
const sc = buildScaledConstants(ctx);
|
|
35001
35399
|
const legendGroups = computeInfraLegendGroups(
|
|
@@ -35004,7 +35402,7 @@ function renderInfra(container, layout, palette, isDark, title, titleLineNumber,
|
|
|
35004
35402
|
palette,
|
|
35005
35403
|
layout.edges
|
|
35006
35404
|
);
|
|
35007
|
-
const hasLegend = legendGroups.length > 0 || !!playback;
|
|
35405
|
+
const hasLegend = legendGroups.length > 0 || !!playback && !appHostedPlayback;
|
|
35008
35406
|
const fixedLegend = !exportMode && hasLegend;
|
|
35009
35407
|
const legendDynamicH = hasLegend ? getMaxLegendReservedHeight(
|
|
35010
35408
|
{
|
|
@@ -35148,7 +35546,8 @@ function renderInfra(container, layout, palette, isDark, title, titleLineNumber,
|
|
|
35148
35546
|
isDark,
|
|
35149
35547
|
activeGroup ?? null,
|
|
35150
35548
|
playback ?? void 0,
|
|
35151
|
-
exportMode
|
|
35549
|
+
exportMode,
|
|
35550
|
+
controlsHost
|
|
35152
35551
|
);
|
|
35153
35552
|
legendSvg.selectAll(".infra-legend-group").style("pointer-events", "auto");
|
|
35154
35553
|
} else {
|
|
@@ -35161,7 +35560,8 @@ function renderInfra(container, layout, palette, isDark, title, titleLineNumber,
|
|
|
35161
35560
|
isDark,
|
|
35162
35561
|
activeGroup ?? null,
|
|
35163
35562
|
playback ?? void 0,
|
|
35164
|
-
exportMode
|
|
35563
|
+
exportMode,
|
|
35564
|
+
controlsHost
|
|
35165
35565
|
);
|
|
35166
35566
|
}
|
|
35167
35567
|
}
|
|
@@ -42796,6 +43196,9 @@ function renderTechRadar(container, parsed, palette, isDark, onClickItem, export
|
|
|
42796
43196
|
onToggle: (active) => options.onToggleListing(active)
|
|
42797
43197
|
}
|
|
42798
43198
|
]
|
|
43199
|
+
},
|
|
43200
|
+
...options.controlsHost !== void 0 && {
|
|
43201
|
+
controlsHost: options.controlsHost
|
|
42799
43202
|
}
|
|
42800
43203
|
};
|
|
42801
43204
|
const legendState = {
|
|
@@ -44619,7 +45022,7 @@ function computeCycleLayout(parsed, options) {
|
|
|
44619
45022
|
const circleNodes = parsed.options["circle-nodes"] === "true";
|
|
44620
45023
|
const nodeDims = parsed.nodes.map((node) => {
|
|
44621
45024
|
const hasDesc = !hideDescriptions && node.description.length > 0;
|
|
44622
|
-
const
|
|
45025
|
+
const labelWidth2 = Math.max(
|
|
44623
45026
|
MIN_NODE_WIDTH4,
|
|
44624
45027
|
node.label.length * LABEL_CHAR_W + NODE_PAD_X * 2
|
|
44625
45028
|
);
|
|
@@ -44628,12 +45031,12 @@ function computeCycleLayout(parsed, options) {
|
|
|
44628
45031
|
}
|
|
44629
45032
|
if (!hasDesc) {
|
|
44630
45033
|
return {
|
|
44631
|
-
width: Math.min(MAX_NODE_WIDTH3,
|
|
45034
|
+
width: Math.min(MAX_NODE_WIDTH3, labelWidth2),
|
|
44632
45035
|
height: PLAIN_NODE_HEIGHT,
|
|
44633
45036
|
wrappedDesc: []
|
|
44634
45037
|
};
|
|
44635
45038
|
}
|
|
44636
|
-
return chooseDescribedRectDims(node.description,
|
|
45039
|
+
return chooseDescribedRectDims(node.description, labelWidth2);
|
|
44637
45040
|
});
|
|
44638
45041
|
if (circleNodes) {
|
|
44639
45042
|
const maxDiam = Math.max(...nodeDims.map((d) => d.width));
|
|
@@ -44829,10 +45232,10 @@ function computeCycleLayout(parsed, options) {
|
|
|
44829
45232
|
scale
|
|
44830
45233
|
};
|
|
44831
45234
|
}
|
|
44832
|
-
function chooseDescribedRectDims(description,
|
|
45235
|
+
function chooseDescribedRectDims(description, labelWidth2) {
|
|
44833
45236
|
const minW = Math.min(
|
|
44834
45237
|
MAX_NODE_WIDTH3,
|
|
44835
|
-
Math.max(MIN_NODE_WIDTH4,
|
|
45238
|
+
Math.max(MIN_NODE_WIDTH4, labelWidth2, DESC_MIN_WIDTH)
|
|
44836
45239
|
);
|
|
44837
45240
|
let best = null;
|
|
44838
45241
|
let bestScore = Infinity;
|
|
@@ -45260,7 +45663,8 @@ function renderCycle(container, parsed, palette, isDark, onClickItem, exportDims
|
|
|
45260
45663
|
const hideDescriptions = (renderOptions?.hideDescriptions ?? false) || parsed.options["no-descriptions"] === "true" || viewState?.hd === true;
|
|
45261
45664
|
const showDescriptions = !hideDescriptions;
|
|
45262
45665
|
const hasDescriptions = parsed.nodes.some((n) => n.description.length > 0) || parsed.edges.some((e) => e.description.length > 0);
|
|
45263
|
-
const
|
|
45666
|
+
const appHostedControls = renderOptions?.controlsHost === "app";
|
|
45667
|
+
const hasLegend = !appHostedControls && hasDescriptions && !!renderOptions?.onToggleDescriptions;
|
|
45264
45668
|
const showTitle = !!parsed.title && parsed.options["no-title"] !== "on";
|
|
45265
45669
|
const legendOffset = hasLegend ? sLegendHeight : 0;
|
|
45266
45670
|
const layoutHeight = height - (showTitle ? sTitleAreaHeight : 0) - legendOffset;
|
|
@@ -45297,7 +45701,10 @@ function renderCycle(container, parsed, palette, isDark, onClickItem, exportDims
|
|
|
45297
45701
|
groups: [],
|
|
45298
45702
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
45299
45703
|
mode: renderOptions?.exportMode ? "export" : "preview",
|
|
45300
|
-
controlsGroup
|
|
45704
|
+
controlsGroup,
|
|
45705
|
+
...renderOptions?.controlsHost !== void 0 && {
|
|
45706
|
+
controlsHost: renderOptions.controlsHost
|
|
45707
|
+
}
|
|
45301
45708
|
};
|
|
45302
45709
|
const legendState = {
|
|
45303
45710
|
activeGroup: null,
|
|
@@ -45568,6 +45975,107 @@ function featureIndex(topo) {
|
|
|
45568
45975
|
}
|
|
45569
45976
|
return idx;
|
|
45570
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
|
+
}
|
|
45571
46079
|
function featureBbox(topo, geomId) {
|
|
45572
46080
|
const geom = geomObject(topo).geometries.find((g) => g.id === geomId);
|
|
45573
46081
|
if (!geom) return null;
|
|
@@ -45685,13 +46193,15 @@ function unionLongitudes(lons) {
|
|
|
45685
46193
|
}
|
|
45686
46194
|
return { west: pts[gapIdx], east: pts[gapIdx - 1] + 360 };
|
|
45687
46195
|
}
|
|
45688
|
-
var import_topojson_client, import_d3_geo, fold, DETACH_GAP_DEG, DETACH_AREA_FRAC;
|
|
46196
|
+
var import_topojson_client, import_d3_geo, fold, adjacencyCache, EDGE_EPS, DETACH_GAP_DEG, DETACH_AREA_FRAC;
|
|
45689
46197
|
var init_geo = __esm({
|
|
45690
46198
|
"src/map/geo.ts"() {
|
|
45691
46199
|
"use strict";
|
|
45692
46200
|
import_topojson_client = require("topojson-client");
|
|
45693
46201
|
import_d3_geo = require("d3-geo");
|
|
45694
46202
|
fold = (s) => s.normalize("NFD").replace(/\p{Diacritic}/gu, "").toLowerCase().trim();
|
|
46203
|
+
adjacencyCache = /* @__PURE__ */ new WeakMap();
|
|
46204
|
+
EDGE_EPS = 1e-9;
|
|
45695
46205
|
DETACH_GAP_DEG = 10;
|
|
45696
46206
|
DETACH_AREA_FRAC = 0.25;
|
|
45697
46207
|
}
|
|
@@ -45711,6 +46221,12 @@ function looksUS(lat, lon) {
|
|
|
45711
46221
|
if (lat < 15 || lat > 72) return false;
|
|
45712
46222
|
return lon >= -180 && lon <= -64 || lon >= 172;
|
|
45713
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
|
+
}
|
|
45714
46230
|
function resolveMap(parsed, data) {
|
|
45715
46231
|
const diagnostics = [...parsed.diagnostics];
|
|
45716
46232
|
const err = (line12, message, code) => {
|
|
@@ -45721,9 +46237,6 @@ function resolveMap(parsed, data) {
|
|
|
45721
46237
|
};
|
|
45722
46238
|
const result = {
|
|
45723
46239
|
title: parsed.title,
|
|
45724
|
-
...parsed.directives.subtitle !== void 0 && {
|
|
45725
|
-
subtitle: parsed.directives.subtitle
|
|
45726
|
-
},
|
|
45727
46240
|
...parsed.directives.caption !== void 0 && {
|
|
45728
46241
|
caption: parsed.directives.caption
|
|
45729
46242
|
},
|
|
@@ -45733,7 +46246,7 @@ function resolveMap(parsed, data) {
|
|
|
45733
46246
|
// renderer's job (step 4) — the resolver only carries `tags` + `tagGroups`
|
|
45734
46247
|
// through; it never resolves a tag value to a palette color (#10).
|
|
45735
46248
|
directives: { ...parsed.directives },
|
|
45736
|
-
basemaps: { world: "
|
|
46249
|
+
basemaps: { world: "detail", subdivisions: [] },
|
|
45737
46250
|
regions: [],
|
|
45738
46251
|
pois: [],
|
|
45739
46252
|
edges: [],
|
|
@@ -45742,7 +46255,8 @@ function resolveMap(parsed, data) {
|
|
|
45742
46255
|
[-180, -85],
|
|
45743
46256
|
[180, 85]
|
|
45744
46257
|
],
|
|
45745
|
-
projection: "
|
|
46258
|
+
projection: "equirectangular",
|
|
46259
|
+
poiFrameContainers: [],
|
|
45746
46260
|
diagnostics,
|
|
45747
46261
|
error: parsed.error
|
|
45748
46262
|
};
|
|
@@ -45752,7 +46266,10 @@ function resolveMap(parsed, data) {
|
|
|
45752
46266
|
...[...countryIndex.values()].map((v) => v.name),
|
|
45753
46267
|
...[...usStateIndex.values()].map((v) => v.name)
|
|
45754
46268
|
];
|
|
45755
|
-
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) => {
|
|
45756
46273
|
const f = fold(r.name);
|
|
45757
46274
|
return usStateIndex.has(f) && !countryIndex.has(f);
|
|
45758
46275
|
}) || parsed.regions.some(
|
|
@@ -45903,7 +46420,7 @@ function resolveMap(parsed, data) {
|
|
|
45903
46420
|
if (!scope)
|
|
45904
46421
|
warn(
|
|
45905
46422
|
line12,
|
|
45906
|
-
`"${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.`,
|
|
45907
46424
|
"W_MAP_AMBIGUOUS_NAME"
|
|
45908
46425
|
);
|
|
45909
46426
|
}
|
|
@@ -45916,17 +46433,21 @@ function resolveMap(parsed, data) {
|
|
|
45916
46433
|
return fold(pos.name);
|
|
45917
46434
|
};
|
|
45918
46435
|
const poiCountries = [];
|
|
45919
|
-
let
|
|
46436
|
+
let anyUsPoi = false;
|
|
46437
|
+
let anyNonNaPoi = false;
|
|
45920
46438
|
const noteCountry = (iso) => {
|
|
45921
46439
|
if (iso) {
|
|
45922
46440
|
poiCountries.push(iso);
|
|
45923
|
-
if (iso
|
|
46441
|
+
if (iso === "US") anyUsPoi = true;
|
|
46442
|
+
if (iso !== "US" && iso !== "CA" && iso !== "MX") anyNonNaPoi = true;
|
|
45924
46443
|
}
|
|
45925
46444
|
};
|
|
45926
46445
|
const deferred = [];
|
|
45927
46446
|
for (const p of parsed.pois) {
|
|
45928
46447
|
if (p.pos.kind === "coords") {
|
|
45929
|
-
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;
|
|
45930
46451
|
addResolvedPoi(p.pos.lat, p.pos.lon, p);
|
|
45931
46452
|
continue;
|
|
45932
46453
|
}
|
|
@@ -45944,14 +46465,15 @@ function resolveMap(parsed, data) {
|
|
|
45944
46465
|
deferred.push(p);
|
|
45945
46466
|
}
|
|
45946
46467
|
}
|
|
45947
|
-
const inferredCountry =
|
|
46468
|
+
const inferredCountry = localeCountry ?? mostCommonCountry(regions, poiCountries) ?? void 0;
|
|
46469
|
+
const inferredScope = localeSubdivision ?? inferredCountry;
|
|
45948
46470
|
for (const p of deferred) {
|
|
45949
46471
|
if (p.pos.kind !== "name") continue;
|
|
45950
46472
|
const got = lookupName(
|
|
45951
46473
|
p.pos.name,
|
|
45952
46474
|
p.pos.scope,
|
|
45953
46475
|
p.lineNumber,
|
|
45954
|
-
|
|
46476
|
+
inferredScope,
|
|
45955
46477
|
true
|
|
45956
46478
|
);
|
|
45957
46479
|
if (got.kind === "ok") {
|
|
@@ -46021,7 +46543,8 @@ function resolveMap(parsed, data) {
|
|
|
46021
46543
|
const meta = sizeValue !== void 0 ? { value: sizeValue } : {};
|
|
46022
46544
|
if (pos.kind === "coords") {
|
|
46023
46545
|
const id = alias ? fold(alias) : `@${pos.lat},${pos.lon}`;
|
|
46024
|
-
if (
|
|
46546
|
+
if (looksUS(pos.lat, pos.lon)) anyUsPoi = true;
|
|
46547
|
+
else if (!looksNorthAmericaNeighbor(pos.lat, pos.lon)) anyNonNaPoi = true;
|
|
46025
46548
|
if (!registry.has(id)) {
|
|
46026
46549
|
registerPoi(
|
|
46027
46550
|
id,
|
|
@@ -46044,7 +46567,7 @@ function resolveMap(parsed, data) {
|
|
|
46044
46567
|
if (registry.has(f)) return f;
|
|
46045
46568
|
const aliased = declaredByName.get(f);
|
|
46046
46569
|
if (aliased) return aliased;
|
|
46047
|
-
const got = lookupName(pos.name, pos.scope, line12,
|
|
46570
|
+
const got = lookupName(pos.name, pos.scope, line12, inferredScope, true);
|
|
46048
46571
|
if (got.kind !== "ok") return null;
|
|
46049
46572
|
noteCountry(got.iso);
|
|
46050
46573
|
registerPoi(
|
|
@@ -46101,9 +46624,12 @@ function resolveMap(parsed, data) {
|
|
|
46101
46624
|
}
|
|
46102
46625
|
routes.push({ stopIds, legs, lineNumber: rt.lineNumber });
|
|
46103
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;
|
|
46104
46631
|
const subdivisions = [];
|
|
46105
|
-
if (usSubdivisionReferenced ||
|
|
46106
|
-
subdivisions.push("us-states");
|
|
46632
|
+
if (usSubdivisionReferenced || usOriented) subdivisions.push("us-states");
|
|
46107
46633
|
const regionBoxes = [];
|
|
46108
46634
|
for (const ref of referencedRegionIds) {
|
|
46109
46635
|
const bb = featureBbox(data.usStates, ref.id);
|
|
@@ -46121,17 +46647,51 @@ function resolveMap(parsed, data) {
|
|
|
46121
46647
|
[-180, -85],
|
|
46122
46648
|
[180, 85]
|
|
46123
46649
|
];
|
|
46124
|
-
|
|
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
|
+
}
|
|
46125
46687
|
const lonSpan = extent2[1][0] - extent2[0][0];
|
|
46126
46688
|
const latSpan = extent2[1][1] - extent2[0][1];
|
|
46127
46689
|
const span = Math.max(lonSpan, latSpan);
|
|
46128
46690
|
const maxAbsLat = Math.max(Math.abs(extent2[0][1]), Math.abs(extent2[1][1]));
|
|
46129
|
-
const usDominant = (subdivisions.includes("us-states") || regions.some((r) => r.layer === "us-state")) && !regions.some((r) => r.layer === "country" && r.iso !== "US") && !anyNonUsPoi;
|
|
46130
46691
|
let projection;
|
|
46131
|
-
|
|
46132
|
-
|
|
46133
|
-
|
|
46134
|
-
} else if (usDominant) {
|
|
46692
|
+
if (isPoiOnly && usOriented && lonSpan < US_NATIONAL_LON_SPAN) {
|
|
46693
|
+
projection = "mercator";
|
|
46694
|
+
} else if (usOriented) {
|
|
46135
46695
|
projection = "albers-usa";
|
|
46136
46696
|
} else if (span > WORLD_SPAN || maxAbsLat > MERCATOR_MAX_LAT) {
|
|
46137
46697
|
projection = "equirectangular";
|
|
@@ -46149,11 +46709,20 @@ function resolveMap(parsed, data) {
|
|
|
46149
46709
|
result.edges = edges;
|
|
46150
46710
|
result.routes = routes;
|
|
46151
46711
|
result.basemaps = {
|
|
46152
|
-
|
|
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",
|
|
46153
46721
|
subdivisions
|
|
46154
46722
|
};
|
|
46155
46723
|
result.extent = extent2;
|
|
46156
46724
|
result.projection = projection;
|
|
46725
|
+
result.poiFrameContainers = containerRegionIds;
|
|
46157
46726
|
result.error = parsed.error ?? firstError(diagnostics);
|
|
46158
46727
|
return result;
|
|
46159
46728
|
}
|
|
@@ -46190,7 +46759,7 @@ function firstError(diags) {
|
|
|
46190
46759
|
const e = diags.find((d) => d.severity === "error");
|
|
46191
46760
|
return e ? formatDgmoError(e) : null;
|
|
46192
46761
|
}
|
|
46193
|
-
var WORLD_SPAN, MERCATOR_MAX_LAT, PAD_FRACTION, WORLD_LAT_SOUTH, WORLD_LAT_NORTH, REGION_ALIASES, US_STATE_POSTAL;
|
|
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;
|
|
46194
46763
|
var init_resolver2 = __esm({
|
|
46195
46764
|
"src/map/resolver.ts"() {
|
|
46196
46765
|
"use strict";
|
|
@@ -46199,8 +46768,11 @@ var init_resolver2 = __esm({
|
|
|
46199
46768
|
WORLD_SPAN = 90;
|
|
46200
46769
|
MERCATOR_MAX_LAT = 80;
|
|
46201
46770
|
PAD_FRACTION = 0.05;
|
|
46771
|
+
REGION_PAD_FRACTION = 0.12;
|
|
46202
46772
|
WORLD_LAT_SOUTH = -58;
|
|
46203
46773
|
WORLD_LAT_NORTH = 78;
|
|
46774
|
+
POI_ZOOM_FLOOR_DEG = 7;
|
|
46775
|
+
US_NATIONAL_LON_SPAN = 48;
|
|
46204
46776
|
REGION_ALIASES = {
|
|
46205
46777
|
// Common everyday names → the Natural-Earth display name actually shipped.
|
|
46206
46778
|
"united states": "united states of america",
|
|
@@ -46278,17 +46850,305 @@ var init_resolver2 = __esm({
|
|
|
46278
46850
|
}
|
|
46279
46851
|
});
|
|
46280
46852
|
|
|
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
|
+
}
|
|
46875
|
+
});
|
|
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]);
|
|
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 };
|
|
46936
|
+
}
|
|
46937
|
+
return best?.lines ?? [text];
|
|
46938
|
+
}
|
|
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 };
|
|
46943
|
+
}
|
|
46944
|
+
function rectFits(r, width, height) {
|
|
46945
|
+
return r.x >= 0 && r.y >= 0 && r.x + r.w <= width && r.y + r.h <= height;
|
|
46946
|
+
}
|
|
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]
|
|
47021
|
+
});
|
|
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;
|
|
47092
|
+
}
|
|
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"() {
|
|
47096
|
+
"use strict";
|
|
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
|
|
47115
|
+
};
|
|
47116
|
+
}
|
|
47117
|
+
});
|
|
47118
|
+
|
|
46281
47119
|
// src/map/layout.ts
|
|
46282
47120
|
function geomObject2(topo) {
|
|
46283
47121
|
const key = Object.keys(topo.objects)[0];
|
|
46284
47122
|
return topo.objects[key];
|
|
46285
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
|
+
}
|
|
46286
47140
|
function decodeLayer(topo) {
|
|
47141
|
+
const cached = decodeCache.get(topo);
|
|
47142
|
+
if (cached) return cached;
|
|
46287
47143
|
const out = /* @__PURE__ */ new Map();
|
|
46288
47144
|
for (const g of geomObject2(topo).geometries) {
|
|
46289
47145
|
const f = (0, import_topojson_client2.feature)(topo, g);
|
|
46290
|
-
|
|
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);
|
|
46291
47150
|
}
|
|
47151
|
+
decodeCache.set(topo, out);
|
|
46292
47152
|
return out;
|
|
46293
47153
|
}
|
|
46294
47154
|
function projectionFor(family) {
|
|
@@ -46297,9 +47157,12 @@ function projectionFor(family) {
|
|
|
46297
47157
|
return usConusProjection();
|
|
46298
47158
|
case "mercator":
|
|
46299
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)();
|
|
46300
47164
|
case "natural-earth":
|
|
46301
47165
|
return (0, import_d3_geo2.geoNaturalEarth1)();
|
|
46302
|
-
case "equirectangular":
|
|
46303
47166
|
default:
|
|
46304
47167
|
return (0, import_d3_geo2.geoEquirectangular)();
|
|
46305
47168
|
}
|
|
@@ -46318,13 +47181,11 @@ function mapNeutralLandColor(palette, isDark, _dataActive = false) {
|
|
|
46318
47181
|
isDark ? LAND_TINT_DARK : LAND_TINT_LIGHT
|
|
46319
47182
|
);
|
|
46320
47183
|
}
|
|
46321
|
-
function
|
|
46322
|
-
const { palette, isDark } = opts;
|
|
46323
|
-
const { width, height } = size;
|
|
47184
|
+
function buildMapProjection(resolved, data) {
|
|
46324
47185
|
const wantsUsStates = resolved.basemaps.subdivisions.includes("us-states");
|
|
46325
|
-
const usCrisp = resolved.projection === "albers-usa" && wantsUsStates && !!data.naLand;
|
|
47186
|
+
const usCrisp = (resolved.projection === "albers-usa" || resolved.projection === "mercator") && wantsUsStates && !!data.naLand;
|
|
46326
47187
|
const worldTopo = usCrisp ? data.worldDetail : resolved.basemaps.world === "detail" ? data.worldDetail : data.worldCoarse;
|
|
46327
|
-
const worldLayer = decodeLayer(worldTopo);
|
|
47188
|
+
const worldLayer = new Map(decodeLayer(worldTopo));
|
|
46328
47189
|
if (usCrisp && data.naLand) {
|
|
46329
47190
|
const [nbW, nbS, nbE, nbN] = [-140, 10, -52, 66];
|
|
46330
47191
|
const crisp = decodeLayer(data.naLand);
|
|
@@ -46333,16 +47194,109 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46333
47194
|
if (!base) continue;
|
|
46334
47195
|
const [[bw, bs], [be, bn]] = (0, import_d3_geo2.geoBounds)(base);
|
|
46335
47196
|
if (bw >= nbW && be <= nbE && bs >= nbS && bn <= nbN)
|
|
46336
|
-
worldLayer.set(iso, cf);
|
|
47197
|
+
worldLayer.set(iso, { ...cf, properties: base.properties });
|
|
46337
47198
|
}
|
|
46338
47199
|
}
|
|
46339
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);
|
|
46340
47294
|
const usContext = usLayer !== null;
|
|
46341
47295
|
const regionStroke = isDark ? mix(palette.bg, palette.text, 78) : mix(palette.text, palette.bg, 78);
|
|
46342
47296
|
const values = resolved.regions.filter((r) => r.value !== void 0).map((r) => r.value);
|
|
46343
|
-
const
|
|
46344
|
-
const rampMin =
|
|
46345
|
-
const rampMax =
|
|
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);
|
|
46346
47300
|
const rampHue = resolveColor(resolved.directives.regionMetricColor ?? "", palette) ?? palette.colors.red;
|
|
46347
47301
|
const hasRamp = values.length > 0;
|
|
46348
47302
|
const VALUE_NAME = hasRamp ? resolved.directives.regionMetric?.trim() || "Value" : null;
|
|
@@ -46363,7 +47317,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46363
47317
|
activeGroup = VALUE_NAME ?? (resolved.tagGroups.length > 0 ? resolved.tagGroups[0].name : null);
|
|
46364
47318
|
}
|
|
46365
47319
|
const activeIsScore = VALUE_NAME !== null && activeGroup === VALUE_NAME;
|
|
46366
|
-
const mutedBasemap =
|
|
47320
|
+
const mutedBasemap = activeGroup !== null;
|
|
46367
47321
|
const neutralFill = mapNeutralLandColor(palette, isDark, mutedBasemap);
|
|
46368
47322
|
const water = mapBackgroundColor(palette, isDark, mutedBasemap);
|
|
46369
47323
|
const lakeStroke = mix(regionStroke, water, 45);
|
|
@@ -46372,6 +47326,39 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46372
47326
|
palette.bg,
|
|
46373
47327
|
mutedBasemap ? isDark ? MUTED_FOREIGN_DARK : MUTED_FOREIGN_LIGHT : isDark ? FOREIGN_TINT_DARK : FOREIGN_TINT_LIGHT
|
|
46374
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);
|
|
46375
47362
|
const rampBase = isDark ? mix(palette.surface, palette.text, 28) : palette.bg;
|
|
46376
47363
|
const fillForValue = (s) => {
|
|
46377
47364
|
const t = rampMax > rampMin ? (s - rampMin) / (rampMax - rampMin) : 1;
|
|
@@ -46407,43 +47394,15 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46407
47394
|
if (activeIsScore) {
|
|
46408
47395
|
return r.value !== void 0 ? fillForValue(r.value) : neutralFill;
|
|
46409
47396
|
}
|
|
47397
|
+
if (colorizeActive) return (r.iso && colorByIso.get(r.iso)) ?? neutralFill;
|
|
46410
47398
|
return tagFill(r.tags, activeGroup) ?? neutralFill;
|
|
46411
47399
|
};
|
|
46412
47400
|
const regionById = new Map(resolved.regions.map((r) => [r.iso, r]));
|
|
46413
|
-
const
|
|
46414
|
-
const [[w, s], [e, n]] = resolved.extent;
|
|
46415
|
-
const N = 16;
|
|
46416
|
-
const coords = [];
|
|
46417
|
-
for (let i = 0; i <= N; i++) {
|
|
46418
|
-
const t = i / N;
|
|
46419
|
-
const lon = w + (e - w) * t;
|
|
46420
|
-
const lat = s + (n - s) * t;
|
|
46421
|
-
coords.push([lon, s], [lon, n], [w, lat], [e, lat]);
|
|
46422
|
-
}
|
|
46423
|
-
return {
|
|
46424
|
-
type: "Feature",
|
|
46425
|
-
properties: {},
|
|
46426
|
-
geometry: { type: "MultiPoint", coordinates: coords }
|
|
46427
|
-
};
|
|
46428
|
-
};
|
|
46429
|
-
let fitFeatures;
|
|
46430
|
-
if (resolved.projection === "albers-usa" && usLayer) {
|
|
46431
|
-
fitFeatures = [...usLayer.entries()].filter(([iso]) => !US_NON_CONUS.has(iso)).map(([, f]) => f);
|
|
46432
|
-
} else {
|
|
46433
|
-
fitFeatures = [extentOutline()];
|
|
46434
|
-
}
|
|
46435
|
-
const fitTarget = { type: "FeatureCollection", features: fitFeatures };
|
|
46436
|
-
const projection = projectionFor(resolved.projection);
|
|
46437
|
-
if (resolved.projection !== "albers-usa") {
|
|
46438
|
-
let centerLon = (resolved.extent[0][0] + resolved.extent[1][0]) / 2;
|
|
46439
|
-
if (centerLon > 180) centerLon -= 360;
|
|
46440
|
-
projection.rotate([-centerLon, 0]);
|
|
46441
|
-
}
|
|
46442
|
-
const TITLE_GAP = 16;
|
|
47401
|
+
const TITLE_GAP2 = 16;
|
|
46443
47402
|
let topPad = FIT_PAD;
|
|
46444
47403
|
if (resolved.title && resolved.pois.length > 0) {
|
|
46445
47404
|
const bannerBottom = (resolved.subtitle ? TITLE_Y + TITLE_FONT_SIZE : TITLE_Y) + TITLE_FONT_SIZE / 2;
|
|
46446
|
-
topPad = Math.max(FIT_PAD, bannerBottom +
|
|
47405
|
+
topPad = Math.max(FIT_PAD, bannerBottom + TITLE_GAP2);
|
|
46447
47406
|
}
|
|
46448
47407
|
const fitBox = [
|
|
46449
47408
|
[FIT_PAD, topPad],
|
|
@@ -46453,12 +47412,10 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46453
47412
|
]
|
|
46454
47413
|
];
|
|
46455
47414
|
projection.fitExtent(fitBox, fitTarget);
|
|
46456
|
-
const fitGB = (0, import_d3_geo2.geoBounds)(fitTarget);
|
|
46457
|
-
const fitIsGlobal = fitGB[1][0] - fitGB[0][0] >= 270 || fitGB[1][1] - fitGB[0][1] >= 130;
|
|
46458
47415
|
let path;
|
|
46459
47416
|
let project;
|
|
46460
47417
|
let stretchParams = null;
|
|
46461
|
-
if (fitIsGlobal) {
|
|
47418
|
+
if (fitIsGlobal && !opts.preferContain) {
|
|
46462
47419
|
const cb = (0, import_d3_geo2.geoPath)(projection).bounds(fitTarget);
|
|
46463
47420
|
const bx0 = cb[0][0];
|
|
46464
47421
|
const by0 = cb[0][1];
|
|
@@ -46500,7 +47457,9 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46500
47457
|
const insets = [];
|
|
46501
47458
|
const insetRegions = [];
|
|
46502
47459
|
const insetLabelSeeds = [];
|
|
46503
|
-
|
|
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)) {
|
|
46504
47463
|
const PAD = 8;
|
|
46505
47464
|
const GAP = 12;
|
|
46506
47465
|
const yB = height - FIT_PAD;
|
|
@@ -46565,8 +47524,18 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46565
47524
|
);
|
|
46566
47525
|
const d = (0, import_d3_geo2.geoPath)(proj)(f) ?? "";
|
|
46567
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
|
+
}
|
|
46568
47537
|
const r = regionById.get(iso);
|
|
46569
|
-
let fill2 = neutralFill;
|
|
47538
|
+
let fill2 = colorizeActive ? colorByIso.get(iso) ?? neutralFill : neutralFill;
|
|
46570
47539
|
let lineNumber = -1;
|
|
46571
47540
|
if (r?.layer === "us-state") {
|
|
46572
47541
|
fill2 = regionFill(r);
|
|
@@ -46585,13 +47554,14 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46585
47554
|
],
|
|
46586
47555
|
// The FITTED inset projection (just fit to this box) — captured so the
|
|
46587
47556
|
// geo-query can invert pixels inside the frame back to AK/HI coords.
|
|
46588
|
-
projection: proj
|
|
47557
|
+
projection: proj,
|
|
47558
|
+
...contextLand && { contextLand }
|
|
46589
47559
|
});
|
|
46590
47560
|
insetRegions.push({
|
|
46591
47561
|
id: iso,
|
|
46592
47562
|
d,
|
|
46593
47563
|
fill: fill2,
|
|
46594
|
-
stroke: regionStroke,
|
|
47564
|
+
stroke: colorizeActive ? colorizeStroke(fill2) : regionStroke,
|
|
46595
47565
|
lineNumber,
|
|
46596
47566
|
layer: "us-state",
|
|
46597
47567
|
...r?.value !== void 0 && { value: r.value },
|
|
@@ -46604,13 +47574,16 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46604
47574
|
}
|
|
46605
47575
|
return xr;
|
|
46606
47576
|
};
|
|
46607
|
-
|
|
46608
|
-
|
|
46609
|
-
alaskaProjection(),
|
|
46610
|
-
|
|
46611
|
-
|
|
46612
|
-
|
|
46613
|
-
|
|
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
|
+
);
|
|
46614
47587
|
}
|
|
46615
47588
|
const conusFit = resolved.projection === "albers-usa" && !!usLayer;
|
|
46616
47589
|
const classifyExtent = conusFit ? (0, import_d3_geo2.geoBounds)(fitTarget) : resolved.extent;
|
|
@@ -46626,15 +47599,24 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46626
47599
|
};
|
|
46627
47600
|
const ringOverlapsView = (ring) => {
|
|
46628
47601
|
let loMin = Infinity, loMax = -Infinity, rawMin = Infinity, rawMax = -Infinity;
|
|
47602
|
+
const lons = [];
|
|
46629
47603
|
for (const [rawLon] of ring) {
|
|
46630
47604
|
const lon = normLon(rawLon);
|
|
47605
|
+
lons.push(lon);
|
|
46631
47606
|
if (lon < loMin) loMin = lon;
|
|
46632
47607
|
if (lon > loMax) loMax = lon;
|
|
46633
47608
|
if (rawLon < rawMin) rawMin = rawLon;
|
|
46634
47609
|
if (rawLon > rawMax) rawMax = rawLon;
|
|
46635
47610
|
}
|
|
46636
|
-
|
|
46637
|
-
|
|
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;
|
|
46638
47620
|
let px0 = Infinity, py0 = Infinity, px1 = -Infinity, py1 = -Infinity, anyFinite = false;
|
|
46639
47621
|
for (const [lon, lat] of ring) {
|
|
46640
47622
|
const p = project(lon, lat);
|
|
@@ -46707,7 +47689,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46707
47689
|
const regions = [];
|
|
46708
47690
|
const pushRegionLayer = (layerFeatures, layerKind, shouldCull) => {
|
|
46709
47691
|
for (const [iso, f] of layerFeatures) {
|
|
46710
|
-
if (layerKind === "us-state" && usContext && INSET_STATES.has(iso))
|
|
47692
|
+
if (layerKind === "us-state" && usContext && resolved.projection === "albers-usa" && INSET_STATES.has(iso))
|
|
46711
47693
|
continue;
|
|
46712
47694
|
if (layerKind === "country" && usContext && iso === "US") continue;
|
|
46713
47695
|
if (layerKind === "country" && iso === "AQ" && !regionById.has("AQ"))
|
|
@@ -46719,7 +47701,8 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46719
47701
|
if (!d) continue;
|
|
46720
47702
|
const isThisLayer = r?.layer === layerKind;
|
|
46721
47703
|
const isForeign = layerKind === "country" && usContext && iso !== "US";
|
|
46722
|
-
|
|
47704
|
+
const baseFill = isForeign ? foreignFill : neutralFill;
|
|
47705
|
+
let fill2 = colorizeActive ? colorByIso.get(iso) ?? baseFill : baseFill;
|
|
46723
47706
|
let label;
|
|
46724
47707
|
let lineNumber = -1;
|
|
46725
47708
|
let layer = "base";
|
|
@@ -46728,12 +47711,14 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46728
47711
|
lineNumber = r.lineNumber;
|
|
46729
47712
|
layer = layerKind;
|
|
46730
47713
|
label = r.name;
|
|
47714
|
+
} else {
|
|
47715
|
+
label = f.properties?.name;
|
|
46731
47716
|
}
|
|
46732
47717
|
regions.push({
|
|
46733
47718
|
id: iso,
|
|
46734
47719
|
d,
|
|
46735
47720
|
fill: fill2,
|
|
46736
|
-
stroke: regionStroke,
|
|
47721
|
+
stroke: colorizeActive ? colorizeStroke(fill2) : regionStroke,
|
|
46737
47722
|
lineNumber,
|
|
46738
47723
|
layer,
|
|
46739
47724
|
...label !== void 0 && { label },
|
|
@@ -46761,9 +47746,41 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46761
47746
|
});
|
|
46762
47747
|
}
|
|
46763
47748
|
}
|
|
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;
|
|
46764
47781
|
const relief = [];
|
|
46765
47782
|
let reliefHatch = null;
|
|
46766
|
-
if (
|
|
47783
|
+
if (reliefAllowed && data.mountainRanges) {
|
|
46767
47784
|
for (const [, f] of decodeLayer(data.mountainRanges)) {
|
|
46768
47785
|
const viewF = isGlobalView ? dropFrameFillers(f) : cullFeatureToView(f);
|
|
46769
47786
|
if (!viewF) continue;
|
|
@@ -46779,16 +47796,32 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46779
47796
|
if (relief.length) {
|
|
46780
47797
|
const darkTone = isDark ? palette.bg : palette.text;
|
|
46781
47798
|
const lightTone = isDark ? palette.text : palette.bg;
|
|
46782
|
-
const
|
|
47799
|
+
const reliefLandRef = colorizeActive ? isDark ? palette.surface : palette.bg : neutralFill;
|
|
47800
|
+
const landLum = relativeLuminance(reliefLandRef);
|
|
46783
47801
|
const tone = Math.abs(landLum - relativeLuminance(darkTone)) > 0.04 ? darkTone : lightTone;
|
|
46784
47802
|
reliefHatch = {
|
|
46785
|
-
color: mix(tone,
|
|
47803
|
+
color: mix(tone, reliefLandRef, RELIEF_HATCH_STRENGTH),
|
|
46786
47804
|
spacing: RELIEF_HATCH_SPACING,
|
|
46787
47805
|
width: RELIEF_HATCH_WIDTH
|
|
46788
47806
|
};
|
|
46789
47807
|
}
|
|
46790
47808
|
}
|
|
46791
|
-
|
|
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);
|
|
46792
47825
|
const rivers = [];
|
|
46793
47826
|
if (data.rivers) {
|
|
46794
47827
|
for (const [, f] of decodeLayer(data.rivers)) {
|
|
@@ -46844,38 +47877,108 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46844
47877
|
const xy = project(p.lon, p.lat);
|
|
46845
47878
|
if (xy) projected.push({ p, xy });
|
|
46846
47879
|
}
|
|
46847
|
-
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);
|
|
46848
47909
|
for (const e of projected) {
|
|
46849
|
-
|
|
46850
|
-
|
|
46851
|
-
|
|
46852
|
-
|
|
46853
|
-
|
|
46854
|
-
|
|
46855
|
-
|
|
46856
|
-
|
|
46857
|
-
|
|
46858
|
-
|
|
46859
|
-
|
|
46860
|
-
|
|
46861
|
-
|
|
46862
|
-
|
|
46863
|
-
|
|
46864
|
-
|
|
46865
|
-
|
|
46866
|
-
|
|
46867
|
-
|
|
46868
|
-
|
|
46869
|
-
|
|
46870
|
-
|
|
46871
|
-
|
|
46872
|
-
|
|
46873
|
-
|
|
46874
|
-
|
|
46875
|
-
|
|
46876
|
-
|
|
46877
|
-
|
|
46878
|
-
|
|
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
|
|
46879
47982
|
});
|
|
46880
47983
|
}
|
|
46881
47984
|
const legs = [];
|
|
@@ -46925,16 +48028,26 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46925
48028
|
if (!a || !b) continue;
|
|
46926
48029
|
const mx = (a.cx + b.cx) / 2;
|
|
46927
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;
|
|
46928
48038
|
legs.push({
|
|
46929
|
-
d: legPath(a, b,
|
|
48039
|
+
d: legPath(a, b, bow.curved, bow.offset),
|
|
46930
48040
|
width: routeWidthFor(Number(leg.value)),
|
|
46931
48041
|
color: mix(palette.text, palette.bg, 72),
|
|
46932
48042
|
arrow: true,
|
|
46933
48043
|
lineNumber: leg.lineNumber,
|
|
46934
48044
|
...leg.label !== void 0 && {
|
|
46935
48045
|
label: leg.label,
|
|
46936
|
-
labelX:
|
|
46937
|
-
labelY:
|
|
48046
|
+
labelX: bow.labelX,
|
|
48047
|
+
labelY: bow.labelY,
|
|
48048
|
+
labelColor: routeLabelStyle.color,
|
|
48049
|
+
labelHalo: routeLabelStyle.halo,
|
|
48050
|
+
labelHaloColor: routeLabelStyle.haloColor
|
|
46938
48051
|
}
|
|
46939
48052
|
});
|
|
46940
48053
|
}
|
|
@@ -46962,20 +48075,29 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46962
48075
|
const a = poiScreen.get(e.fromId);
|
|
46963
48076
|
const b = poiScreen.get(e.toId);
|
|
46964
48077
|
if (!a || !b) return;
|
|
46965
|
-
const
|
|
46966
|
-
const offset = n > 1 ? (i - (n - 1) / 2) * FAN_STEP : 0;
|
|
48078
|
+
const fanOffset = n > 1 ? (i - (n - 1) / 2) * FAN_STEP : 0;
|
|
46967
48079
|
const mx = (a.cx + b.cx) / 2;
|
|
46968
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;
|
|
46969
48088
|
legs.push({
|
|
46970
|
-
d: legPath(a, b, curved, offset),
|
|
48089
|
+
d: legPath(a, b, bow.curved, bow.offset),
|
|
46971
48090
|
width: widthFor(e),
|
|
46972
48091
|
color: mix(palette.text, palette.bg, 66),
|
|
46973
48092
|
arrow: e.directed,
|
|
46974
48093
|
lineNumber: e.lineNumber,
|
|
46975
48094
|
...e.label !== void 0 && {
|
|
46976
48095
|
label: e.label,
|
|
46977
|
-
labelX:
|
|
46978
|
-
labelY:
|
|
48096
|
+
labelX: bow.labelX,
|
|
48097
|
+
labelY: bow.labelY,
|
|
48098
|
+
labelColor: edgeLabelStyle.color,
|
|
48099
|
+
labelHalo: edgeLabelStyle.halo,
|
|
48100
|
+
labelHaloColor: edgeLabelStyle.haloColor
|
|
46979
48101
|
}
|
|
46980
48102
|
});
|
|
46981
48103
|
});
|
|
@@ -47017,25 +48139,25 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47017
48139
|
}
|
|
47018
48140
|
}
|
|
47019
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));
|
|
47020
|
-
const
|
|
48142
|
+
const showRegionLabels = resolved.directives.noRegionLabels !== true;
|
|
48143
|
+
const isCompact = width < COMPACT_WIDTH_PX;
|
|
47021
48144
|
const LABEL_PADX = 6;
|
|
47022
48145
|
const LABEL_PADY = 3;
|
|
47023
|
-
const labelW = (text) => measureLegendText(text,
|
|
47024
|
-
const labelH =
|
|
48146
|
+
const labelW = (text) => measureLegendText(text, FONT2) + 2 * LABEL_PADX;
|
|
48147
|
+
const labelH = FONT2 + 2 * LABEL_PADY;
|
|
47025
48148
|
const pushRegionLabel = (x, y, text, fill2, lineNumber) => {
|
|
47026
|
-
const color =
|
|
47027
|
-
|
|
47028
|
-
|
|
47029
|
-
|
|
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
|
|
47030
48153
|
);
|
|
47031
|
-
const haloColor = color === palette.textOnFillLight ? palette.textOnFillDark : palette.textOnFillLight;
|
|
47032
48154
|
labels.push({
|
|
47033
48155
|
x,
|
|
47034
48156
|
y,
|
|
47035
48157
|
text,
|
|
47036
48158
|
anchor: "middle",
|
|
47037
48159
|
color,
|
|
47038
|
-
halo:
|
|
48160
|
+
halo: overflows,
|
|
47039
48161
|
haloColor,
|
|
47040
48162
|
lineNumber
|
|
47041
48163
|
});
|
|
@@ -47044,21 +48166,50 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47044
48166
|
US: [-98.5, 39.5]
|
|
47045
48167
|
// CONUS geographic centre (near Lebanon, Kansas)
|
|
47046
48168
|
};
|
|
47047
|
-
|
|
47048
|
-
|
|
47049
|
-
|
|
47050
|
-
|
|
47051
|
-
|
|
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;
|
|
47052
48183
|
const [[x0, y0], [x1, y1]] = path.bounds(f);
|
|
47053
|
-
const
|
|
47054
|
-
|
|
47055
|
-
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;
|
|
47056
48189
|
const c = anchor ? project(anchor[0], anchor[1]) : path.centroid(f);
|
|
47057
|
-
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));
|
|
47058
48209
|
pushRegionLabel(c[0], c[1], text, r.fill, r.lineNumber);
|
|
47059
48210
|
}
|
|
47060
48211
|
for (const seed of insetLabelSeeds) {
|
|
47061
|
-
const text =
|
|
48212
|
+
const text = isCompact ? seed.iso.replace(/^US-/, "") : seed.name;
|
|
47062
48213
|
const src = regionById.get(seed.iso);
|
|
47063
48214
|
pushRegionLabel(
|
|
47064
48215
|
seed.x,
|
|
@@ -47069,22 +48220,26 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47069
48220
|
);
|
|
47070
48221
|
}
|
|
47071
48222
|
}
|
|
47072
|
-
|
|
47073
|
-
|
|
47074
|
-
const ordered = [...pois].sort(
|
|
47075
|
-
(a, b) => a.lineNumber - b.lineNumber || (a.id < b.id ? -1 : 1)
|
|
47076
|
-
);
|
|
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));
|
|
47077
48225
|
const poiById = new Map(resolved.pois.map((q) => [q.id, q]));
|
|
47078
48226
|
const labelText = (p) => {
|
|
47079
48227
|
const src = poiById.get(p.id);
|
|
47080
48228
|
return src?.label ?? src?.name ?? p.id;
|
|
47081
48229
|
};
|
|
47082
|
-
const poiLabH =
|
|
48230
|
+
const poiLabH = FONT2 * 1.25;
|
|
47083
48231
|
const labelInfo = (p) => {
|
|
47084
48232
|
const text = labelText(p);
|
|
47085
|
-
return { text, w: measureLegendText(text,
|
|
48233
|
+
return { text, w: measureLegendText(text, FONT2) };
|
|
47086
48234
|
};
|
|
47087
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
|
+
}
|
|
47088
48243
|
const inlineRect = (p, w, side) => {
|
|
47089
48244
|
switch (side) {
|
|
47090
48245
|
case "right":
|
|
@@ -47114,11 +48269,11 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47114
48269
|
const x = side === "right" ? rect.x : side === "left" ? rect.x + w : p.cx;
|
|
47115
48270
|
labels.push({
|
|
47116
48271
|
x,
|
|
47117
|
-
y: rect.y + poiLabH / 2 +
|
|
48272
|
+
y: rect.y + poiLabH / 2 + FONT2 / 3,
|
|
47118
48273
|
text,
|
|
47119
48274
|
anchor,
|
|
47120
48275
|
color: palette.text,
|
|
47121
|
-
halo:
|
|
48276
|
+
halo: false,
|
|
47122
48277
|
haloColor: palette.bg,
|
|
47123
48278
|
poiId: p.id,
|
|
47124
48279
|
lineNumber: p.lineNumber
|
|
@@ -47129,43 +48284,60 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47129
48284
|
return rect.x >= 0 && rect.x + rect.w <= width && rect.y >= 0 && rect.y + rect.h <= height && !collides(rect);
|
|
47130
48285
|
};
|
|
47131
48286
|
const GROUP_R = 30;
|
|
47132
|
-
const
|
|
48287
|
+
const groups2 = [];
|
|
47133
48288
|
for (const p of ordered) {
|
|
47134
|
-
const near =
|
|
48289
|
+
const near = groups2.find(
|
|
47135
48290
|
(g) => g.some((q) => Math.hypot(q.cx - p.cx, q.cy - p.cy) < GROUP_R)
|
|
47136
48291
|
);
|
|
47137
48292
|
if (near) near.push(p);
|
|
47138
|
-
else
|
|
48293
|
+
else groups2.push([p]);
|
|
47139
48294
|
}
|
|
47140
48295
|
const ROW_GAP2 = 3;
|
|
47141
48296
|
const step = poiLabH + ROW_GAP2;
|
|
47142
48297
|
const COL_GAP = 16;
|
|
47143
|
-
const
|
|
47144
|
-
|
|
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) => {
|
|
47145
48300
|
const left = Math.min(...items.map((o) => o.p.cx - o.p.r));
|
|
47146
48301
|
const right = Math.max(...items.map((o) => o.p.cx + o.p.r));
|
|
47147
|
-
const cyMid = (Math.min(...items.map((o) => o.p.cy)) + Math.max(...items.map((o) => o.p.cy))) / 2;
|
|
47148
48302
|
const maxW = Math.max(...items.map((o) => o.w));
|
|
47149
|
-
const
|
|
47150
|
-
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);
|
|
47151
48305
|
const totalH = items.length * step;
|
|
47152
48306
|
let startY = cyMid - totalH / 2;
|
|
47153
48307
|
startY = Math.max(2, Math.min(startY, height - totalH - 2));
|
|
47154
|
-
items.
|
|
48308
|
+
return items.map((o, i) => {
|
|
47155
48309
|
const rowCy = startY + i * step + step / 2;
|
|
47156
|
-
|
|
47157
|
-
|
|
47158
|
-
|
|
47159
|
-
|
|
47160
|
-
|
|
47161
|
-
|
|
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);
|
|
47162
48334
|
labels.push({
|
|
47163
48335
|
x: colX,
|
|
47164
|
-
y: rowCy +
|
|
48336
|
+
y: rowCy + FONT2 / 3,
|
|
47165
48337
|
text: o.text,
|
|
47166
48338
|
anchor: side === "right" ? "start" : "end",
|
|
47167
48339
|
color: palette.text,
|
|
47168
|
-
halo:
|
|
48340
|
+
halo: false,
|
|
47169
48341
|
haloColor: palette.bg,
|
|
47170
48342
|
leader: {
|
|
47171
48343
|
x1: o.p.cx,
|
|
@@ -47175,24 +48347,141 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47175
48347
|
},
|
|
47176
48348
|
leaderColor: o.p.fill,
|
|
47177
48349
|
poiId: o.p.id,
|
|
47178
|
-
lineNumber: o.p.lineNumber
|
|
48350
|
+
lineNumber: o.p.lineNumber,
|
|
48351
|
+
...clusterId !== void 0 && { clusterMember: clusterId }
|
|
47179
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
|
|
47180
48375
|
});
|
|
47181
48376
|
};
|
|
47182
|
-
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);
|
|
47183
48387
|
if (g.length === 1) {
|
|
47184
|
-
const p =
|
|
47185
|
-
const { text, w } = labelInfo(p);
|
|
48388
|
+
const { p, text, w } = items[0];
|
|
47186
48389
|
const side = ["right", "left", "above", "below"].find(
|
|
47187
48390
|
(s) => inlineFits(p, w, s)
|
|
47188
48391
|
);
|
|
47189
|
-
if (side)
|
|
47190
|
-
|
|
47191
|
-
|
|
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;
|
|
47192
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
|
+
});
|
|
47193
48466
|
}
|
|
47194
|
-
placeColumn(g);
|
|
47195
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);
|
|
47196
48485
|
}
|
|
47197
48486
|
let legend = null;
|
|
47198
48487
|
if (!resolved.directives.noLegend) {
|
|
@@ -47229,27 +48518,33 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47229
48518
|
rivers,
|
|
47230
48519
|
relief,
|
|
47231
48520
|
reliefHatch,
|
|
48521
|
+
coastlineStyle,
|
|
47232
48522
|
legs,
|
|
47233
48523
|
pois,
|
|
48524
|
+
clusters,
|
|
47234
48525
|
labels,
|
|
47235
48526
|
legend,
|
|
47236
48527
|
insets,
|
|
47237
48528
|
insetRegions,
|
|
47238
48529
|
projection,
|
|
47239
|
-
stretch: stretchParams
|
|
48530
|
+
stretch: stretchParams,
|
|
48531
|
+
diagnostics: []
|
|
47240
48532
|
};
|
|
47241
48533
|
}
|
|
47242
|
-
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;
|
|
47243
48535
|
var init_layout15 = __esm({
|
|
47244
48536
|
"src/map/layout.ts"() {
|
|
47245
48537
|
"use strict";
|
|
47246
48538
|
import_d3_geo2 = require("d3-geo");
|
|
47247
48539
|
import_topojson_client2 = require("topojson-client");
|
|
47248
48540
|
init_color_utils();
|
|
48541
|
+
init_geo();
|
|
48542
|
+
init_colorize();
|
|
47249
48543
|
init_colors();
|
|
47250
48544
|
init_label_layout();
|
|
47251
48545
|
init_legend_constants();
|
|
47252
48546
|
init_title_constants();
|
|
48547
|
+
init_context_labels();
|
|
47253
48548
|
FIT_PAD = 24;
|
|
47254
48549
|
RAMP_FLOOR = 15;
|
|
47255
48550
|
R_DEFAULT = 6;
|
|
@@ -47257,32 +48552,66 @@ var init_layout15 = __esm({
|
|
|
47257
48552
|
R_MAX = 22;
|
|
47258
48553
|
W_MIN = 1.25;
|
|
47259
48554
|
W_MAX = 8;
|
|
47260
|
-
|
|
47261
|
-
|
|
48555
|
+
FONT2 = 11;
|
|
48556
|
+
MAX_CLUSTER_EXTENT_FACTOR = 0.18;
|
|
48557
|
+
MAX_COLUMN_ROWS = 7;
|
|
48558
|
+
REGION_LABEL_HALO_RATIO = 4.5;
|
|
47262
48559
|
LAND_TINT_LIGHT = 12;
|
|
47263
48560
|
LAND_TINT_DARK = 24;
|
|
47264
48561
|
TAG_TINT_LIGHT = 60;
|
|
47265
48562
|
TAG_TINT_DARK = 68;
|
|
47266
|
-
WATER_TINT_LIGHT =
|
|
47267
|
-
WATER_TINT_DARK =
|
|
48563
|
+
WATER_TINT_LIGHT = 24;
|
|
48564
|
+
WATER_TINT_DARK = 24;
|
|
47268
48565
|
RIVER_WIDTH = 1.3;
|
|
48566
|
+
COMPACT_WIDTH_PX = 480;
|
|
47269
48567
|
RELIEF_MIN_AREA = 12;
|
|
47270
48568
|
RELIEF_MIN_DIM = 2;
|
|
47271
|
-
RELIEF_HATCH_SPACING =
|
|
47272
|
-
RELIEF_HATCH_WIDTH = 0.
|
|
48569
|
+
RELIEF_HATCH_SPACING = 2;
|
|
48570
|
+
RELIEF_HATCH_WIDTH = 0.15;
|
|
47273
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;
|
|
47274
48581
|
FOREIGN_TINT_LIGHT = 30;
|
|
47275
48582
|
FOREIGN_TINT_DARK = 62;
|
|
47276
48583
|
MUTED_FOREIGN_LIGHT = 28;
|
|
47277
48584
|
MUTED_FOREIGN_DARK = 16;
|
|
47278
48585
|
COLO_R = 9;
|
|
47279
48586
|
GOLDEN_ANGLE = 2.399963229728653;
|
|
48587
|
+
STACK_OVERLAP = 1;
|
|
48588
|
+
STACK_RING_MAX = 8;
|
|
48589
|
+
STACK_RING_GAP = 4;
|
|
47280
48590
|
FAN_STEP = 16;
|
|
47281
48591
|
ARC_CURVE_FRAC = 0.18;
|
|
48592
|
+
decodeCache = /* @__PURE__ */ new WeakMap();
|
|
47282
48593
|
usConusProjection = () => (0, import_d3_geo2.geoConicEqualArea)().parallels([29.5, 45.5]).rotate([96, 0]);
|
|
47283
48594
|
alaskaProjection = () => (0, import_d3_geo2.geoConicEqualArea)().rotate([154, 0]).center([-2, 58.5]).parallels([55, 65]);
|
|
47284
48595
|
hawaiiProjection = () => (0, import_d3_geo2.geoMercator)();
|
|
47285
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
|
+
};
|
|
47286
48615
|
US_NON_CONUS = /* @__PURE__ */ new Set([
|
|
47287
48616
|
"US-AK",
|
|
47288
48617
|
"US-HI",
|
|
@@ -47301,6 +48630,58 @@ __export(renderer_exports16, {
|
|
|
47301
48630
|
renderMap: () => renderMap,
|
|
47302
48631
|
renderMapForExport: () => renderMapForExport
|
|
47303
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
|
+
}
|
|
47304
48685
|
function renderMap(container, resolved, data, palette, isDark, onClickItem, exportDims, activeGroupOverride) {
|
|
47305
48686
|
d3Selection18.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
47306
48687
|
const width = exportDims?.width ?? container.clientWidth;
|
|
@@ -47313,6 +48694,11 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47313
48694
|
{
|
|
47314
48695
|
palette,
|
|
47315
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,
|
|
47316
48702
|
...activeGroupOverride !== void 0 && {
|
|
47317
48703
|
activeGroup: activeGroupOverride
|
|
47318
48704
|
}
|
|
@@ -47326,6 +48712,7 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47326
48712
|
const gRegions = svg.append("g").attr("class", "dgmo-map-regions");
|
|
47327
48713
|
const drawRegion = (g, r, strokeWidth) => {
|
|
47328
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);
|
|
47329
48716
|
if (r.layer !== "base") {
|
|
47330
48717
|
p.classed("dgmo-map-region", true).attr("data-region", r.id);
|
|
47331
48718
|
if (r.value !== void 0) p.attr("data-value", r.value);
|
|
@@ -47360,6 +48747,38 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47360
48747
|
gRelief.append("line").attr("x1", 0).attr("y1", y).attr("x2", width).attr("y2", y);
|
|
47361
48748
|
}
|
|
47362
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
|
+
}
|
|
47363
48782
|
if (layout.rivers.length) {
|
|
47364
48783
|
const gRivers = svg.append("g").attr("class", "dgmo-map-rivers").attr("fill", "none");
|
|
47365
48784
|
for (const r of layout.rivers) {
|
|
@@ -47368,15 +48787,61 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47368
48787
|
}
|
|
47369
48788
|
if (layout.insets.length) {
|
|
47370
48789
|
const insetG = svg.append("g").attr("class", "dgmo-map-insets");
|
|
47371
|
-
|
|
48790
|
+
layout.insets.forEach((box, bi) => {
|
|
47372
48791
|
const d = box.points.map((p, i) => `${i ? "L" : "M"}${p[0]},${p[1]}`).join("") + "Z";
|
|
47373
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");
|
|
47374
|
-
|
|
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
|
+
});
|
|
47375
48799
|
for (const r of layout.insetRegions) drawRegion(insetG, r, 0.5);
|
|
47376
|
-
|
|
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
|
+
};
|
|
47377
48841
|
const gLegs = svg.append("g").attr("class", "dgmo-map-legs").attr("fill", "none");
|
|
47378
48842
|
layout.legs.forEach((leg, i) => {
|
|
47379
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);
|
|
47380
48845
|
if (leg.arrow) {
|
|
47381
48846
|
const id = `dgmo-map-arrow-${i}`;
|
|
47382
48847
|
const s = arrowSize(leg.width);
|
|
@@ -47384,25 +48849,38 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47384
48849
|
p.attr("marker-end", `url(#${id})`);
|
|
47385
48850
|
}
|
|
47386
48851
|
if (leg.label !== void 0 && leg.labelX !== void 0) {
|
|
47387
|
-
emitText(
|
|
48852
|
+
const lt = emitText(
|
|
47388
48853
|
gLegs,
|
|
47389
48854
|
leg.labelX,
|
|
47390
48855
|
leg.labelY ?? 0,
|
|
47391
48856
|
leg.label,
|
|
47392
48857
|
"middle",
|
|
47393
|
-
palette.textMuted,
|
|
47394
|
-
haloColor,
|
|
47395
|
-
true,
|
|
48858
|
+
leg.labelColor ?? palette.textMuted,
|
|
48859
|
+
leg.labelHaloColor ?? haloColor,
|
|
48860
|
+
leg.labelHalo ?? true,
|
|
47396
48861
|
LABEL_FONT - 1
|
|
47397
48862
|
);
|
|
48863
|
+
wireSync(lt, leg.lineNumber);
|
|
47398
48864
|
}
|
|
47399
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
|
+
}
|
|
47400
48876
|
const gPois = svg.append("g").attr("class", "dgmo-map-pois");
|
|
47401
48877
|
for (const poi of layout.pois) {
|
|
47402
48878
|
if (poi.isOrigin) {
|
|
47403
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);
|
|
47404
48880
|
}
|
|
47405
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);
|
|
47406
48884
|
if (poi.tags) {
|
|
47407
48885
|
for (const [group, value] of Object.entries(poi.tags)) {
|
|
47408
48886
|
c.attr(`data-tag-${group.toLowerCase()}`, value.toLowerCase());
|
|
@@ -47430,12 +48908,32 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47430
48908
|
}
|
|
47431
48909
|
const gLabels = svg.append("g").attr("class", "dgmo-map-labels");
|
|
47432
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
|
+
}
|
|
47433
48928
|
if (lab.leader) {
|
|
47434
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(
|
|
47435
48930
|
"stroke",
|
|
47436
48931
|
lab.leaderColor ?? mix(palette.textMuted, palette.bg, 60)
|
|
47437
48932
|
).attr("stroke-width", lab.leaderColor ? 1 : 0.75);
|
|
47438
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);
|
|
47439
48937
|
}
|
|
47440
48938
|
const t = emitText(
|
|
47441
48939
|
gLabels,
|
|
@@ -47446,11 +48944,38 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47446
48944
|
lab.color,
|
|
47447
48945
|
lab.haloColor,
|
|
47448
48946
|
lab.halo,
|
|
47449
|
-
LABEL_FONT
|
|
48947
|
+
LABEL_FONT,
|
|
48948
|
+
lab.italic,
|
|
48949
|
+
lab.letterSpacing,
|
|
48950
|
+
lab.lines
|
|
47450
48951
|
);
|
|
47451
48952
|
if (lab.poiId !== void 0) {
|
|
47452
48953
|
t.attr("data-poi", lab.poiId).style("cursor", "default");
|
|
47453
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
|
+
}
|
|
47454
48979
|
}
|
|
47455
48980
|
if (layout.legend) {
|
|
47456
48981
|
const legendY = (layout.title ? TITLE_Y + TITLE_FONT_SIZE : 0) + (layout.subtitle ? TITLE_FONT_SIZE : 0) + 8;
|
|
@@ -47487,7 +49012,7 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47487
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);
|
|
47488
49013
|
}
|
|
47489
49014
|
if (layout.subtitle) {
|
|
47490
|
-
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);
|
|
47491
49016
|
}
|
|
47492
49017
|
if (layout.caption) {
|
|
47493
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);
|
|
@@ -47496,10 +49021,21 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47496
49021
|
function renderMapForExport(container, resolved, data, palette, isDark, exportDims) {
|
|
47497
49022
|
renderMap(container, resolved, data, palette, isDark, void 0, exportDims);
|
|
47498
49023
|
}
|
|
47499
|
-
function emitText(g, x, y, text, anchor, color, halo, withHalo, fontSize) {
|
|
47500
|
-
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);
|
|
47501
49037
|
if (withHalo) {
|
|
47502
|
-
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);
|
|
47503
49039
|
}
|
|
47504
49040
|
return t;
|
|
47505
49041
|
}
|
|
@@ -47517,6 +49053,56 @@ var init_renderer16 = __esm({
|
|
|
47517
49053
|
}
|
|
47518
49054
|
});
|
|
47519
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
|
+
|
|
47520
49106
|
// src/map/load-data.ts
|
|
47521
49107
|
var load_data_exports = {};
|
|
47522
49108
|
__export(load_data_exports, {
|
|
@@ -47575,12 +49161,17 @@ function loadMapData() {
|
|
|
47575
49161
|
mountainRanges,
|
|
47576
49162
|
naLand,
|
|
47577
49163
|
naLakes,
|
|
49164
|
+
waterBodies,
|
|
47578
49165
|
gazetteer
|
|
47579
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.
|
|
47580
49171
|
readJson(nb, dir, FILES.worldCoarse),
|
|
47581
49172
|
readJson(nb, dir, FILES.worldDetail),
|
|
47582
49173
|
readJson(nb, dir, FILES.usStates),
|
|
47583
|
-
// Lakes/rivers/mountain/NA assets are optional — older bundles may predate them.
|
|
49174
|
+
// Lakes/rivers/mountain/NA/water assets are optional — older bundles may predate them.
|
|
47584
49175
|
readJson(nb, dir, FILES.lakes).catch(() => void 0),
|
|
47585
49176
|
readJson(nb, dir, FILES.rivers).catch(() => void 0),
|
|
47586
49177
|
readJson(nb, dir, FILES.mountainRanges).catch(
|
|
@@ -47588,6 +49179,7 @@ function loadMapData() {
|
|
|
47588
49179
|
),
|
|
47589
49180
|
readJson(nb, dir, FILES.naLand).catch(() => void 0),
|
|
47590
49181
|
readJson(nb, dir, FILES.naLakes).catch(() => void 0),
|
|
49182
|
+
readJson(nb, dir, FILES.waterBodies).catch(() => void 0),
|
|
47591
49183
|
readJson(nb, dir, FILES.gazetteer)
|
|
47592
49184
|
]);
|
|
47593
49185
|
return validate({
|
|
@@ -47599,7 +49191,8 @@ function loadMapData() {
|
|
|
47599
49191
|
...rivers && { rivers },
|
|
47600
49192
|
...mountainRanges && { mountainRanges },
|
|
47601
49193
|
...naLand && { naLand },
|
|
47602
|
-
...naLakes && { naLakes }
|
|
49194
|
+
...naLakes && { naLakes },
|
|
49195
|
+
...waterBodies && { waterBodies }
|
|
47603
49196
|
});
|
|
47604
49197
|
})().catch((e) => {
|
|
47605
49198
|
cache = void 0;
|
|
@@ -47621,6 +49214,7 @@ var init_load_data = __esm({
|
|
|
47621
49214
|
mountainRanges: "mountain-ranges.json",
|
|
47622
49215
|
naLand: "na-land.json",
|
|
47623
49216
|
naLakes: "na-lakes.json",
|
|
49217
|
+
waterBodies: "water-bodies.json",
|
|
47624
49218
|
gazetteer: "gazetteer.json"
|
|
47625
49219
|
};
|
|
47626
49220
|
CANDIDATE_DIRS = [
|
|
@@ -49633,8 +51227,8 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
|
|
|
49633
51227
|
const lines = splitParticipantLabel(p.label, LABEL_MAX_CHARS);
|
|
49634
51228
|
if (lines.length === 0) continue;
|
|
49635
51229
|
const widest = Math.max(...lines.map((l) => l.length));
|
|
49636
|
-
const
|
|
49637
|
-
uniformBoxWidth = Math.max(uniformBoxWidth,
|
|
51230
|
+
const labelWidth2 = widest * LABEL_CHAR_WIDTH + 10;
|
|
51231
|
+
uniformBoxWidth = Math.max(uniformBoxWidth, labelWidth2);
|
|
49638
51232
|
}
|
|
49639
51233
|
uniformBoxWidth = Math.min(MAX_BOX_WIDTH, uniformBoxWidth);
|
|
49640
51234
|
const effectiveGap = Math.max(PARTICIPANT_GAP, uniformBoxWidth + 30);
|
|
@@ -52329,15 +53923,15 @@ function renderArcDiagram(container, parsed, palette, _isDark, onClickItem, expo
|
|
|
52329
53923
|
textColor,
|
|
52330
53924
|
onClickItem
|
|
52331
53925
|
);
|
|
52332
|
-
const
|
|
52333
|
-
for (const node of nodes)
|
|
53926
|
+
const neighbors2 = /* @__PURE__ */ new Map();
|
|
53927
|
+
for (const node of nodes) neighbors2.set(node, /* @__PURE__ */ new Set());
|
|
52334
53928
|
for (const link of links) {
|
|
52335
|
-
|
|
52336
|
-
|
|
53929
|
+
neighbors2.get(link.source).add(link.target);
|
|
53930
|
+
neighbors2.get(link.target).add(link.source);
|
|
52337
53931
|
}
|
|
52338
53932
|
const FADE_OPACITY3 = 0.1;
|
|
52339
53933
|
function handleMouseEnter(hovered) {
|
|
52340
|
-
const connected =
|
|
53934
|
+
const connected = neighbors2.get(hovered);
|
|
52341
53935
|
g.selectAll(".arc-link").each(function() {
|
|
52342
53936
|
const el = d3Selection23.select(this);
|
|
52343
53937
|
const src = el.attr("data-source");
|
|
@@ -54272,7 +55866,7 @@ function renderVenn(container, parsed, palette, _isDark, onClickItem, exportDims
|
|
|
54272
55866
|
8,
|
|
54273
55867
|
Math.floor(OVERLAP_WRAP_TARGET_W / OVERLAP_CH_W)
|
|
54274
55868
|
);
|
|
54275
|
-
function
|
|
55869
|
+
function wrapLabel3(text, maxChars) {
|
|
54276
55870
|
const words = text.split(/\s+/).filter(Boolean);
|
|
54277
55871
|
const lines = [];
|
|
54278
55872
|
let cur = "";
|
|
@@ -54318,7 +55912,7 @@ function renderVenn(container, parsed, palette, _isDark, onClickItem, exportDims
|
|
|
54318
55912
|
if (!ov.label) continue;
|
|
54319
55913
|
const idxs = ov.sets.map((s) => vennSets.findIndex((vs) => vs.name === s));
|
|
54320
55914
|
if (idxs.some((idx) => idx < 0)) continue;
|
|
54321
|
-
const lines =
|
|
55915
|
+
const lines = wrapLabel3(ov.label, MAX_WRAP_CHARS);
|
|
54322
55916
|
wrappedOverlapLabels.set(ov, lines);
|
|
54323
55917
|
const dir = predictOverlapDirRaw(idxs);
|
|
54324
55918
|
const longest = lines.reduce((m, l) => Math.max(m, l.length), 0);
|
|
@@ -55756,6 +57350,7 @@ async function renderForExport(content, theme, palette, viewState, options) {
|
|
|
55756
57350
|
const { parseMap: parseMap2 } = await Promise.resolve().then(() => (init_parser12(), parser_exports11));
|
|
55757
57351
|
const { resolveMap: resolveMap2 } = await Promise.resolve().then(() => (init_resolver2(), resolver_exports));
|
|
55758
57352
|
const { renderMapForExport: renderMapForExport2 } = await Promise.resolve().then(() => (init_renderer16(), renderer_exports16));
|
|
57353
|
+
const { mapExportDimensions: mapExportDimensions2 } = await Promise.resolve().then(() => (init_dimensions(), dimensions_exports));
|
|
55759
57354
|
const effectivePalette2 = await resolveExportPalette(theme, palette);
|
|
55760
57355
|
const mapParsed = parseMap2(content);
|
|
55761
57356
|
let mapData = options?.mapData;
|
|
@@ -55768,14 +57363,15 @@ async function renderForExport(content, theme, palette, viewState, options) {
|
|
|
55768
57363
|
}
|
|
55769
57364
|
}
|
|
55770
57365
|
const mapResolved = resolveMap2(mapParsed, mapData);
|
|
55771
|
-
const
|
|
57366
|
+
const dims2 = mapExportDimensions2(mapResolved, mapData, EXPORT_WIDTH);
|
|
57367
|
+
const container2 = createExportContainer(dims2.width, dims2.height);
|
|
55772
57368
|
renderMapForExport2(
|
|
55773
57369
|
container2,
|
|
55774
57370
|
mapResolved,
|
|
55775
57371
|
mapData,
|
|
55776
57372
|
effectivePalette2,
|
|
55777
57373
|
theme === "dark",
|
|
55778
|
-
|
|
57374
|
+
dims2
|
|
55779
57375
|
);
|
|
55780
57376
|
return finalizeSvgExport(container2, theme, effectivePalette2);
|
|
55781
57377
|
}
|
|
@@ -56639,7 +58235,8 @@ async function render(content, options) {
|
|
|
56639
58235
|
...options?.c4Container !== void 0 && {
|
|
56640
58236
|
c4Container: options.c4Container
|
|
56641
58237
|
},
|
|
56642
|
-
...options?.tagGroup !== void 0 && { tagGroup: options.tagGroup }
|
|
58238
|
+
...options?.tagGroup !== void 0 && { tagGroup: options.tagGroup },
|
|
58239
|
+
...options?.mapData !== void 0 && { mapData: options.mapData }
|
|
56643
58240
|
});
|
|
56644
58241
|
if (chartType === "map") {
|
|
56645
58242
|
try {
|
|
@@ -56650,7 +58247,7 @@ async function render(content, options) {
|
|
|
56650
58247
|
Promise.resolve().then(() => (init_load_data(), load_data_exports))
|
|
56651
58248
|
]
|
|
56652
58249
|
);
|
|
56653
|
-
const data = await loadMapData2();
|
|
58250
|
+
const data = options?.mapData ?? await loadMapData2();
|
|
56654
58251
|
diagnostics = [...resolveMap2(parseMap2(content), data).diagnostics];
|
|
56655
58252
|
} catch {
|
|
56656
58253
|
}
|