@diagrammo/dgmo 0.21.0 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -6
- package/dist/advanced.cjs +2521 -623
- package/dist/advanced.d.cts +917 -534
- package/dist/advanced.d.ts +917 -534
- package/dist/advanced.js +2516 -623
- package/dist/auto.cjs +2333 -608
- package/dist/auto.js +119 -119
- package/dist/auto.mjs +2335 -609
- package/dist/cli.cjs +168 -168
- package/dist/editor.cjs +13 -15
- package/dist/editor.js +13 -15
- package/dist/highlight.cjs +15 -12
- package/dist/highlight.js +15 -12
- package/dist/index.cjs +2317 -595
- package/dist/index.d.cts +4 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +2319 -596
- package/dist/internal.cjs +2521 -623
- package/dist/internal.d.cts +917 -534
- package/dist/internal.d.ts +917 -534
- package/dist/internal.js +2516 -623
- package/dist/map-data/PROVENANCE.json +1 -1
- package/dist/map-data/mountain-ranges.json +1 -0
- package/dist/map-data/water-bodies.json +1 -0
- package/docs/language-reference.md +44 -31
- package/gallery/fixtures/map-categorical-world.dgmo +16 -0
- package/gallery/fixtures/map-categorical.dgmo +0 -1
- package/gallery/fixtures/map-choropleth.dgmo +0 -1
- package/gallery/fixtures/map-coastline.dgmo +7 -0
- package/gallery/fixtures/map-colorize.dgmo +11 -0
- package/gallery/fixtures/map-direct-color.dgmo +9 -0
- package/gallery/fixtures/map-reference-world.dgmo +11 -0
- package/gallery/fixtures/map-region-scope.dgmo +0 -3
- package/gallery/fixtures/map-route.dgmo +0 -1
- package/package.json +1 -1
- package/src/advanced.ts +26 -1
- package/src/boxes-and-lines/renderer.ts +39 -12
- package/src/cli.ts +1 -1
- package/src/completion.ts +32 -24
- package/src/cycle/renderer.ts +14 -1
- package/src/d3.ts +23 -11
- package/src/editor/highlight-api.ts +4 -0
- package/src/editor/keywords.ts +13 -15
- package/src/infra/renderer.ts +35 -7
- package/src/map/colorize.ts +54 -0
- package/src/map/context-labels.ts +429 -0
- package/src/map/data/PROVENANCE.json +1 -1
- package/src/map/data/mountain-ranges.json +1 -0
- package/src/map/data/types.ts +34 -0
- package/src/map/data/water-bodies.json +1 -0
- package/src/map/dimensions.ts +117 -0
- package/src/map/geo-query.ts +295 -0
- package/src/map/geo.ts +305 -2
- package/src/map/invert.ts +111 -0
- package/src/map/layout.ts +1504 -335
- package/src/map/load-data.ts +16 -2
- package/src/map/parser.ts +57 -111
- package/src/map/renderer.ts +556 -13
- package/src/map/resolved-types.ts +24 -2
- package/src/map/resolver.ts +237 -67
- package/src/map/types.ts +39 -23
- package/src/mindmap/renderer.ts +10 -1
- package/src/palettes/atlas.ts +77 -0
- package/src/palettes/blueprint.ts +73 -0
- package/src/palettes/color-utils.ts +58 -1
- package/src/palettes/index.ts +12 -3
- package/src/palettes/slate.ts +73 -0
- package/src/palettes/tidewater.ts +73 -0
- package/src/render.ts +8 -1
- package/src/tech-radar/renderer.ts +3 -0
- package/src/tech-radar/types.ts +3 -0
- package/src/utils/d3-types.ts +5 -0
- package/src/utils/legend-layout.ts +21 -4
- package/src/utils/legend-types.ts +7 -0
- package/src/utils/reserved-key-registry.ts +3 -0
- package/src/palettes/bold.ts +0 -67
package/dist/advanced.js
CHANGED
|
@@ -371,18 +371,18 @@ function computeQuadrantPointLabels(points, chartBounds, obstacles, pointRadius,
|
|
|
371
371
|
const results = [];
|
|
372
372
|
for (let i = 0; i < points.length; i++) {
|
|
373
373
|
const pt = points[i];
|
|
374
|
-
const
|
|
374
|
+
const labelWidth2 = pt.label.length * fontSize * CHAR_WIDTH_RATIO + 8;
|
|
375
375
|
let best = null;
|
|
376
376
|
const directions = [
|
|
377
377
|
{
|
|
378
378
|
// Above
|
|
379
379
|
gen: (offset) => {
|
|
380
|
-
const lx = pt.cx -
|
|
380
|
+
const lx = pt.cx - labelWidth2 / 2;
|
|
381
381
|
const ly = pt.cy - offset - labelHeight;
|
|
382
|
-
if (ly < chartBounds.top || lx < chartBounds.left || lx +
|
|
382
|
+
if (ly < chartBounds.top || lx < chartBounds.left || lx + labelWidth2 > chartBounds.right)
|
|
383
383
|
return null;
|
|
384
384
|
return {
|
|
385
|
-
rect: { x: lx, y: ly, w:
|
|
385
|
+
rect: { x: lx, y: ly, w: labelWidth2, h: labelHeight },
|
|
386
386
|
textX: pt.cx,
|
|
387
387
|
textY: ly + labelHeight / 2,
|
|
388
388
|
anchor: "middle"
|
|
@@ -392,12 +392,12 @@ function computeQuadrantPointLabels(points, chartBounds, obstacles, pointRadius,
|
|
|
392
392
|
{
|
|
393
393
|
// Below
|
|
394
394
|
gen: (offset) => {
|
|
395
|
-
const lx = pt.cx -
|
|
395
|
+
const lx = pt.cx - labelWidth2 / 2;
|
|
396
396
|
const ly = pt.cy + offset;
|
|
397
|
-
if (ly + labelHeight > chartBounds.bottom || lx < chartBounds.left || lx +
|
|
397
|
+
if (ly + labelHeight > chartBounds.bottom || lx < chartBounds.left || lx + labelWidth2 > chartBounds.right)
|
|
398
398
|
return null;
|
|
399
399
|
return {
|
|
400
|
-
rect: { x: lx, y: ly, w:
|
|
400
|
+
rect: { x: lx, y: ly, w: labelWidth2, h: labelHeight },
|
|
401
401
|
textX: pt.cx,
|
|
402
402
|
textY: ly + labelHeight / 2,
|
|
403
403
|
anchor: "middle"
|
|
@@ -409,10 +409,10 @@ function computeQuadrantPointLabels(points, chartBounds, obstacles, pointRadius,
|
|
|
409
409
|
gen: (offset) => {
|
|
410
410
|
const lx = pt.cx + offset;
|
|
411
411
|
const ly = pt.cy - labelHeight / 2;
|
|
412
|
-
if (lx +
|
|
412
|
+
if (lx + labelWidth2 > chartBounds.right || ly < chartBounds.top || ly + labelHeight > chartBounds.bottom)
|
|
413
413
|
return null;
|
|
414
414
|
return {
|
|
415
|
-
rect: { x: lx, y: ly, w:
|
|
415
|
+
rect: { x: lx, y: ly, w: labelWidth2, h: labelHeight },
|
|
416
416
|
textX: lx,
|
|
417
417
|
textY: pt.cy,
|
|
418
418
|
anchor: "start"
|
|
@@ -422,13 +422,13 @@ function computeQuadrantPointLabels(points, chartBounds, obstacles, pointRadius,
|
|
|
422
422
|
{
|
|
423
423
|
// Left
|
|
424
424
|
gen: (offset) => {
|
|
425
|
-
const lx = pt.cx - offset -
|
|
425
|
+
const lx = pt.cx - offset - labelWidth2;
|
|
426
426
|
const ly = pt.cy - labelHeight / 2;
|
|
427
427
|
if (lx < chartBounds.left || ly < chartBounds.top || ly + labelHeight > chartBounds.bottom)
|
|
428
428
|
return null;
|
|
429
429
|
return {
|
|
430
|
-
rect: { x: lx, y: ly, w:
|
|
431
|
-
textX: lx +
|
|
430
|
+
rect: { x: lx, y: ly, w: labelWidth2, h: labelHeight },
|
|
431
|
+
textX: lx + labelWidth2,
|
|
432
432
|
textY: pt.cy,
|
|
433
433
|
anchor: "end"
|
|
434
434
|
};
|
|
@@ -478,10 +478,10 @@ function computeQuadrantPointLabels(points, chartBounds, obstacles, pointRadius,
|
|
|
478
478
|
}
|
|
479
479
|
}
|
|
480
480
|
if (!best) {
|
|
481
|
-
const lx = pt.cx -
|
|
481
|
+
const lx = pt.cx - labelWidth2 / 2;
|
|
482
482
|
const ly = pt.cy - minGap - labelHeight;
|
|
483
483
|
best = {
|
|
484
|
-
rect: { x: lx, y: ly, w:
|
|
484
|
+
rect: { x: lx, y: ly, w: labelWidth2, h: labelHeight },
|
|
485
485
|
textX: pt.cx,
|
|
486
486
|
textY: ly + labelHeight / 2,
|
|
487
487
|
anchor: "middle",
|
|
@@ -858,6 +858,9 @@ var init_reserved_key_registry = __esm({
|
|
|
858
858
|
"value",
|
|
859
859
|
"label",
|
|
860
860
|
"style"
|
|
861
|
+
// `surface:` was removed in the 2026-06-02 defaults-on review — it is no longer
|
|
862
|
+
// a recognized metadata key (the route/edge surface feature was cut; §24B.7).
|
|
863
|
+
// A stray `surface: water` is no longer captured as a reserved key.
|
|
861
864
|
]);
|
|
862
865
|
ORG_REGISTRY = staticRegistry([
|
|
863
866
|
"color",
|
|
@@ -1920,77 +1923,266 @@ function getSegmentColors(palette, count) {
|
|
|
1920
1923
|
(_, i) => hslToHex(Math.round((startHue + i * step) % 360), avgS, avgL)
|
|
1921
1924
|
);
|
|
1922
1925
|
}
|
|
1926
|
+
function politicalTints(palette, count, isDark) {
|
|
1927
|
+
if (count <= 0) return [];
|
|
1928
|
+
const base = isDark ? palette.surface : palette.bg;
|
|
1929
|
+
const c = palette.colors;
|
|
1930
|
+
const swatches = [
|
|
1931
|
+
.../* @__PURE__ */ new Set([
|
|
1932
|
+
c.green,
|
|
1933
|
+
c.yellow,
|
|
1934
|
+
c.orange,
|
|
1935
|
+
c.purple,
|
|
1936
|
+
c.red,
|
|
1937
|
+
c.teal,
|
|
1938
|
+
c.cyan,
|
|
1939
|
+
c.blue
|
|
1940
|
+
])
|
|
1941
|
+
];
|
|
1942
|
+
const bands = isDark ? POLITICAL_TINT_BANDS.dark : POLITICAL_TINT_BANDS.light;
|
|
1943
|
+
const out = [];
|
|
1944
|
+
for (const pct of bands) {
|
|
1945
|
+
if (out.length >= count) break;
|
|
1946
|
+
for (const s of swatches) out.push(mix(s, base, pct));
|
|
1947
|
+
}
|
|
1948
|
+
return out.slice(0, count);
|
|
1949
|
+
}
|
|
1950
|
+
var POLITICAL_TINT_BANDS;
|
|
1923
1951
|
var init_color_utils = __esm({
|
|
1924
1952
|
"src/palettes/color-utils.ts"() {
|
|
1925
1953
|
"use strict";
|
|
1954
|
+
POLITICAL_TINT_BANDS = {
|
|
1955
|
+
light: [32, 48, 64, 80],
|
|
1956
|
+
dark: [44, 58, 72, 86]
|
|
1957
|
+
};
|
|
1926
1958
|
}
|
|
1927
1959
|
});
|
|
1928
1960
|
|
|
1929
|
-
// src/palettes/
|
|
1930
|
-
var
|
|
1931
|
-
var
|
|
1932
|
-
"src/palettes/
|
|
1961
|
+
// src/palettes/atlas.ts
|
|
1962
|
+
var atlasPalette;
|
|
1963
|
+
var init_atlas = __esm({
|
|
1964
|
+
"src/palettes/atlas.ts"() {
|
|
1933
1965
|
"use strict";
|
|
1934
1966
|
init_registry();
|
|
1935
|
-
|
|
1936
|
-
id: "
|
|
1937
|
-
name: "
|
|
1967
|
+
atlasPalette = {
|
|
1968
|
+
id: "atlas",
|
|
1969
|
+
name: "Atlas",
|
|
1938
1970
|
light: {
|
|
1939
|
-
bg: "#
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1971
|
+
bg: "#f3ead3",
|
|
1972
|
+
// warm manila / parchment
|
|
1973
|
+
surface: "#ece0c0",
|
|
1974
|
+
// deeper paper (cards, panels)
|
|
1975
|
+
overlay: "#e8dab8",
|
|
1976
|
+
// popovers, dropdowns
|
|
1977
|
+
border: "#bcaa86",
|
|
1978
|
+
// muted sepia rule line
|
|
1979
|
+
text: "#463a26",
|
|
1980
|
+
// aged sepia-brown ink
|
|
1981
|
+
textMuted: "#7a6a4f",
|
|
1982
|
+
// faded annotation ink
|
|
1983
|
+
textOnFillLight: "#f7f1de",
|
|
1984
|
+
// parchment (light text on dark fills)
|
|
1985
|
+
textOnFillDark: "#3a2e1c",
|
|
1986
|
+
// deep ink (dark text on light fills)
|
|
1987
|
+
primary: "#5b7a99",
|
|
1988
|
+
// pull-down map ocean (steel-blue)
|
|
1989
|
+
secondary: "#7e9a6f",
|
|
1990
|
+
// lowland sage / celadon
|
|
1991
|
+
accent: "#b07f7c",
|
|
1992
|
+
// dusty rose
|
|
1993
|
+
destructive: "#b25a45",
|
|
1994
|
+
// brick / terracotta
|
|
1951
1995
|
colors: {
|
|
1952
|
-
red: "#
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1996
|
+
red: "#bf6a52",
|
|
1997
|
+
// terracotta brick
|
|
1998
|
+
orange: "#cf9a5c",
|
|
1999
|
+
// map tan / ochre
|
|
2000
|
+
yellow: "#cdb35e",
|
|
2001
|
+
// straw / muted lemon
|
|
2002
|
+
green: "#7e9a6f",
|
|
2003
|
+
// sage / celadon lowland
|
|
2004
|
+
blue: "#5b7a99",
|
|
2005
|
+
// steel-blue ocean
|
|
2006
|
+
purple: "#9a7fa6",
|
|
2007
|
+
// dusty lilac / mauve
|
|
2008
|
+
teal: "#6fa094",
|
|
2009
|
+
// muted seafoam
|
|
2010
|
+
cyan: "#79a7b5",
|
|
2011
|
+
// shallow-water blue
|
|
2012
|
+
gray: "#8a7d68",
|
|
2013
|
+
// warm taupe
|
|
2014
|
+
black: "#463a26",
|
|
2015
|
+
// ink
|
|
2016
|
+
white: "#ece0c0"
|
|
2017
|
+
// paper
|
|
1963
2018
|
}
|
|
1964
2019
|
},
|
|
1965
2020
|
dark: {
|
|
1966
|
-
bg: "#
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
2021
|
+
bg: "#1e2a33",
|
|
2022
|
+
// deep map ocean (night globe)
|
|
2023
|
+
surface: "#27353f",
|
|
2024
|
+
// raised ocean
|
|
2025
|
+
overlay: "#2e3d48",
|
|
2026
|
+
// popovers, dropdowns
|
|
2027
|
+
border: "#3d4f5c",
|
|
2028
|
+
// depth-contour line
|
|
2029
|
+
text: "#e8dcc0",
|
|
2030
|
+
// parchment ink, inverted
|
|
2031
|
+
textMuted: "#a89a7d",
|
|
2032
|
+
// faded label
|
|
2033
|
+
textOnFillLight: "#f7f1de",
|
|
2034
|
+
// parchment
|
|
2035
|
+
textOnFillDark: "#1a242c",
|
|
2036
|
+
// deep ocean ink
|
|
2037
|
+
primary: "#7ba0bf",
|
|
2038
|
+
// brighter ocean
|
|
2039
|
+
secondary: "#9bb588",
|
|
2040
|
+
// sage, lifted
|
|
2041
|
+
accent: "#cf9a96",
|
|
2042
|
+
// dusty rose, lifted
|
|
2043
|
+
destructive: "#c9745c",
|
|
2044
|
+
// brick, lifted
|
|
2045
|
+
colors: {
|
|
2046
|
+
red: "#cf7a60",
|
|
2047
|
+
// terracotta
|
|
2048
|
+
orange: "#d9a96a",
|
|
2049
|
+
// tan / ochre
|
|
2050
|
+
yellow: "#d8c074",
|
|
2051
|
+
// straw
|
|
2052
|
+
green: "#9bb588",
|
|
2053
|
+
// sage lowland
|
|
2054
|
+
blue: "#7ba0bf",
|
|
2055
|
+
// ocean
|
|
2056
|
+
purple: "#b59ac0",
|
|
2057
|
+
// lilac / mauve
|
|
2058
|
+
teal: "#85b3a6",
|
|
2059
|
+
// seafoam
|
|
2060
|
+
cyan: "#92bccb",
|
|
2061
|
+
// shallow-water blue
|
|
2062
|
+
gray: "#9a8d76",
|
|
2063
|
+
// warm taupe
|
|
2064
|
+
black: "#27353f",
|
|
2065
|
+
// raised ocean
|
|
2066
|
+
white: "#e8dcc0"
|
|
2067
|
+
// parchment
|
|
2068
|
+
}
|
|
2069
|
+
}
|
|
2070
|
+
};
|
|
2071
|
+
registerPalette(atlasPalette);
|
|
2072
|
+
}
|
|
2073
|
+
});
|
|
2074
|
+
|
|
2075
|
+
// src/palettes/blueprint.ts
|
|
2076
|
+
var blueprintPalette;
|
|
2077
|
+
var init_blueprint = __esm({
|
|
2078
|
+
"src/palettes/blueprint.ts"() {
|
|
2079
|
+
"use strict";
|
|
2080
|
+
init_registry();
|
|
2081
|
+
blueprintPalette = {
|
|
2082
|
+
id: "blueprint",
|
|
2083
|
+
name: "Blueprint",
|
|
2084
|
+
light: {
|
|
2085
|
+
bg: "#f4f8fb",
|
|
2086
|
+
// pale drafting white (faint cyan)
|
|
2087
|
+
surface: "#e6eef4",
|
|
2088
|
+
// drafting panel
|
|
2089
|
+
overlay: "#dde9f1",
|
|
2090
|
+
// popovers, dropdowns
|
|
2091
|
+
border: "#aac3d6",
|
|
2092
|
+
// pale blue grid line
|
|
2093
|
+
text: "#123a5e",
|
|
2094
|
+
// blueprint navy ink
|
|
2095
|
+
textMuted: "#4f7390",
|
|
2096
|
+
// faint draft note
|
|
2097
|
+
textOnFillLight: "#f4f8fb",
|
|
2098
|
+
// drafting white
|
|
2099
|
+
textOnFillDark: "#0c2f4d",
|
|
2100
|
+
// deep blueprint navy
|
|
2101
|
+
primary: "#1f5e8c",
|
|
2102
|
+
// blueprint blue
|
|
2103
|
+
secondary: "#5b7d96",
|
|
2104
|
+
// steel
|
|
2105
|
+
accent: "#b08a3e",
|
|
2106
|
+
// draftsman's ochre highlight
|
|
2107
|
+
destructive: "#c0504d",
|
|
2108
|
+
// correction red
|
|
1978
2109
|
colors: {
|
|
1979
|
-
red: "#
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
2110
|
+
red: "#c25a4e",
|
|
2111
|
+
// correction red
|
|
2112
|
+
orange: "#c2823e",
|
|
2113
|
+
// ochre
|
|
2114
|
+
yellow: "#c2a843",
|
|
2115
|
+
// pencil gold
|
|
2116
|
+
green: "#4f8a6b",
|
|
2117
|
+
// drafting green
|
|
2118
|
+
blue: "#1f5e8c",
|
|
2119
|
+
// blueprint blue
|
|
2120
|
+
purple: "#6f5e96",
|
|
2121
|
+
// indigo pencil
|
|
2122
|
+
teal: "#3a8a8a",
|
|
2123
|
+
// teal
|
|
2124
|
+
cyan: "#3f8fb5",
|
|
2125
|
+
// cyan
|
|
2126
|
+
gray: "#7e8e98",
|
|
2127
|
+
// graphite
|
|
2128
|
+
black: "#123a5e",
|
|
2129
|
+
// navy ink
|
|
2130
|
+
white: "#e6eef4"
|
|
2131
|
+
// panel
|
|
2132
|
+
}
|
|
2133
|
+
},
|
|
2134
|
+
dark: {
|
|
2135
|
+
bg: "#103a5e",
|
|
2136
|
+
// deep blueprint blue (cyanotype ground)
|
|
2137
|
+
surface: "#16466e",
|
|
2138
|
+
// raised sheet
|
|
2139
|
+
overlay: "#1c5180",
|
|
2140
|
+
// popovers, dropdowns
|
|
2141
|
+
border: "#3a6f96",
|
|
2142
|
+
// grid line
|
|
2143
|
+
text: "#eaf2f8",
|
|
2144
|
+
// chalk white
|
|
2145
|
+
textMuted: "#9fc0d6",
|
|
2146
|
+
// faint chalk note
|
|
2147
|
+
textOnFillLight: "#eaf2f8",
|
|
2148
|
+
// chalk white
|
|
2149
|
+
textOnFillDark: "#0c2f4d",
|
|
2150
|
+
// deep blueprint navy
|
|
2151
|
+
primary: "#7fb8d8",
|
|
2152
|
+
// chalk cyan
|
|
2153
|
+
secondary: "#9fb8c8",
|
|
2154
|
+
// pale steel
|
|
2155
|
+
accent: "#d8c27a",
|
|
2156
|
+
// chalk amber
|
|
2157
|
+
destructive: "#e08a7a",
|
|
2158
|
+
// chalk correction red
|
|
2159
|
+
colors: {
|
|
2160
|
+
red: "#e0907e",
|
|
2161
|
+
// chalk red
|
|
2162
|
+
orange: "#e0ab78",
|
|
2163
|
+
// chalk amber
|
|
2164
|
+
yellow: "#e3d089",
|
|
2165
|
+
// chalk gold
|
|
2166
|
+
green: "#93c79e",
|
|
2167
|
+
// chalk green
|
|
2168
|
+
blue: "#8ec3e0",
|
|
2169
|
+
// chalk cyan-blue
|
|
2170
|
+
purple: "#b6a6d8",
|
|
2171
|
+
// chalk indigo
|
|
2172
|
+
teal: "#84c7c2",
|
|
2173
|
+
// chalk teal
|
|
2174
|
+
cyan: "#9fd6e0",
|
|
2175
|
+
// chalk cyan
|
|
2176
|
+
gray: "#aebecb",
|
|
2177
|
+
// chalk graphite
|
|
2178
|
+
black: "#16466e",
|
|
2179
|
+
// raised sheet
|
|
2180
|
+
white: "#eaf2f8"
|
|
2181
|
+
// chalk white
|
|
1990
2182
|
}
|
|
1991
2183
|
}
|
|
1992
2184
|
};
|
|
1993
|
-
registerPalette(
|
|
2185
|
+
registerPalette(blueprintPalette);
|
|
1994
2186
|
}
|
|
1995
2187
|
});
|
|
1996
2188
|
|
|
@@ -2487,6 +2679,120 @@ var init_rose_pine = __esm({
|
|
|
2487
2679
|
}
|
|
2488
2680
|
});
|
|
2489
2681
|
|
|
2682
|
+
// src/palettes/slate.ts
|
|
2683
|
+
var slatePalette;
|
|
2684
|
+
var init_slate = __esm({
|
|
2685
|
+
"src/palettes/slate.ts"() {
|
|
2686
|
+
"use strict";
|
|
2687
|
+
init_registry();
|
|
2688
|
+
slatePalette = {
|
|
2689
|
+
id: "slate",
|
|
2690
|
+
name: "Slate",
|
|
2691
|
+
light: {
|
|
2692
|
+
bg: "#ffffff",
|
|
2693
|
+
// clean slide white
|
|
2694
|
+
surface: "#f3f5f8",
|
|
2695
|
+
// light cool-gray panel
|
|
2696
|
+
overlay: "#eaeef3",
|
|
2697
|
+
// popovers, dropdowns
|
|
2698
|
+
border: "#d4dae1",
|
|
2699
|
+
// hairline rule
|
|
2700
|
+
text: "#1f2933",
|
|
2701
|
+
// near-black slate (softer than pure black)
|
|
2702
|
+
textMuted: "#5b6672",
|
|
2703
|
+
// secondary label
|
|
2704
|
+
textOnFillLight: "#ffffff",
|
|
2705
|
+
// light text on dark fills
|
|
2706
|
+
textOnFillDark: "#1f2933",
|
|
2707
|
+
// dark text on light fills
|
|
2708
|
+
primary: "#3b6ea5",
|
|
2709
|
+
// confident corporate blue
|
|
2710
|
+
secondary: "#5b6672",
|
|
2711
|
+
// slate gray
|
|
2712
|
+
accent: "#3a9188",
|
|
2713
|
+
// muted teal accent
|
|
2714
|
+
destructive: "#c0504d",
|
|
2715
|
+
// brick red
|
|
2716
|
+
colors: {
|
|
2717
|
+
red: "#c0504d",
|
|
2718
|
+
// brick
|
|
2719
|
+
orange: "#cc7a33",
|
|
2720
|
+
// muted amber
|
|
2721
|
+
yellow: "#c9a227",
|
|
2722
|
+
// gold (not neon)
|
|
2723
|
+
green: "#5b9357",
|
|
2724
|
+
// forest / sage
|
|
2725
|
+
blue: "#3b6ea5",
|
|
2726
|
+
// corporate blue
|
|
2727
|
+
purple: "#7d5ba6",
|
|
2728
|
+
// muted violet
|
|
2729
|
+
teal: "#3a9188",
|
|
2730
|
+
// teal
|
|
2731
|
+
cyan: "#4f96c4",
|
|
2732
|
+
// steel cyan
|
|
2733
|
+
gray: "#7e8a97",
|
|
2734
|
+
// cool gray
|
|
2735
|
+
black: "#1f2933",
|
|
2736
|
+
// slate ink
|
|
2737
|
+
white: "#f3f5f8"
|
|
2738
|
+
// panel
|
|
2739
|
+
}
|
|
2740
|
+
},
|
|
2741
|
+
dark: {
|
|
2742
|
+
bg: "#161b22",
|
|
2743
|
+
// deep slate (keynote dark)
|
|
2744
|
+
surface: "#202833",
|
|
2745
|
+
// raised panel
|
|
2746
|
+
overlay: "#29323e",
|
|
2747
|
+
// popovers, dropdowns
|
|
2748
|
+
border: "#38424f",
|
|
2749
|
+
// divider
|
|
2750
|
+
text: "#e6eaef",
|
|
2751
|
+
// off-white
|
|
2752
|
+
textMuted: "#9aa5b1",
|
|
2753
|
+
// secondary label
|
|
2754
|
+
textOnFillLight: "#ffffff",
|
|
2755
|
+
// light text on dark fills
|
|
2756
|
+
textOnFillDark: "#161b22",
|
|
2757
|
+
// dark text on light fills
|
|
2758
|
+
primary: "#5b9bd5",
|
|
2759
|
+
// lifted corporate blue
|
|
2760
|
+
secondary: "#8593a3",
|
|
2761
|
+
// slate gray, lifted
|
|
2762
|
+
accent: "#45b3a3",
|
|
2763
|
+
// teal, lifted
|
|
2764
|
+
destructive: "#e07b6e",
|
|
2765
|
+
// brick, lifted
|
|
2766
|
+
colors: {
|
|
2767
|
+
red: "#e07b6e",
|
|
2768
|
+
// brick
|
|
2769
|
+
orange: "#e0975a",
|
|
2770
|
+
// amber
|
|
2771
|
+
yellow: "#d9bd5a",
|
|
2772
|
+
// gold
|
|
2773
|
+
green: "#74b56e",
|
|
2774
|
+
// forest / sage
|
|
2775
|
+
blue: "#5b9bd5",
|
|
2776
|
+
// corporate blue
|
|
2777
|
+
purple: "#a585c9",
|
|
2778
|
+
// violet
|
|
2779
|
+
teal: "#45b3a3",
|
|
2780
|
+
// teal
|
|
2781
|
+
cyan: "#62b0d9",
|
|
2782
|
+
// steel cyan
|
|
2783
|
+
gray: "#95a1ae",
|
|
2784
|
+
// cool gray
|
|
2785
|
+
black: "#202833",
|
|
2786
|
+
// raised panel
|
|
2787
|
+
white: "#e6eaef"
|
|
2788
|
+
// off-white
|
|
2789
|
+
}
|
|
2790
|
+
}
|
|
2791
|
+
};
|
|
2792
|
+
registerPalette(slatePalette);
|
|
2793
|
+
}
|
|
2794
|
+
});
|
|
2795
|
+
|
|
2490
2796
|
// src/palettes/solarized.ts
|
|
2491
2797
|
var solarizedPalette;
|
|
2492
2798
|
var init_solarized = __esm({
|
|
@@ -2582,6 +2888,120 @@ var init_solarized = __esm({
|
|
|
2582
2888
|
}
|
|
2583
2889
|
});
|
|
2584
2890
|
|
|
2891
|
+
// src/palettes/tidewater.ts
|
|
2892
|
+
var tidewaterPalette;
|
|
2893
|
+
var init_tidewater = __esm({
|
|
2894
|
+
"src/palettes/tidewater.ts"() {
|
|
2895
|
+
"use strict";
|
|
2896
|
+
init_registry();
|
|
2897
|
+
tidewaterPalette = {
|
|
2898
|
+
id: "tidewater",
|
|
2899
|
+
name: "Tidewater",
|
|
2900
|
+
light: {
|
|
2901
|
+
bg: "#eceff0",
|
|
2902
|
+
// weathered sea-mist paper
|
|
2903
|
+
surface: "#e0e4e3",
|
|
2904
|
+
// worn deck panel
|
|
2905
|
+
overlay: "#dadfdf",
|
|
2906
|
+
// popovers, dropdowns
|
|
2907
|
+
border: "#a9b2b3",
|
|
2908
|
+
// muted slate rule
|
|
2909
|
+
text: "#18313f",
|
|
2910
|
+
// ship's-log navy ink
|
|
2911
|
+
textMuted: "#51636b",
|
|
2912
|
+
// faded log entry
|
|
2913
|
+
textOnFillLight: "#f3f5f3",
|
|
2914
|
+
// weathered white
|
|
2915
|
+
textOnFillDark: "#162c38",
|
|
2916
|
+
// deep navy
|
|
2917
|
+
primary: "#1f4e6b",
|
|
2918
|
+
// deep-sea navy
|
|
2919
|
+
secondary: "#b08a4f",
|
|
2920
|
+
// rope / manila tan
|
|
2921
|
+
accent: "#c69a3e",
|
|
2922
|
+
// brass
|
|
2923
|
+
destructive: "#c1433a",
|
|
2924
|
+
// signal-flag red
|
|
2925
|
+
colors: {
|
|
2926
|
+
red: "#c1433a",
|
|
2927
|
+
// signal-flag red
|
|
2928
|
+
orange: "#cc7a38",
|
|
2929
|
+
// weathered amber
|
|
2930
|
+
yellow: "#d6bf5a",
|
|
2931
|
+
// brass gold
|
|
2932
|
+
green: "#4f8a6b",
|
|
2933
|
+
// sea-glass green
|
|
2934
|
+
blue: "#1f4e6b",
|
|
2935
|
+
// deep-sea navy
|
|
2936
|
+
purple: "#6a5a8c",
|
|
2937
|
+
// twilight harbor
|
|
2938
|
+
teal: "#3d8c8c",
|
|
2939
|
+
// sea-glass teal
|
|
2940
|
+
cyan: "#4f9bb5",
|
|
2941
|
+
// shallow water
|
|
2942
|
+
gray: "#8a8d86",
|
|
2943
|
+
// driftwood gray
|
|
2944
|
+
black: "#18313f",
|
|
2945
|
+
// navy ink
|
|
2946
|
+
white: "#e0e4e3"
|
|
2947
|
+
// deck panel
|
|
2948
|
+
}
|
|
2949
|
+
},
|
|
2950
|
+
dark: {
|
|
2951
|
+
bg: "#0f2230",
|
|
2952
|
+
// night-harbor deep sea
|
|
2953
|
+
surface: "#16303f",
|
|
2954
|
+
// raised hull
|
|
2955
|
+
overlay: "#1d3a4a",
|
|
2956
|
+
// popovers, dropdowns
|
|
2957
|
+
border: "#2c4856",
|
|
2958
|
+
// rigging line
|
|
2959
|
+
text: "#e6ebe8",
|
|
2960
|
+
// weathered white
|
|
2961
|
+
textMuted: "#9aaab0",
|
|
2962
|
+
// faded label
|
|
2963
|
+
textOnFillLight: "#f3f5f3",
|
|
2964
|
+
// weathered white
|
|
2965
|
+
textOnFillDark: "#0f2230",
|
|
2966
|
+
// deep sea
|
|
2967
|
+
primary: "#4f9bc4",
|
|
2968
|
+
// lifted sea blue
|
|
2969
|
+
secondary: "#c9a46a",
|
|
2970
|
+
// rope tan, lifted
|
|
2971
|
+
accent: "#d9b25a",
|
|
2972
|
+
// brass, lifted
|
|
2973
|
+
destructive: "#e06a5e",
|
|
2974
|
+
// signal red, lifted
|
|
2975
|
+
colors: {
|
|
2976
|
+
red: "#e06a5e",
|
|
2977
|
+
// signal-flag red
|
|
2978
|
+
orange: "#df9a52",
|
|
2979
|
+
// amber
|
|
2980
|
+
yellow: "#e0c662",
|
|
2981
|
+
// brass gold
|
|
2982
|
+
green: "#6fb58c",
|
|
2983
|
+
// sea-glass green
|
|
2984
|
+
blue: "#4f9bc4",
|
|
2985
|
+
// sea blue
|
|
2986
|
+
purple: "#9486bf",
|
|
2987
|
+
// twilight harbor
|
|
2988
|
+
teal: "#5cb0ac",
|
|
2989
|
+
// sea-glass teal
|
|
2990
|
+
cyan: "#62b4cf",
|
|
2991
|
+
// shallow water
|
|
2992
|
+
gray: "#9aa39c",
|
|
2993
|
+
// driftwood gray
|
|
2994
|
+
black: "#16303f",
|
|
2995
|
+
// raised hull
|
|
2996
|
+
white: "#e6ebe8"
|
|
2997
|
+
// weathered white
|
|
2998
|
+
}
|
|
2999
|
+
}
|
|
3000
|
+
};
|
|
3001
|
+
registerPalette(tidewaterPalette);
|
|
3002
|
+
}
|
|
3003
|
+
});
|
|
3004
|
+
|
|
2585
3005
|
// src/palettes/tokyo-night.ts
|
|
2586
3006
|
var tokyoNightPalette;
|
|
2587
3007
|
var init_tokyo_night = __esm({
|
|
@@ -2857,7 +3277,8 @@ var init_monokai = __esm({
|
|
|
2857
3277
|
// src/palettes/index.ts
|
|
2858
3278
|
var palettes_exports = {};
|
|
2859
3279
|
__export(palettes_exports, {
|
|
2860
|
-
|
|
3280
|
+
atlasPalette: () => atlasPalette,
|
|
3281
|
+
blueprintPalette: () => blueprintPalette,
|
|
2861
3282
|
catppuccinPalette: () => catppuccinPalette,
|
|
2862
3283
|
contrastText: () => contrastText,
|
|
2863
3284
|
draculaPalette: () => draculaPalette,
|
|
@@ -2878,7 +3299,9 @@ __export(palettes_exports, {
|
|
|
2878
3299
|
rosePinePalette: () => rosePinePalette,
|
|
2879
3300
|
shade: () => shade,
|
|
2880
3301
|
shapeFill: () => shapeFill,
|
|
3302
|
+
slatePalette: () => slatePalette,
|
|
2881
3303
|
solarizedPalette: () => solarizedPalette,
|
|
3304
|
+
tidewaterPalette: () => tidewaterPalette,
|
|
2882
3305
|
tint: () => tint,
|
|
2883
3306
|
tokyoNightPalette: () => tokyoNightPalette
|
|
2884
3307
|
});
|
|
@@ -2888,17 +3311,21 @@ var init_palettes = __esm({
|
|
|
2888
3311
|
"use strict";
|
|
2889
3312
|
init_registry();
|
|
2890
3313
|
init_color_utils();
|
|
2891
|
-
|
|
3314
|
+
init_atlas();
|
|
3315
|
+
init_blueprint();
|
|
2892
3316
|
init_catppuccin();
|
|
2893
3317
|
init_gruvbox();
|
|
2894
3318
|
init_nord();
|
|
2895
3319
|
init_one_dark();
|
|
2896
3320
|
init_rose_pine();
|
|
3321
|
+
init_slate();
|
|
2897
3322
|
init_solarized();
|
|
3323
|
+
init_tidewater();
|
|
2898
3324
|
init_tokyo_night();
|
|
2899
3325
|
init_dracula();
|
|
2900
3326
|
init_monokai();
|
|
2901
|
-
|
|
3327
|
+
init_atlas();
|
|
3328
|
+
init_blueprint();
|
|
2902
3329
|
init_catppuccin();
|
|
2903
3330
|
init_dracula();
|
|
2904
3331
|
init_gruvbox();
|
|
@@ -2906,9 +3333,15 @@ var init_palettes = __esm({
|
|
|
2906
3333
|
init_nord();
|
|
2907
3334
|
init_one_dark();
|
|
2908
3335
|
init_rose_pine();
|
|
3336
|
+
init_slate();
|
|
2909
3337
|
init_solarized();
|
|
3338
|
+
init_tidewater();
|
|
2910
3339
|
init_tokyo_night();
|
|
2911
3340
|
palettes = {
|
|
3341
|
+
atlas: atlasPalette,
|
|
3342
|
+
blueprint: blueprintPalette,
|
|
3343
|
+
slate: slatePalette,
|
|
3344
|
+
tidewater: tidewaterPalette,
|
|
2912
3345
|
nord: nordPalette,
|
|
2913
3346
|
catppuccin: catppuccinPalette,
|
|
2914
3347
|
solarized: solarizedPalette,
|
|
@@ -2917,8 +3350,7 @@ var init_palettes = __esm({
|
|
|
2917
3350
|
oneDark: oneDarkPalette,
|
|
2918
3351
|
rosePine: rosePinePalette,
|
|
2919
3352
|
dracula: draculaPalette,
|
|
2920
|
-
monokai: monokaiPalette
|
|
2921
|
-
bold: boldPalette
|
|
3353
|
+
monokai: monokaiPalette
|
|
2922
3354
|
};
|
|
2923
3355
|
}
|
|
2924
3356
|
});
|
|
@@ -3428,6 +3860,9 @@ function controlsGroupCapsuleWidth(toggles) {
|
|
|
3428
3860
|
}
|
|
3429
3861
|
return w;
|
|
3430
3862
|
}
|
|
3863
|
+
function isAppHostedControls(config, isExport) {
|
|
3864
|
+
return !isExport && config.controlsHost === "app" && !!config.controlsGroup && config.controlsGroup.toggles.length > 0;
|
|
3865
|
+
}
|
|
3431
3866
|
function buildControlsGroupLayout(config, state) {
|
|
3432
3867
|
const cg = config.controlsGroup;
|
|
3433
3868
|
if (!cg || cg.toggles.length === 0) return void 0;
|
|
@@ -3481,6 +3916,7 @@ function buildControlsGroupLayout(config, state) {
|
|
|
3481
3916
|
function computeLegendLayout(config, state, containerWidth) {
|
|
3482
3917
|
const { groups, controls: configControls, mode } = config;
|
|
3483
3918
|
const isExport = mode === "export";
|
|
3919
|
+
const gated = isAppHostedControls(config, isExport);
|
|
3484
3920
|
const activeGroupName = state.activeGroup?.toLowerCase() ?? null;
|
|
3485
3921
|
if (isExport && !activeGroupName) {
|
|
3486
3922
|
return {
|
|
@@ -3491,7 +3927,7 @@ function computeLegendLayout(config, state, containerWidth) {
|
|
|
3491
3927
|
pills: []
|
|
3492
3928
|
};
|
|
3493
3929
|
}
|
|
3494
|
-
const controlsGroupLayout = isExport ? void 0 : buildControlsGroupLayout(config, state);
|
|
3930
|
+
const controlsGroupLayout = isExport || gated ? void 0 : buildControlsGroupLayout(config, state);
|
|
3495
3931
|
const visibleGroups = config.showEmptyGroups ? groups : groups.filter((g) => g.entries.length > 0 || !!g.gradient);
|
|
3496
3932
|
if (visibleGroups.length === 0 && (!configControls || configControls.length === 0) && !controlsGroupLayout) {
|
|
3497
3933
|
return {
|
|
@@ -8345,8 +8781,8 @@ function computeScatterLabelGraphics(points, chartBounds, fontSize, symbolSize,
|
|
|
8345
8781
|
const pt = points[i];
|
|
8346
8782
|
const ptSize = pt.size ?? symbolSize;
|
|
8347
8783
|
const minGap = ptSize / 2 + 4;
|
|
8348
|
-
const
|
|
8349
|
-
const labelX = pt.px -
|
|
8784
|
+
const labelWidth2 = pt.name.length * fontSize * 0.6 + 8;
|
|
8785
|
+
const labelX = pt.px - labelWidth2 / 2;
|
|
8350
8786
|
let bestLabelY = 0;
|
|
8351
8787
|
let bestOffset = Infinity;
|
|
8352
8788
|
let placed = false;
|
|
@@ -8358,7 +8794,7 @@ function computeScatterLabelGraphics(points, chartBounds, fontSize, symbolSize,
|
|
|
8358
8794
|
const candidate = {
|
|
8359
8795
|
x: labelX,
|
|
8360
8796
|
y: labelY,
|
|
8361
|
-
w:
|
|
8797
|
+
w: labelWidth2,
|
|
8362
8798
|
h: labelHeight
|
|
8363
8799
|
};
|
|
8364
8800
|
let collision = false;
|
|
@@ -8400,7 +8836,7 @@ function computeScatterLabelGraphics(points, chartBounds, fontSize, symbolSize,
|
|
|
8400
8836
|
const labelRect = {
|
|
8401
8837
|
x: labelX,
|
|
8402
8838
|
y: bestLabelY,
|
|
8403
|
-
w:
|
|
8839
|
+
w: labelWidth2,
|
|
8404
8840
|
h: labelHeight
|
|
8405
8841
|
};
|
|
8406
8842
|
placedLabels.push(labelRect);
|
|
@@ -8436,7 +8872,7 @@ function computeScatterLabelGraphics(points, chartBounds, fontSize, symbolSize,
|
|
|
8436
8872
|
shape: {
|
|
8437
8873
|
x: labelX - bgPad,
|
|
8438
8874
|
y: bestLabelY - bgPad,
|
|
8439
|
-
width:
|
|
8875
|
+
width: labelWidth2 + bgPad * 2,
|
|
8440
8876
|
height: labelHeight + bgPad * 2
|
|
8441
8877
|
},
|
|
8442
8878
|
style: { fill: bg },
|
|
@@ -15872,10 +16308,6 @@ function parseMap(content) {
|
|
|
15872
16308
|
handleTag(trimmed, lineNumber);
|
|
15873
16309
|
continue;
|
|
15874
16310
|
}
|
|
15875
|
-
if ((firstWord === "muted" || firstWord === "natural") && trimmed === firstWord) {
|
|
15876
|
-
handleDirective(firstWord, "", lineNumber);
|
|
15877
|
-
continue;
|
|
15878
|
-
}
|
|
15879
16311
|
if (DIRECTIVE_SET.has(firstWord) && !trimmed.slice(firstWord.length).trimStart().startsWith(":")) {
|
|
15880
16312
|
handleDirective(
|
|
15881
16313
|
firstWord,
|
|
@@ -15922,28 +16354,13 @@ function parseMap(content) {
|
|
|
15922
16354
|
pushWarning(line12, `Duplicate directive "${key}" \u2014 last value wins.`);
|
|
15923
16355
|
};
|
|
15924
16356
|
switch (key) {
|
|
15925
|
-
case "region":
|
|
15926
|
-
dup(d.region);
|
|
15927
|
-
d.region = value;
|
|
15928
|
-
break;
|
|
15929
|
-
case "projection":
|
|
15930
|
-
dup(d.projection);
|
|
15931
|
-
if (value && ![
|
|
15932
|
-
"equirectangular",
|
|
15933
|
-
"natural-earth",
|
|
15934
|
-
"albers-usa",
|
|
15935
|
-
"mercator"
|
|
15936
|
-
].includes(value))
|
|
15937
|
-
pushWarning(
|
|
15938
|
-
line12,
|
|
15939
|
-
`Unknown projection "${value}" (expected equirectangular | natural-earth | albers-usa | mercator).`
|
|
15940
|
-
);
|
|
15941
|
-
d.projection = value;
|
|
15942
|
-
break;
|
|
15943
|
-
case "region-metric":
|
|
16357
|
+
case "region-metric": {
|
|
15944
16358
|
dup(d.regionMetric);
|
|
15945
|
-
|
|
16359
|
+
const { label: rmLabel, colorName: rmColor } = peelTrailingColorName(value);
|
|
16360
|
+
d.regionMetric = rmLabel;
|
|
16361
|
+
if (rmColor) d.regionMetricColor = rmColor;
|
|
15946
16362
|
break;
|
|
16363
|
+
}
|
|
15947
16364
|
case "poi-metric":
|
|
15948
16365
|
dup(d.poiMetric);
|
|
15949
16366
|
d.poiMetric = value;
|
|
@@ -15952,85 +16369,43 @@ function parseMap(content) {
|
|
|
15952
16369
|
dup(d.flowMetric);
|
|
15953
16370
|
d.flowMetric = value;
|
|
15954
16371
|
break;
|
|
15955
|
-
case "
|
|
15956
|
-
dup(d.
|
|
15957
|
-
|
|
15958
|
-
const s = parseScale(value, line12);
|
|
15959
|
-
if (s) d.scale = s;
|
|
15960
|
-
}
|
|
15961
|
-
break;
|
|
15962
|
-
case "region-labels":
|
|
15963
|
-
dup(d.regionLabels);
|
|
15964
|
-
if (value && !["full", "abbrev", "off"].includes(value))
|
|
15965
|
-
pushWarning(
|
|
15966
|
-
line12,
|
|
15967
|
-
`Unknown region-labels "${value}" (expected full | abbrev | off).`
|
|
15968
|
-
);
|
|
15969
|
-
d.regionLabels = value;
|
|
15970
|
-
break;
|
|
15971
|
-
case "poi-labels":
|
|
15972
|
-
dup(d.poiLabels);
|
|
15973
|
-
if (value && !["off", "auto", "all"].includes(value))
|
|
15974
|
-
pushWarning(
|
|
15975
|
-
line12,
|
|
15976
|
-
`Unknown poi-labels "${value}" (expected off | auto | all).`
|
|
15977
|
-
);
|
|
15978
|
-
d.poiLabels = value;
|
|
15979
|
-
break;
|
|
15980
|
-
case "default-country":
|
|
15981
|
-
dup(d.defaultCountry);
|
|
15982
|
-
d.defaultCountry = value;
|
|
15983
|
-
break;
|
|
15984
|
-
case "default-state":
|
|
15985
|
-
dup(d.defaultState);
|
|
15986
|
-
d.defaultState = value;
|
|
16372
|
+
case "locale":
|
|
16373
|
+
dup(d.locale);
|
|
16374
|
+
d.locale = value;
|
|
15987
16375
|
break;
|
|
15988
16376
|
case "active-tag":
|
|
15989
16377
|
dup(d.activeTag);
|
|
15990
16378
|
d.activeTag = value;
|
|
15991
16379
|
break;
|
|
16380
|
+
case "caption":
|
|
16381
|
+
dup(d.caption);
|
|
16382
|
+
d.caption = value;
|
|
16383
|
+
break;
|
|
16384
|
+
// ── Cosmetic `no-*` opt-outs: bare flags, idempotent (mirror `no-legend`,
|
|
16385
|
+
// no dup warning); each defaults the feature ON when absent. ──
|
|
15992
16386
|
case "no-legend":
|
|
15993
16387
|
d.noLegend = true;
|
|
15994
16388
|
break;
|
|
15995
|
-
case "
|
|
15996
|
-
|
|
15997
|
-
if (d.basemapStyle !== void 0 && d.basemapStyle !== key)
|
|
15998
|
-
pushWarning(
|
|
15999
|
-
line12,
|
|
16000
|
-
`Conflicting basemap dress \u2014 "${d.basemapStyle}" then "${key}"; last wins.`
|
|
16001
|
-
);
|
|
16002
|
-
d.basemapStyle = key;
|
|
16389
|
+
case "no-coastline":
|
|
16390
|
+
d.noCoastline = true;
|
|
16003
16391
|
break;
|
|
16004
|
-
case "
|
|
16005
|
-
|
|
16006
|
-
d.subtitle = value;
|
|
16392
|
+
case "no-relief":
|
|
16393
|
+
d.noRelief = true;
|
|
16007
16394
|
break;
|
|
16008
|
-
case "
|
|
16009
|
-
|
|
16010
|
-
|
|
16395
|
+
case "no-context-labels":
|
|
16396
|
+
d.noContextLabels = true;
|
|
16397
|
+
break;
|
|
16398
|
+
case "no-region-labels":
|
|
16399
|
+
d.noRegionLabels = true;
|
|
16400
|
+
break;
|
|
16401
|
+
case "no-poi-labels":
|
|
16402
|
+
d.noPoiLabels = true;
|
|
16403
|
+
break;
|
|
16404
|
+
case "no-colorize":
|
|
16405
|
+
d.noColorize = true;
|
|
16011
16406
|
break;
|
|
16012
16407
|
}
|
|
16013
16408
|
}
|
|
16014
|
-
function parseScale(value, line12) {
|
|
16015
|
-
const toks = value.split(/\s+/).filter(Boolean);
|
|
16016
|
-
const min = Number(toks[0]);
|
|
16017
|
-
const max = Number(toks[1]);
|
|
16018
|
-
if (!Number.isFinite(min) || !Number.isFinite(max)) {
|
|
16019
|
-
pushError(line12, `scale requires numeric <min> <max> (got "${value}").`);
|
|
16020
|
-
return null;
|
|
16021
|
-
}
|
|
16022
|
-
const scale = { min, max };
|
|
16023
|
-
if (toks[2] === "center") {
|
|
16024
|
-
const c = Number(toks[3]);
|
|
16025
|
-
if (Number.isFinite(c)) scale.center = c;
|
|
16026
|
-
else
|
|
16027
|
-
pushError(
|
|
16028
|
-
line12,
|
|
16029
|
-
`scale center requires a number (got "${toks[3] ?? ""}").`
|
|
16030
|
-
);
|
|
16031
|
-
}
|
|
16032
|
-
return scale;
|
|
16033
|
-
}
|
|
16034
16409
|
function handleTag(trimmed, line12) {
|
|
16035
16410
|
const m = matchTagBlockHeading(trimmed);
|
|
16036
16411
|
if (!m) {
|
|
@@ -16104,6 +16479,7 @@ function parseMap(content) {
|
|
|
16104
16479
|
};
|
|
16105
16480
|
if (regionScope !== void 0) region.scope = regionScope;
|
|
16106
16481
|
if (valueNum !== void 0) region.value = valueNum;
|
|
16482
|
+
if (split.color) region.color = split.color;
|
|
16107
16483
|
regions.push(region);
|
|
16108
16484
|
}
|
|
16109
16485
|
function handlePoi(rest, line12, indent) {
|
|
@@ -16128,6 +16504,7 @@ function parseMap(content) {
|
|
|
16128
16504
|
const poi = { pos, tags, meta, lineNumber: line12 };
|
|
16129
16505
|
if (split.alias) poi.alias = split.alias;
|
|
16130
16506
|
if (label !== void 0) poi.label = label;
|
|
16507
|
+
if (split.color) poi.color = split.color;
|
|
16131
16508
|
pois.push(poi);
|
|
16132
16509
|
open.poi = { poi, indent };
|
|
16133
16510
|
}
|
|
@@ -16228,13 +16605,15 @@ function parseMap(content) {
|
|
|
16228
16605
|
pushError(line12, `Edge has an empty endpoint: "${trimmed}".`);
|
|
16229
16606
|
continue;
|
|
16230
16607
|
}
|
|
16231
|
-
const
|
|
16608
|
+
const isLast = k === links.length - 1;
|
|
16609
|
+
const meta = isLast ? lastSplit.meta : {};
|
|
16610
|
+
const style = links[k].style === "arc" ? "arc" : "straight";
|
|
16232
16611
|
edges.push({
|
|
16233
16612
|
from,
|
|
16234
16613
|
to,
|
|
16235
16614
|
...links[k].label !== void 0 && { label: links[k].label },
|
|
16236
16615
|
directed: links[k].directed,
|
|
16237
|
-
style
|
|
16616
|
+
style,
|
|
16238
16617
|
meta,
|
|
16239
16618
|
lineNumber: line12
|
|
16240
16619
|
});
|
|
@@ -16320,20 +16699,19 @@ var init_parser12 = __esm({
|
|
|
16320
16699
|
LEG_ARROW_RE = /^(-[^>]*?->|->|~[^>]*?~>|~>|--)\s+(.+)$/;
|
|
16321
16700
|
AT_RE = /(^|[\s,])at\s*:/i;
|
|
16322
16701
|
DIRECTIVE_SET = /* @__PURE__ */ new Set([
|
|
16323
|
-
"region",
|
|
16324
|
-
"projection",
|
|
16325
16702
|
"region-metric",
|
|
16326
16703
|
"poi-metric",
|
|
16327
16704
|
"flow-metric",
|
|
16328
|
-
"
|
|
16329
|
-
"region-labels",
|
|
16330
|
-
"poi-labels",
|
|
16331
|
-
"default-country",
|
|
16332
|
-
"default-state",
|
|
16705
|
+
"locale",
|
|
16333
16706
|
"active-tag",
|
|
16707
|
+
"caption",
|
|
16334
16708
|
"no-legend",
|
|
16335
|
-
"
|
|
16336
|
-
"
|
|
16709
|
+
"no-coastline",
|
|
16710
|
+
"no-relief",
|
|
16711
|
+
"no-context-labels",
|
|
16712
|
+
"no-region-labels",
|
|
16713
|
+
"no-poi-labels",
|
|
16714
|
+
"no-colorize"
|
|
16337
16715
|
]);
|
|
16338
16716
|
}
|
|
16339
16717
|
});
|
|
@@ -24345,8 +24723,8 @@ function renderKanban(container, parsed, palette, isDark, options) {
|
|
|
24345
24723
|
let metaY = separatorY + sCardSeparatorGap + sCardMetaFontSize;
|
|
24346
24724
|
for (const meta of tagMeta) {
|
|
24347
24725
|
cg.append("text").attr("x", cx + sCardPaddingX).attr("y", metaY).attr("font-size", sCardMetaFontSize).attr("fill", onCardText).text(`${meta.label}: `);
|
|
24348
|
-
const
|
|
24349
|
-
cg.append("text").attr("x", cx + sCardPaddingX +
|
|
24726
|
+
const labelWidth2 = (meta.label.length + 2) * sCardMetaFontSize * 0.6;
|
|
24727
|
+
cg.append("text").attr("x", cx + sCardPaddingX + labelWidth2).attr("y", metaY).attr("font-size", sCardMetaFontSize).attr("fill", onCardText).text(meta.value);
|
|
24350
24728
|
metaY += sCardMetaLineHeight;
|
|
24351
24729
|
}
|
|
24352
24730
|
for (const detail of card.details) {
|
|
@@ -24690,8 +25068,8 @@ function renderSwimlaneCard(parent, cardLayout, tagGroups, activeTagGroup, palet
|
|
|
24690
25068
|
let metaY = separatorY + sCardSeparatorGap + sCardMetaFontSize;
|
|
24691
25069
|
for (const meta of tagMeta) {
|
|
24692
25070
|
cg.append("text").attr("x", cx + sCardPaddingX).attr("y", metaY).attr("font-size", sCardMetaFontSize).attr("fill", palette.textMuted).text(`${meta.label}: `);
|
|
24693
|
-
const
|
|
24694
|
-
cg.append("text").attr("x", cx + sCardPaddingX +
|
|
25071
|
+
const labelWidth2 = (meta.label.length + 2) * sCardMetaFontSize * 0.6;
|
|
25072
|
+
cg.append("text").attr("x", cx + sCardPaddingX + labelWidth2).attr("y", metaY).attr("font-size", sCardMetaFontSize).attr("fill", onCardText).text(meta.value);
|
|
24695
25073
|
metaY += sCardMetaLineHeight;
|
|
24696
25074
|
}
|
|
24697
25075
|
for (const detail of card.details) {
|
|
@@ -25525,8 +25903,8 @@ function classifyEREntities(tables, relationships) {
|
|
|
25525
25903
|
}
|
|
25526
25904
|
}
|
|
25527
25905
|
const mmParticipants = /* @__PURE__ */ new Set();
|
|
25528
|
-
for (const [id,
|
|
25529
|
-
if (
|
|
25906
|
+
for (const [id, neighbors2] of tableStarNeighbors) {
|
|
25907
|
+
if (neighbors2.size >= 2) mmParticipants.add(id);
|
|
25530
25908
|
}
|
|
25531
25909
|
const indegreeValues = Object.values(indegreeMap);
|
|
25532
25910
|
const mean = indegreeValues.reduce((a, b) => a + b, 0) / indegreeValues.length;
|
|
@@ -26199,7 +26577,8 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26199
26577
|
controlsExpanded,
|
|
26200
26578
|
onToggleDescriptions,
|
|
26201
26579
|
onToggleControlsExpand,
|
|
26202
|
-
exportMode = false
|
|
26580
|
+
exportMode = false,
|
|
26581
|
+
controlsHost
|
|
26203
26582
|
} = options ?? {};
|
|
26204
26583
|
d3Selection6.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
26205
26584
|
const width = exportDims?.width ?? container.clientWidth;
|
|
@@ -26217,7 +26596,11 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26217
26596
|
const sGroupLabelZone = sctx.structural(GROUP_LABEL_ZONE);
|
|
26218
26597
|
const sTitleFontSize = sctx.text(TITLE_FONT_SIZE);
|
|
26219
26598
|
const sTitleY = sctx.structural(TITLE_Y);
|
|
26220
|
-
const
|
|
26599
|
+
const reserveHasDescriptions = parsed.nodes.some(
|
|
26600
|
+
(n) => n.description && n.description.length > 0
|
|
26601
|
+
);
|
|
26602
|
+
const willRenderLegend = parsed.tagGroups.length > 0 || reserveHasDescriptions && controlsHost !== "app";
|
|
26603
|
+
const sLegendHeight = willRenderLegend ? sctx.structural(
|
|
26221
26604
|
getMaxLegendReservedHeight(
|
|
26222
26605
|
{
|
|
26223
26606
|
groups: parsed.tagGroups,
|
|
@@ -26226,7 +26609,7 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26226
26609
|
},
|
|
26227
26610
|
width
|
|
26228
26611
|
)
|
|
26229
|
-
);
|
|
26612
|
+
) : 0;
|
|
26230
26613
|
const activeGroup = resolveActiveTagGroup(
|
|
26231
26614
|
parsed.tagGroups,
|
|
26232
26615
|
parsed.options["active-tag"],
|
|
@@ -26541,10 +26924,10 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26541
26924
|
const hasDescriptions = parsed.nodes.some(
|
|
26542
26925
|
(n) => n.description && n.description.length > 0
|
|
26543
26926
|
);
|
|
26544
|
-
const hasLegend = parsed.tagGroups.length > 0 || hasDescriptions;
|
|
26927
|
+
const hasLegend = parsed.tagGroups.length > 0 || hasDescriptions && controlsHost !== "app";
|
|
26545
26928
|
if (hasLegend) {
|
|
26546
26929
|
let controlsGroup;
|
|
26547
|
-
if (hasDescriptions && onToggleDescriptions) {
|
|
26930
|
+
if (hasDescriptions && (onToggleDescriptions || controlsHost === "app")) {
|
|
26548
26931
|
controlsGroup = {
|
|
26549
26932
|
toggles: [
|
|
26550
26933
|
{
|
|
@@ -26562,7 +26945,14 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26562
26945
|
groups: parsed.tagGroups,
|
|
26563
26946
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
26564
26947
|
mode: exportMode ? "export" : "preview",
|
|
26565
|
-
|
|
26948
|
+
// Keep inactive sibling tag groups visible as collapsed pills so the user
|
|
26949
|
+
// can click one to flip the active colouring dimension (preview only —
|
|
26950
|
+
// export shows just the active group). Without this, declaring a second
|
|
26951
|
+
// tag group (e.g. Team) leaves it invisible whenever another group is
|
|
26952
|
+
// active. The app's BoxesAndLinesPreview already wires pill clicks.
|
|
26953
|
+
showInactivePills: true,
|
|
26954
|
+
...controlsGroup !== void 0 && { controlsGroup },
|
|
26955
|
+
...controlsHost !== void 0 && { controlsHost }
|
|
26566
26956
|
};
|
|
26567
26957
|
const legendState = {
|
|
26568
26958
|
activeGroup,
|
|
@@ -27809,8 +28199,9 @@ function renderMindmap(container, parsed, layout, palette, isDark, onClickItem,
|
|
|
27809
28199
|
const containerHeight = exportDims?.height ?? (container.getBoundingClientRect().height || 600);
|
|
27810
28200
|
d3Selection7.select(container).selectAll("*").remove();
|
|
27811
28201
|
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);
|
|
28202
|
+
const appHosted = options?.controlsHost === "app";
|
|
27812
28203
|
const hasControls = !!options?.onToggleColorByDepth || !!options?.onToggleDescriptions;
|
|
27813
|
-
const hasLegend = parsed.tagGroups.length > 0 || hasControls;
|
|
28204
|
+
const hasLegend = parsed.tagGroups.length > 0 || hasControls && !appHosted;
|
|
27814
28205
|
const fixedLegend = !isExport && hasLegend;
|
|
27815
28206
|
const legendReserve = fixedLegend ? getMaxLegendReservedHeight(
|
|
27816
28207
|
{
|
|
@@ -27904,7 +28295,10 @@ function renderMindmap(container, parsed, layout, palette, isDark, onClickItem,
|
|
|
27904
28295
|
}),
|
|
27905
28296
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
27906
28297
|
mode: options?.exportMode ? "export" : "preview",
|
|
27907
|
-
...controlsToggles !== void 0 && { controlsGroup: controlsToggles }
|
|
28298
|
+
...controlsToggles !== void 0 && { controlsGroup: controlsToggles },
|
|
28299
|
+
...options?.controlsHost !== void 0 && {
|
|
28300
|
+
controlsHost: options.controlsHost
|
|
28301
|
+
}
|
|
27908
28302
|
};
|
|
27909
28303
|
const legendState = {
|
|
27910
28304
|
activeGroup: options?.colorByDepth ? null : activeTagGroup !== void 0 ? activeTagGroup : parsed.options["active-tag"] ?? null,
|
|
@@ -28347,8 +28741,8 @@ function computeFieldAlignX(children) {
|
|
|
28347
28741
|
for (const child of children) {
|
|
28348
28742
|
if (child.metadata["_labelField"] === "true" && child.children.length >= 2) {
|
|
28349
28743
|
const labelEl = child.children[0];
|
|
28350
|
-
const
|
|
28351
|
-
maxLabelWidth = Math.max(maxLabelWidth,
|
|
28744
|
+
const labelWidth2 = labelEl.label.length * CHAR_WIDTH5;
|
|
28745
|
+
maxLabelWidth = Math.max(maxLabelWidth, labelWidth2);
|
|
28352
28746
|
labelFieldCount++;
|
|
28353
28747
|
}
|
|
28354
28748
|
}
|
|
@@ -33313,7 +33707,7 @@ function hasRoles(node) {
|
|
|
33313
33707
|
function computeNodeWidth2(node, expanded, options) {
|
|
33314
33708
|
const badgeVal = node.computedConcurrentInvocations === 0 && node.computedInstances > 1 ? node.computedInstances : 0;
|
|
33315
33709
|
const badgeLen = badgeVal > 0 ? `${badgeVal}x`.length + 2 : 0;
|
|
33316
|
-
const
|
|
33710
|
+
const labelWidth2 = (node.label.length + badgeLen) * CHAR_WIDTH7 + PADDING_X3;
|
|
33317
33711
|
const allKeys = [];
|
|
33318
33712
|
if (node.computedRps > 0) allKeys.push("RPS");
|
|
33319
33713
|
if (expanded) {
|
|
@@ -33357,7 +33751,7 @@ function computeNodeWidth2(node, expanded, options) {
|
|
|
33357
33751
|
allKeys.push("overflow");
|
|
33358
33752
|
}
|
|
33359
33753
|
}
|
|
33360
|
-
if (allKeys.length === 0) return Math.max(MIN_NODE_WIDTH2,
|
|
33754
|
+
if (allKeys.length === 0) return Math.max(MIN_NODE_WIDTH2, labelWidth2);
|
|
33361
33755
|
const maxKeyLen = Math.max(...allKeys.map((k) => k.length));
|
|
33362
33756
|
let maxRowWidth = 0;
|
|
33363
33757
|
if (node.computedRps > 0) {
|
|
@@ -33445,7 +33839,7 @@ function computeNodeWidth2(node, expanded, options) {
|
|
|
33445
33839
|
truncated.length * META_CHAR_WIDTH3 + PADDING_X3
|
|
33446
33840
|
);
|
|
33447
33841
|
}
|
|
33448
|
-
return Math.max(MIN_NODE_WIDTH2,
|
|
33842
|
+
return Math.max(MIN_NODE_WIDTH2, labelWidth2, maxRowWidth + 20, descWidth);
|
|
33449
33843
|
}
|
|
33450
33844
|
function computeNodeHeight2(node, expanded, options) {
|
|
33451
33845
|
const propCount = countDisplayProps(node, expanded, options);
|
|
@@ -34995,8 +35389,9 @@ function computeInfraLegendGroups(nodes, tagGroups, palette, edges) {
|
|
|
34995
35389
|
}
|
|
34996
35390
|
return groups;
|
|
34997
35391
|
}
|
|
34998
|
-
function renderLegend3(rootSvg, legendGroups, totalWidth, legendY, palette, isDark, activeGroup, playback, exportMode = false) {
|
|
35392
|
+
function renderLegend3(rootSvg, legendGroups, totalWidth, legendY, palette, isDark, activeGroup, playback, exportMode = false, controlsHost) {
|
|
34999
35393
|
if (legendGroups.length === 0 && !playback) return;
|
|
35394
|
+
const appHostedPlayback = controlsHost === "app" && !!playback;
|
|
35000
35395
|
const legendG = rootSvg.append("g").attr("transform", `translate(0, ${legendY})`);
|
|
35001
35396
|
if (activeGroup) {
|
|
35002
35397
|
legendG.attr("data-legend-active", activeGroup.toLowerCase());
|
|
@@ -35005,14 +35400,29 @@ function renderLegend3(rootSvg, legendGroups, totalWidth, legendY, palette, isDa
|
|
|
35005
35400
|
name: g.name,
|
|
35006
35401
|
entries: g.entries.map((e) => ({ value: e.value, color: e.color }))
|
|
35007
35402
|
}));
|
|
35008
|
-
if (playback) {
|
|
35403
|
+
if (playback && !appHostedPlayback) {
|
|
35009
35404
|
allGroups.push({ name: "Playback", entries: [] });
|
|
35010
35405
|
}
|
|
35011
35406
|
const legendConfig = {
|
|
35012
35407
|
groups: allGroups,
|
|
35013
35408
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
35014
35409
|
mode: exportMode ? "export" : "preview",
|
|
35015
|
-
showEmptyGroups: true
|
|
35410
|
+
showEmptyGroups: true,
|
|
35411
|
+
...appHostedPlayback && {
|
|
35412
|
+
controlsHost: "app",
|
|
35413
|
+
controlsGroup: {
|
|
35414
|
+
toggles: [
|
|
35415
|
+
{
|
|
35416
|
+
id: "playback",
|
|
35417
|
+
type: "toggle",
|
|
35418
|
+
label: "Playback",
|
|
35419
|
+
active: true,
|
|
35420
|
+
onToggle: () => {
|
|
35421
|
+
}
|
|
35422
|
+
}
|
|
35423
|
+
]
|
|
35424
|
+
}
|
|
35425
|
+
}
|
|
35016
35426
|
};
|
|
35017
35427
|
const legendState = { activeGroup };
|
|
35018
35428
|
renderLegendD3(
|
|
@@ -35063,8 +35473,9 @@ function renderLegend3(rootSvg, legendGroups, totalWidth, legendY, palette, isDa
|
|
|
35063
35473
|
}
|
|
35064
35474
|
}
|
|
35065
35475
|
}
|
|
35066
|
-
function renderInfra(container, layout, palette, isDark, title, titleLineNumber, tagGroups, activeGroup, animate, playback, expandedNodeIds, exportMode, collapsedNodes) {
|
|
35476
|
+
function renderInfra(container, layout, palette, isDark, title, titleLineNumber, tagGroups, activeGroup, animate, playback, expandedNodeIds, exportMode, collapsedNodes, controlsHost) {
|
|
35067
35477
|
d3Selection11.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
35478
|
+
const appHostedPlayback = controlsHost === "app" && !!playback;
|
|
35068
35479
|
const ctx = ScaleContext.identity();
|
|
35069
35480
|
const sc = buildScaledConstants(ctx);
|
|
35070
35481
|
const legendGroups = computeInfraLegendGroups(
|
|
@@ -35073,7 +35484,7 @@ function renderInfra(container, layout, palette, isDark, title, titleLineNumber,
|
|
|
35073
35484
|
palette,
|
|
35074
35485
|
layout.edges
|
|
35075
35486
|
);
|
|
35076
|
-
const hasLegend = legendGroups.length > 0 || !!playback;
|
|
35487
|
+
const hasLegend = legendGroups.length > 0 || !!playback && !appHostedPlayback;
|
|
35077
35488
|
const fixedLegend = !exportMode && hasLegend;
|
|
35078
35489
|
const legendDynamicH = hasLegend ? getMaxLegendReservedHeight(
|
|
35079
35490
|
{
|
|
@@ -35217,7 +35628,8 @@ function renderInfra(container, layout, palette, isDark, title, titleLineNumber,
|
|
|
35217
35628
|
isDark,
|
|
35218
35629
|
activeGroup ?? null,
|
|
35219
35630
|
playback ?? void 0,
|
|
35220
|
-
exportMode
|
|
35631
|
+
exportMode,
|
|
35632
|
+
controlsHost
|
|
35221
35633
|
);
|
|
35222
35634
|
legendSvg.selectAll(".infra-legend-group").style("pointer-events", "auto");
|
|
35223
35635
|
} else {
|
|
@@ -35230,7 +35642,8 @@ function renderInfra(container, layout, palette, isDark, title, titleLineNumber,
|
|
|
35230
35642
|
isDark,
|
|
35231
35643
|
activeGroup ?? null,
|
|
35232
35644
|
playback ?? void 0,
|
|
35233
|
-
exportMode
|
|
35645
|
+
exportMode,
|
|
35646
|
+
controlsHost
|
|
35234
35647
|
);
|
|
35235
35648
|
}
|
|
35236
35649
|
}
|
|
@@ -43087,6 +43500,9 @@ function renderTechRadar(container, parsed, palette, isDark, onClickItem, export
|
|
|
43087
43500
|
onToggle: (active) => options.onToggleListing(active)
|
|
43088
43501
|
}
|
|
43089
43502
|
]
|
|
43503
|
+
},
|
|
43504
|
+
...options.controlsHost !== void 0 && {
|
|
43505
|
+
controlsHost: options.controlsHost
|
|
43090
43506
|
}
|
|
43091
43507
|
};
|
|
43092
43508
|
const legendState = {
|
|
@@ -44909,7 +45325,7 @@ function computeCycleLayout(parsed, options) {
|
|
|
44909
45325
|
const circleNodes = parsed.options["circle-nodes"] === "true";
|
|
44910
45326
|
const nodeDims = parsed.nodes.map((node) => {
|
|
44911
45327
|
const hasDesc = !hideDescriptions && node.description.length > 0;
|
|
44912
|
-
const
|
|
45328
|
+
const labelWidth2 = Math.max(
|
|
44913
45329
|
MIN_NODE_WIDTH4,
|
|
44914
45330
|
node.label.length * LABEL_CHAR_W + NODE_PAD_X * 2
|
|
44915
45331
|
);
|
|
@@ -44918,12 +45334,12 @@ function computeCycleLayout(parsed, options) {
|
|
|
44918
45334
|
}
|
|
44919
45335
|
if (!hasDesc) {
|
|
44920
45336
|
return {
|
|
44921
|
-
width: Math.min(MAX_NODE_WIDTH3,
|
|
45337
|
+
width: Math.min(MAX_NODE_WIDTH3, labelWidth2),
|
|
44922
45338
|
height: PLAIN_NODE_HEIGHT,
|
|
44923
45339
|
wrappedDesc: []
|
|
44924
45340
|
};
|
|
44925
45341
|
}
|
|
44926
|
-
return chooseDescribedRectDims(node.description,
|
|
45342
|
+
return chooseDescribedRectDims(node.description, labelWidth2);
|
|
44927
45343
|
});
|
|
44928
45344
|
if (circleNodes) {
|
|
44929
45345
|
const maxDiam = Math.max(...nodeDims.map((d) => d.width));
|
|
@@ -45119,10 +45535,10 @@ function computeCycleLayout(parsed, options) {
|
|
|
45119
45535
|
scale
|
|
45120
45536
|
};
|
|
45121
45537
|
}
|
|
45122
|
-
function chooseDescribedRectDims(description,
|
|
45538
|
+
function chooseDescribedRectDims(description, labelWidth2) {
|
|
45123
45539
|
const minW = Math.min(
|
|
45124
45540
|
MAX_NODE_WIDTH3,
|
|
45125
|
-
Math.max(MIN_NODE_WIDTH4,
|
|
45541
|
+
Math.max(MIN_NODE_WIDTH4, labelWidth2, DESC_MIN_WIDTH)
|
|
45126
45542
|
);
|
|
45127
45543
|
let best = null;
|
|
45128
45544
|
let bestScore = Infinity;
|
|
@@ -45551,7 +45967,8 @@ function renderCycle(container, parsed, palette, isDark, onClickItem, exportDims
|
|
|
45551
45967
|
const hideDescriptions = (renderOptions?.hideDescriptions ?? false) || parsed.options["no-descriptions"] === "true" || viewState?.hd === true;
|
|
45552
45968
|
const showDescriptions = !hideDescriptions;
|
|
45553
45969
|
const hasDescriptions = parsed.nodes.some((n) => n.description.length > 0) || parsed.edges.some((e) => e.description.length > 0);
|
|
45554
|
-
const
|
|
45970
|
+
const appHostedControls = renderOptions?.controlsHost === "app";
|
|
45971
|
+
const hasLegend = !appHostedControls && hasDescriptions && !!renderOptions?.onToggleDescriptions;
|
|
45555
45972
|
const showTitle = !!parsed.title && parsed.options["no-title"] !== "on";
|
|
45556
45973
|
const legendOffset = hasLegend ? sLegendHeight : 0;
|
|
45557
45974
|
const layoutHeight = height - (showTitle ? sTitleAreaHeight : 0) - legendOffset;
|
|
@@ -45588,7 +46005,10 @@ function renderCycle(container, parsed, palette, isDark, onClickItem, exportDims
|
|
|
45588
46005
|
groups: [],
|
|
45589
46006
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
45590
46007
|
mode: renderOptions?.exportMode ? "export" : "preview",
|
|
45591
|
-
controlsGroup
|
|
46008
|
+
controlsGroup,
|
|
46009
|
+
...renderOptions?.controlsHost !== void 0 && {
|
|
46010
|
+
controlsHost: renderOptions.controlsHost
|
|
46011
|
+
}
|
|
45592
46012
|
};
|
|
45593
46013
|
const legendState = {
|
|
45594
46014
|
activeGroup: null,
|
|
@@ -45842,8 +46262,8 @@ var init_renderer15 = __esm({
|
|
|
45842
46262
|
});
|
|
45843
46263
|
|
|
45844
46264
|
// src/map/geo.ts
|
|
45845
|
-
import { feature } from "topojson-client";
|
|
45846
|
-
import { geoBounds } from "d3-geo";
|
|
46265
|
+
import { feature, neighbors } from "topojson-client";
|
|
46266
|
+
import { geoBounds, geoArea } from "d3-geo";
|
|
45847
46267
|
function geomObject(topo) {
|
|
45848
46268
|
const key = Object.keys(topo.objects)[0];
|
|
45849
46269
|
return topo.objects[key];
|
|
@@ -45860,6 +46280,107 @@ function featureIndex(topo) {
|
|
|
45860
46280
|
}
|
|
45861
46281
|
return idx;
|
|
45862
46282
|
}
|
|
46283
|
+
function buildAdjacency(topo) {
|
|
46284
|
+
const cached = adjacencyCache.get(topo);
|
|
46285
|
+
if (cached) return cached;
|
|
46286
|
+
const geometries = geomObject(topo).geometries;
|
|
46287
|
+
const nb = neighbors(geometries);
|
|
46288
|
+
const sets = /* @__PURE__ */ new Map();
|
|
46289
|
+
geometries.forEach((g, i) => {
|
|
46290
|
+
if (!g.type || g.type === "null") return;
|
|
46291
|
+
let set = sets.get(g.id);
|
|
46292
|
+
if (!set) {
|
|
46293
|
+
set = /* @__PURE__ */ new Set();
|
|
46294
|
+
sets.set(g.id, set);
|
|
46295
|
+
}
|
|
46296
|
+
for (const j of nb[i] ?? []) {
|
|
46297
|
+
const nid = geometries[j]?.id;
|
|
46298
|
+
if (nid && nid !== g.id) set.add(nid);
|
|
46299
|
+
}
|
|
46300
|
+
});
|
|
46301
|
+
const out = /* @__PURE__ */ new Map();
|
|
46302
|
+
for (const [iso, set] of sets) out.set(iso, [...set].sort());
|
|
46303
|
+
adjacencyCache.set(topo, out);
|
|
46304
|
+
return out;
|
|
46305
|
+
}
|
|
46306
|
+
function decodeFeatures(topo) {
|
|
46307
|
+
return geomObject(topo).geometries.map((g) => {
|
|
46308
|
+
const f = feature(topo, g);
|
|
46309
|
+
return {
|
|
46310
|
+
type: "Feature",
|
|
46311
|
+
id: g.id,
|
|
46312
|
+
properties: g.properties,
|
|
46313
|
+
geometry: f.geometry
|
|
46314
|
+
};
|
|
46315
|
+
});
|
|
46316
|
+
}
|
|
46317
|
+
function pointInRing(lon, lat, ring) {
|
|
46318
|
+
let inside = false;
|
|
46319
|
+
for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
|
|
46320
|
+
const xi = ring[i][0];
|
|
46321
|
+
const yi = ring[i][1];
|
|
46322
|
+
const xj = ring[j][0];
|
|
46323
|
+
const yj = ring[j][1];
|
|
46324
|
+
const intersect = yi > lat !== yj > lat && lon < (xj - xi) * (lat - yi) / (yj - yi) + xi;
|
|
46325
|
+
if (intersect) inside = !inside;
|
|
46326
|
+
}
|
|
46327
|
+
return inside;
|
|
46328
|
+
}
|
|
46329
|
+
function pointOnRingEdge(lon, lat, ring) {
|
|
46330
|
+
for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
|
|
46331
|
+
const xi = ring[i][0];
|
|
46332
|
+
const yi = ring[i][1];
|
|
46333
|
+
const xj = ring[j][0];
|
|
46334
|
+
const yj = ring[j][1];
|
|
46335
|
+
if (lon < Math.min(xi, xj) - EDGE_EPS || lon > Math.max(xi, xj) + EDGE_EPS)
|
|
46336
|
+
continue;
|
|
46337
|
+
if (lat < Math.min(yi, yj) - EDGE_EPS || lat > Math.max(yi, yj) + EDGE_EPS)
|
|
46338
|
+
continue;
|
|
46339
|
+
const cross = (xj - xi) * (lat - yi) - (yj - yi) * (lon - xi);
|
|
46340
|
+
if (Math.abs(cross) <= EDGE_EPS) return true;
|
|
46341
|
+
}
|
|
46342
|
+
return false;
|
|
46343
|
+
}
|
|
46344
|
+
function pointInGeometry(geometry, lon, lat) {
|
|
46345
|
+
const g = geometry;
|
|
46346
|
+
if (!g) return false;
|
|
46347
|
+
const polys = g.type === "Polygon" ? [g.coordinates] : g.type === "MultiPolygon" ? g.coordinates : [];
|
|
46348
|
+
for (const rings of polys) {
|
|
46349
|
+
if (!rings.length) continue;
|
|
46350
|
+
if (pointOnRingEdge(lon, lat, rings[0])) return true;
|
|
46351
|
+
if (!pointInRing(lon, lat, rings[0])) continue;
|
|
46352
|
+
let inHole = false;
|
|
46353
|
+
for (let h = 1; h < rings.length; h++) {
|
|
46354
|
+
if (pointInRing(lon, lat, rings[h]) && !pointOnRingEdge(lon, lat, rings[h])) {
|
|
46355
|
+
inHole = true;
|
|
46356
|
+
break;
|
|
46357
|
+
}
|
|
46358
|
+
}
|
|
46359
|
+
if (!inHole) return true;
|
|
46360
|
+
}
|
|
46361
|
+
return false;
|
|
46362
|
+
}
|
|
46363
|
+
function regionAt(lonLat, countries, states) {
|
|
46364
|
+
const lon = lonLat[0];
|
|
46365
|
+
const lat = lonLat[1];
|
|
46366
|
+
let country = null;
|
|
46367
|
+
for (const f of countries) {
|
|
46368
|
+
if (pointInGeometry(f.geometry, lon, lat)) {
|
|
46369
|
+
country = { iso: f.id, name: f.properties.name };
|
|
46370
|
+
break;
|
|
46371
|
+
}
|
|
46372
|
+
}
|
|
46373
|
+
let state = null;
|
|
46374
|
+
if (country?.iso === "US" && states) {
|
|
46375
|
+
for (const f of states) {
|
|
46376
|
+
if (pointInGeometry(f.geometry, lon, lat)) {
|
|
46377
|
+
state = { iso: f.id, name: f.properties.name };
|
|
46378
|
+
break;
|
|
46379
|
+
}
|
|
46380
|
+
}
|
|
46381
|
+
}
|
|
46382
|
+
return { country, state };
|
|
46383
|
+
}
|
|
45863
46384
|
function featureBbox(topo, geomId) {
|
|
45864
46385
|
const geom = geomObject(topo).geometries.find((g) => g.id === geomId);
|
|
45865
46386
|
if (!geom) return null;
|
|
@@ -45871,6 +46392,74 @@ function featureBbox(topo, geomId) {
|
|
|
45871
46392
|
[b[1][0], b[1][1]]
|
|
45872
46393
|
];
|
|
45873
46394
|
}
|
|
46395
|
+
function explodePolygons(gj) {
|
|
46396
|
+
const g = gj.geometry ?? gj;
|
|
46397
|
+
const t = g.type;
|
|
46398
|
+
const coords = g.coordinates;
|
|
46399
|
+
if (t === "Polygon") {
|
|
46400
|
+
return [
|
|
46401
|
+
{ type: "Feature", geometry: { type: "Polygon", coordinates: coords } }
|
|
46402
|
+
];
|
|
46403
|
+
}
|
|
46404
|
+
if (t === "MultiPolygon") {
|
|
46405
|
+
return coords.map((rings) => ({
|
|
46406
|
+
type: "Feature",
|
|
46407
|
+
geometry: { type: "Polygon", coordinates: rings }
|
|
46408
|
+
}));
|
|
46409
|
+
}
|
|
46410
|
+
return [];
|
|
46411
|
+
}
|
|
46412
|
+
function bboxGap(a, b) {
|
|
46413
|
+
const lonGap = Math.max(0, a[0][0] - b[1][0], b[0][0] - a[1][0]);
|
|
46414
|
+
const latGap = Math.max(0, a[0][1] - b[1][1], b[0][1] - a[1][1]);
|
|
46415
|
+
return Math.max(lonGap, latGap);
|
|
46416
|
+
}
|
|
46417
|
+
function featureBboxPrimary(topo, geomId) {
|
|
46418
|
+
const geom = geomObject(topo).geometries.find((g) => g.id === geomId);
|
|
46419
|
+
if (!geom) return null;
|
|
46420
|
+
const gj = feature(topo, geom);
|
|
46421
|
+
const parts = explodePolygons(gj);
|
|
46422
|
+
if (parts.length <= 1) return featureBbox(topo, geomId);
|
|
46423
|
+
const polys = parts.map((p) => {
|
|
46424
|
+
const b = geoBounds(p);
|
|
46425
|
+
if (!b || !Number.isFinite(b[0][0])) return null;
|
|
46426
|
+
const wraps = b[1][0] < b[0][0];
|
|
46427
|
+
const bbox = [
|
|
46428
|
+
[b[0][0], b[0][1]],
|
|
46429
|
+
[b[1][0], b[1][1]]
|
|
46430
|
+
];
|
|
46431
|
+
return { bbox, area: geoArea(p), wraps };
|
|
46432
|
+
}).filter(
|
|
46433
|
+
(p) => p !== null
|
|
46434
|
+
);
|
|
46435
|
+
if (polys.length <= 1 || polys.some((p) => p.wraps))
|
|
46436
|
+
return featureBbox(topo, geomId);
|
|
46437
|
+
const maxArea = Math.max(...polys.map((p) => p.area));
|
|
46438
|
+
const anchor = polys.find((p) => p.area === maxArea);
|
|
46439
|
+
const cluster = [
|
|
46440
|
+
[anchor.bbox[0][0], anchor.bbox[0][1]],
|
|
46441
|
+
[anchor.bbox[1][0], anchor.bbox[1][1]]
|
|
46442
|
+
];
|
|
46443
|
+
const remaining = polys.filter((p) => p !== anchor);
|
|
46444
|
+
let added = true;
|
|
46445
|
+
while (added) {
|
|
46446
|
+
added = false;
|
|
46447
|
+
for (let i = remaining.length - 1; i >= 0; i--) {
|
|
46448
|
+
const p = remaining[i];
|
|
46449
|
+
const near = bboxGap(p.bbox, cluster) <= DETACH_GAP_DEG;
|
|
46450
|
+
const large = p.area >= DETACH_AREA_FRAC * maxArea;
|
|
46451
|
+
if (near || large) {
|
|
46452
|
+
cluster[0][0] = Math.min(cluster[0][0], p.bbox[0][0]);
|
|
46453
|
+
cluster[0][1] = Math.min(cluster[0][1], p.bbox[0][1]);
|
|
46454
|
+
cluster[1][0] = Math.max(cluster[1][0], p.bbox[1][0]);
|
|
46455
|
+
cluster[1][1] = Math.max(cluster[1][1], p.bbox[1][1]);
|
|
46456
|
+
remaining.splice(i, 1);
|
|
46457
|
+
added = true;
|
|
46458
|
+
}
|
|
46459
|
+
}
|
|
46460
|
+
}
|
|
46461
|
+
return cluster;
|
|
46462
|
+
}
|
|
45874
46463
|
function unionExtent(boxes, points) {
|
|
45875
46464
|
const lats = [];
|
|
45876
46465
|
const lons = [];
|
|
@@ -45909,11 +46498,15 @@ function unionLongitudes(lons) {
|
|
|
45909
46498
|
}
|
|
45910
46499
|
return { west: pts[gapIdx], east: pts[gapIdx - 1] + 360 };
|
|
45911
46500
|
}
|
|
45912
|
-
var fold;
|
|
46501
|
+
var fold, adjacencyCache, EDGE_EPS, DETACH_GAP_DEG, DETACH_AREA_FRAC;
|
|
45913
46502
|
var init_geo = __esm({
|
|
45914
46503
|
"src/map/geo.ts"() {
|
|
45915
46504
|
"use strict";
|
|
45916
46505
|
fold = (s) => s.normalize("NFD").replace(/\p{Diacritic}/gu, "").toLowerCase().trim();
|
|
46506
|
+
adjacencyCache = /* @__PURE__ */ new WeakMap();
|
|
46507
|
+
EDGE_EPS = 1e-9;
|
|
46508
|
+
DETACH_GAP_DEG = 10;
|
|
46509
|
+
DETACH_AREA_FRAC = 0.25;
|
|
45917
46510
|
}
|
|
45918
46511
|
});
|
|
45919
46512
|
|
|
@@ -45931,6 +46524,12 @@ function looksUS(lat, lon) {
|
|
|
45931
46524
|
if (lat < 15 || lat > 72) return false;
|
|
45932
46525
|
return lon >= -180 && lon <= -64 || lon >= 172;
|
|
45933
46526
|
}
|
|
46527
|
+
function looksNorthAmericaNeighbor(lat, lon) {
|
|
46528
|
+
return lat >= 14 && lat <= 72 && lon >= -141 && lon <= -52;
|
|
46529
|
+
}
|
|
46530
|
+
function isWholeSphere(bb) {
|
|
46531
|
+
return bb[0][0] <= -179 && bb[1][0] >= 179 && bb[0][1] <= -89 && bb[1][1] >= 89;
|
|
46532
|
+
}
|
|
45934
46533
|
function resolveMap(parsed, data) {
|
|
45935
46534
|
const diagnostics = [...parsed.diagnostics];
|
|
45936
46535
|
const err = (line12, message, code) => {
|
|
@@ -45941,9 +46540,6 @@ function resolveMap(parsed, data) {
|
|
|
45941
46540
|
};
|
|
45942
46541
|
const result = {
|
|
45943
46542
|
title: parsed.title,
|
|
45944
|
-
...parsed.directives.subtitle !== void 0 && {
|
|
45945
|
-
subtitle: parsed.directives.subtitle
|
|
45946
|
-
},
|
|
45947
46543
|
...parsed.directives.caption !== void 0 && {
|
|
45948
46544
|
caption: parsed.directives.caption
|
|
45949
46545
|
},
|
|
@@ -45953,7 +46549,7 @@ function resolveMap(parsed, data) {
|
|
|
45953
46549
|
// renderer's job (step 4) — the resolver only carries `tags` + `tagGroups`
|
|
45954
46550
|
// through; it never resolves a tag value to a palette color (#10).
|
|
45955
46551
|
directives: { ...parsed.directives },
|
|
45956
|
-
basemaps: { world: "
|
|
46552
|
+
basemaps: { world: "detail", subdivisions: [] },
|
|
45957
46553
|
regions: [],
|
|
45958
46554
|
pois: [],
|
|
45959
46555
|
edges: [],
|
|
@@ -45962,7 +46558,8 @@ function resolveMap(parsed, data) {
|
|
|
45962
46558
|
[-180, -85],
|
|
45963
46559
|
[180, 85]
|
|
45964
46560
|
],
|
|
45965
|
-
projection: "
|
|
46561
|
+
projection: "equirectangular",
|
|
46562
|
+
poiFrameContainers: [],
|
|
45966
46563
|
diagnostics,
|
|
45967
46564
|
error: parsed.error
|
|
45968
46565
|
};
|
|
@@ -45972,7 +46569,10 @@ function resolveMap(parsed, data) {
|
|
|
45972
46569
|
...[...countryIndex.values()].map((v) => v.name),
|
|
45973
46570
|
...[...usStateIndex.values()].map((v) => v.name)
|
|
45974
46571
|
];
|
|
45975
|
-
const
|
|
46572
|
+
const localeRaw = parsed.directives.locale?.toUpperCase();
|
|
46573
|
+
const localeCountry = localeRaw ? localeRaw.split("-")[0] : void 0;
|
|
46574
|
+
const localeSubdivision = localeRaw && /^[A-Z]{2}-/.test(localeRaw) ? localeRaw : void 0;
|
|
46575
|
+
const usScoped = localeCountry === "US" || parsed.regions.some((r) => {
|
|
45976
46576
|
const f = fold(r.name);
|
|
45977
46577
|
return usStateIndex.has(f) && !countryIndex.has(f);
|
|
45978
46578
|
}) || parsed.regions.some(
|
|
@@ -46017,12 +46617,12 @@ function resolveMap(parsed, data) {
|
|
|
46017
46617
|
chosen = { ...inState, layer: "us-state" };
|
|
46018
46618
|
} else {
|
|
46019
46619
|
chosen = { ...inCountry, layer: "country" };
|
|
46620
|
+
warn(
|
|
46621
|
+
r.lineNumber,
|
|
46622
|
+
`"${r.name}" is both a country and a US state \u2014 resolved as ${chosen.layer} (${chosen.id}). Pin it with an ISO code (${inState.id} / ${inCountry.id}) or name + scope ("${r.name} US" / "${r.name} ${inCountry.id}").`,
|
|
46623
|
+
"W_MAP_REGION_AMBIGUOUS"
|
|
46624
|
+
);
|
|
46020
46625
|
}
|
|
46021
|
-
warn(
|
|
46022
|
-
r.lineNumber,
|
|
46023
|
-
`"${r.name}" is both a country and a US state \u2014 resolved as ${chosen.layer} (${chosen.id}). Pin it with an ISO code (${inState.id} / ${inCountry.id}) or name + scope ("${r.name} US" / "${r.name} ${inCountry.id}").`,
|
|
46024
|
-
"W_MAP_REGION_AMBIGUOUS"
|
|
46025
|
-
);
|
|
46026
46626
|
} else if (inState) {
|
|
46027
46627
|
chosen = { ...inState, layer: "us-state" };
|
|
46028
46628
|
} else if (inCountry) {
|
|
@@ -46046,6 +46646,7 @@ function resolveMap(parsed, data) {
|
|
|
46046
46646
|
name: chosen.name,
|
|
46047
46647
|
layer: chosen.layer,
|
|
46048
46648
|
...r.value !== void 0 && { value: r.value },
|
|
46649
|
+
...r.color !== void 0 && { color: r.color },
|
|
46049
46650
|
tags: r.tags,
|
|
46050
46651
|
meta: r.meta,
|
|
46051
46652
|
lineNumber: r.lineNumber
|
|
@@ -46122,7 +46723,7 @@ function resolveMap(parsed, data) {
|
|
|
46122
46723
|
if (!scope)
|
|
46123
46724
|
warn(
|
|
46124
46725
|
line12,
|
|
46125
|
-
`"${name}" is ambiguous \u2014 resolved to the most-populous match.`,
|
|
46726
|
+
`"${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.`,
|
|
46126
46727
|
"W_MAP_AMBIGUOUS_NAME"
|
|
46127
46728
|
);
|
|
46128
46729
|
}
|
|
@@ -46135,17 +46736,21 @@ function resolveMap(parsed, data) {
|
|
|
46135
46736
|
return fold(pos.name);
|
|
46136
46737
|
};
|
|
46137
46738
|
const poiCountries = [];
|
|
46138
|
-
let
|
|
46739
|
+
let anyUsPoi = false;
|
|
46740
|
+
let anyNonNaPoi = false;
|
|
46139
46741
|
const noteCountry = (iso) => {
|
|
46140
46742
|
if (iso) {
|
|
46141
46743
|
poiCountries.push(iso);
|
|
46142
|
-
if (iso
|
|
46744
|
+
if (iso === "US") anyUsPoi = true;
|
|
46745
|
+
if (iso !== "US" && iso !== "CA" && iso !== "MX") anyNonNaPoi = true;
|
|
46143
46746
|
}
|
|
46144
46747
|
};
|
|
46145
46748
|
const deferred = [];
|
|
46146
46749
|
for (const p of parsed.pois) {
|
|
46147
46750
|
if (p.pos.kind === "coords") {
|
|
46148
|
-
if (
|
|
46751
|
+
if (looksUS(p.pos.lat, p.pos.lon)) anyUsPoi = true;
|
|
46752
|
+
else if (!looksNorthAmericaNeighbor(p.pos.lat, p.pos.lon))
|
|
46753
|
+
anyNonNaPoi = true;
|
|
46149
46754
|
addResolvedPoi(p.pos.lat, p.pos.lon, p);
|
|
46150
46755
|
continue;
|
|
46151
46756
|
}
|
|
@@ -46163,14 +46768,15 @@ function resolveMap(parsed, data) {
|
|
|
46163
46768
|
deferred.push(p);
|
|
46164
46769
|
}
|
|
46165
46770
|
}
|
|
46166
|
-
const inferredCountry =
|
|
46771
|
+
const inferredCountry = localeCountry ?? mostCommonCountry(regions, poiCountries) ?? void 0;
|
|
46772
|
+
const inferredScope = localeSubdivision ?? inferredCountry;
|
|
46167
46773
|
for (const p of deferred) {
|
|
46168
46774
|
if (p.pos.kind !== "name") continue;
|
|
46169
46775
|
const got = lookupName(
|
|
46170
46776
|
p.pos.name,
|
|
46171
46777
|
p.pos.scope,
|
|
46172
46778
|
p.lineNumber,
|
|
46173
|
-
|
|
46779
|
+
inferredScope,
|
|
46174
46780
|
true
|
|
46175
46781
|
);
|
|
46176
46782
|
if (got.kind === "ok") {
|
|
@@ -46187,6 +46793,7 @@ function resolveMap(parsed, data) {
|
|
|
46187
46793
|
lat,
|
|
46188
46794
|
lon,
|
|
46189
46795
|
...p.label !== void 0 && { label: p.label },
|
|
46796
|
+
...p.color !== void 0 && { color: p.color },
|
|
46190
46797
|
tags: p.tags,
|
|
46191
46798
|
meta: p.meta,
|
|
46192
46799
|
lineNumber: p.lineNumber
|
|
@@ -46239,7 +46846,8 @@ function resolveMap(parsed, data) {
|
|
|
46239
46846
|
const meta = sizeValue !== void 0 ? { value: sizeValue } : {};
|
|
46240
46847
|
if (pos.kind === "coords") {
|
|
46241
46848
|
const id = alias ? fold(alias) : `@${pos.lat},${pos.lon}`;
|
|
46242
|
-
if (
|
|
46849
|
+
if (looksUS(pos.lat, pos.lon)) anyUsPoi = true;
|
|
46850
|
+
else if (!looksNorthAmericaNeighbor(pos.lat, pos.lon)) anyNonNaPoi = true;
|
|
46243
46851
|
if (!registry.has(id)) {
|
|
46244
46852
|
registerPoi(
|
|
46245
46853
|
id,
|
|
@@ -46262,7 +46870,7 @@ function resolveMap(parsed, data) {
|
|
|
46262
46870
|
if (registry.has(f)) return f;
|
|
46263
46871
|
const aliased = declaredByName.get(f);
|
|
46264
46872
|
if (aliased) return aliased;
|
|
46265
|
-
const got = lookupName(pos.name, pos.scope, line12,
|
|
46873
|
+
const got = lookupName(pos.name, pos.scope, line12, inferredScope, true);
|
|
46266
46874
|
if (got.kind !== "ok") return null;
|
|
46267
46875
|
noteCountry(got.iso);
|
|
46268
46876
|
registerPoi(
|
|
@@ -46319,9 +46927,12 @@ function resolveMap(parsed, data) {
|
|
|
46319
46927
|
}
|
|
46320
46928
|
routes.push({ stopIds, legs, lineNumber: rt.lineNumber });
|
|
46321
46929
|
}
|
|
46930
|
+
const hasUsContent = usSubdivisionReferenced || anyUsPoi || localeCountry === "US";
|
|
46931
|
+
const usOriented = !anyNonNaPoi && !regions.some(
|
|
46932
|
+
(r) => r.layer === "country" && !["US", "CA", "MX"].includes(r.iso)
|
|
46933
|
+
) && hasUsContent;
|
|
46322
46934
|
const subdivisions = [];
|
|
46323
|
-
if (usSubdivisionReferenced ||
|
|
46324
|
-
subdivisions.push("us-states");
|
|
46935
|
+
if (usSubdivisionReferenced || usOriented) subdivisions.push("us-states");
|
|
46325
46936
|
const regionBoxes = [];
|
|
46326
46937
|
for (const ref of referencedRegionIds) {
|
|
46327
46938
|
const bb = featureBbox(data.usStates, ref.id);
|
|
@@ -46329,7 +46940,7 @@ function resolveMap(parsed, data) {
|
|
|
46329
46940
|
}
|
|
46330
46941
|
for (const r of regions) {
|
|
46331
46942
|
if (r.layer === "country") {
|
|
46332
|
-
const bb =
|
|
46943
|
+
const bb = featureBboxPrimary(data.worldCoarse, r.iso);
|
|
46333
46944
|
if (bb) regionBoxes.push(bb);
|
|
46334
46945
|
}
|
|
46335
46946
|
}
|
|
@@ -46339,23 +46950,56 @@ function resolveMap(parsed, data) {
|
|
|
46339
46950
|
[-180, -85],
|
|
46340
46951
|
[180, 85]
|
|
46341
46952
|
];
|
|
46342
|
-
|
|
46953
|
+
const basePad = regions.length > 0 ? REGION_PAD_FRACTION : PAD_FRACTION;
|
|
46954
|
+
let extent2 = unioned ? pad(unioned, basePad) : DEFAULT_EXTENT;
|
|
46955
|
+
const isPoiOnly = pois.length > 0 && regions.length === 0;
|
|
46956
|
+
const containerRegionIds = [];
|
|
46957
|
+
if (isPoiOnly) {
|
|
46958
|
+
const countries = decodeFeatures(data.worldDetail);
|
|
46959
|
+
const states = decodeFeatures(data.usStates);
|
|
46960
|
+
const seen = /* @__PURE__ */ new Set();
|
|
46961
|
+
const containerBoxes = [];
|
|
46962
|
+
for (const p of pois) {
|
|
46963
|
+
const { country, state } = regionAt([p.lon, p.lat], countries, states);
|
|
46964
|
+
const id = state?.iso ?? country?.iso;
|
|
46965
|
+
if (!id || seen.has(id)) continue;
|
|
46966
|
+
seen.add(id);
|
|
46967
|
+
containerRegionIds.push(id);
|
|
46968
|
+
const bb = state ? featureBbox(data.usStates, id) : featureBboxPrimary(data.worldCoarse, id);
|
|
46969
|
+
if (bb && !isWholeSphere(bb)) containerBoxes.push(bb);
|
|
46970
|
+
}
|
|
46971
|
+
const containerUnion = unionExtent(containerBoxes, points);
|
|
46972
|
+
if (containerUnion) extent2 = pad(containerUnion, PAD_FRACTION);
|
|
46973
|
+
}
|
|
46974
|
+
if (isPoiOnly) {
|
|
46975
|
+
const cx = (extent2[0][0] + extent2[1][0]) / 2;
|
|
46976
|
+
const cy = (extent2[0][1] + extent2[1][1]) / 2;
|
|
46977
|
+
const lon = extent2[1][0] - extent2[0][0];
|
|
46978
|
+
const lat = extent2[1][1] - extent2[0][1];
|
|
46979
|
+
const longer = Math.max(lon, lat);
|
|
46980
|
+
if (longer > 0 && longer < POI_ZOOM_FLOOR_DEG) {
|
|
46981
|
+
const k = POI_ZOOM_FLOOR_DEG / longer;
|
|
46982
|
+
const halfLon = lon * k / 2;
|
|
46983
|
+
const halfLat = lat * k / 2;
|
|
46984
|
+
extent2 = [
|
|
46985
|
+
[cx - halfLon, cy - halfLat],
|
|
46986
|
+
[cx + halfLon, cy + halfLat]
|
|
46987
|
+
];
|
|
46988
|
+
}
|
|
46989
|
+
}
|
|
46343
46990
|
const lonSpan = extent2[1][0] - extent2[0][0];
|
|
46344
46991
|
const latSpan = extent2[1][1] - extent2[0][1];
|
|
46345
46992
|
const span = Math.max(lonSpan, latSpan);
|
|
46346
|
-
const
|
|
46993
|
+
const maxAbsLat = Math.max(Math.abs(extent2[0][1]), Math.abs(extent2[1][1]));
|
|
46347
46994
|
let projection;
|
|
46348
|
-
|
|
46349
|
-
|
|
46350
|
-
|
|
46351
|
-
} else if (usDominant) {
|
|
46995
|
+
if (isPoiOnly && usOriented && lonSpan < US_NATIONAL_LON_SPAN) {
|
|
46996
|
+
projection = "mercator";
|
|
46997
|
+
} else if (usOriented) {
|
|
46352
46998
|
projection = "albers-usa";
|
|
46353
|
-
} else if (span > WORLD_SPAN) {
|
|
46999
|
+
} else if (span > WORLD_SPAN || maxAbsLat > MERCATOR_MAX_LAT) {
|
|
46354
47000
|
projection = "equirectangular";
|
|
46355
|
-
} else if (span < MERCATOR_MAX_SPAN) {
|
|
46356
|
-
projection = "mercator";
|
|
46357
47001
|
} else {
|
|
46358
|
-
projection = "
|
|
47002
|
+
projection = "mercator";
|
|
46359
47003
|
}
|
|
46360
47004
|
if (lonSpan >= 180) {
|
|
46361
47005
|
extent2 = [
|
|
@@ -46368,11 +47012,20 @@ function resolveMap(parsed, data) {
|
|
|
46368
47012
|
result.edges = edges;
|
|
46369
47013
|
result.routes = routes;
|
|
46370
47014
|
result.basemaps = {
|
|
46371
|
-
|
|
47015
|
+
// Tier is intentionally pinned to detail (50m) at ALL scales. Diagrammo maps
|
|
47016
|
+
// are presentational (palette tints, relief hachures, POI hubs), not
|
|
47017
|
+
// survey-grade — recognizability > generalization: 110m coarse drops the
|
|
47018
|
+
// Italian boot to a stump at world scale. `WORLD_SPAN` lives on only for the
|
|
47019
|
+
// projection decision (the `usOriented`/`span > WORLD_SPAN` chain above); it
|
|
47020
|
+
// no longer gates basemap resolution.
|
|
47021
|
+
// `worldCoarse` is still loaded — it's the authoritative name/bbox index
|
|
47022
|
+
// (featureIndex, featureBboxPrimary), not dead code.
|
|
47023
|
+
world: "detail",
|
|
46372
47024
|
subdivisions
|
|
46373
47025
|
};
|
|
46374
47026
|
result.extent = extent2;
|
|
46375
47027
|
result.projection = projection;
|
|
47028
|
+
result.poiFrameContainers = containerRegionIds;
|
|
46376
47029
|
result.error = parsed.error ?? firstError(diagnostics);
|
|
46377
47030
|
return result;
|
|
46378
47031
|
}
|
|
@@ -46409,17 +47062,20 @@ function firstError(diags) {
|
|
|
46409
47062
|
const e = diags.find((d) => d.severity === "error");
|
|
46410
47063
|
return e ? formatDgmoError(e) : null;
|
|
46411
47064
|
}
|
|
46412
|
-
var WORLD_SPAN,
|
|
47065
|
+
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;
|
|
46413
47066
|
var init_resolver2 = __esm({
|
|
46414
47067
|
"src/map/resolver.ts"() {
|
|
46415
47068
|
"use strict";
|
|
46416
47069
|
init_diagnostics();
|
|
46417
47070
|
init_geo();
|
|
46418
47071
|
WORLD_SPAN = 90;
|
|
46419
|
-
|
|
47072
|
+
MERCATOR_MAX_LAT = 80;
|
|
46420
47073
|
PAD_FRACTION = 0.05;
|
|
47074
|
+
REGION_PAD_FRACTION = 0.12;
|
|
46421
47075
|
WORLD_LAT_SOUTH = -58;
|
|
46422
47076
|
WORLD_LAT_NORTH = 78;
|
|
47077
|
+
POI_ZOOM_FLOOR_DEG = 7;
|
|
47078
|
+
US_NATIONAL_LON_SPAN = 48;
|
|
46423
47079
|
REGION_ALIASES = {
|
|
46424
47080
|
// Common everyday names → the Natural-Earth display name actually shipped.
|
|
46425
47081
|
"united states": "united states of america",
|
|
@@ -46497,111 +47153,269 @@ var init_resolver2 = __esm({
|
|
|
46497
47153
|
}
|
|
46498
47154
|
});
|
|
46499
47155
|
|
|
46500
|
-
// src/map/
|
|
46501
|
-
|
|
46502
|
-
|
|
46503
|
-
|
|
47156
|
+
// src/map/colorize.ts
|
|
47157
|
+
function assignColors(isos, adjacency) {
|
|
47158
|
+
const sorted = [...isos].sort();
|
|
47159
|
+
const byIso = /* @__PURE__ */ new Map();
|
|
47160
|
+
let maxIndex = -1;
|
|
47161
|
+
for (const iso of sorted) {
|
|
47162
|
+
const taken = /* @__PURE__ */ new Set();
|
|
47163
|
+
for (const n of adjacency.get(iso) ?? []) {
|
|
47164
|
+
const c = byIso.get(n);
|
|
47165
|
+
if (c !== void 0) taken.add(c);
|
|
47166
|
+
}
|
|
47167
|
+
let h = 0;
|
|
47168
|
+
while (taken.has(h)) h++;
|
|
47169
|
+
byIso.set(iso, h);
|
|
47170
|
+
if (h > maxIndex) maxIndex = h;
|
|
47171
|
+
}
|
|
47172
|
+
return { byIso, huesNeeded: maxIndex + 1 };
|
|
47173
|
+
}
|
|
47174
|
+
var init_colorize = __esm({
|
|
47175
|
+
"src/map/colorize.ts"() {
|
|
47176
|
+
"use strict";
|
|
47177
|
+
}
|
|
46504
47178
|
});
|
|
46505
|
-
|
|
46506
|
-
|
|
46507
|
-
|
|
46508
|
-
|
|
46509
|
-
|
|
46510
|
-
|
|
46511
|
-
return
|
|
46512
|
-
}
|
|
46513
|
-
|
|
46514
|
-
|
|
46515
|
-
|
|
46516
|
-
|
|
46517
|
-
|
|
46518
|
-
|
|
46519
|
-
|
|
46520
|
-
|
|
46521
|
-
|
|
46522
|
-
|
|
47179
|
+
|
|
47180
|
+
// src/map/context-labels.ts
|
|
47181
|
+
function tierBand(maxSpanDeg) {
|
|
47182
|
+
if (maxSpanDeg >= 90) return "world";
|
|
47183
|
+
if (maxSpanDeg >= 20) return "continental";
|
|
47184
|
+
if (maxSpanDeg >= 5) return "regional";
|
|
47185
|
+
return "local";
|
|
47186
|
+
}
|
|
47187
|
+
function labelBudget(width, height, band) {
|
|
47188
|
+
const bandCap = {
|
|
47189
|
+
world: 6,
|
|
47190
|
+
continental: 5,
|
|
47191
|
+
regional: 4,
|
|
47192
|
+
local: 3
|
|
47193
|
+
};
|
|
47194
|
+
const area2 = Math.floor(Math.sqrt(Math.max(0, width * height)) / 150);
|
|
47195
|
+
return Math.max(0, Math.min(area2, bandCap[band]));
|
|
47196
|
+
}
|
|
47197
|
+
function waterEligible(tier, kind, band) {
|
|
47198
|
+
switch (band) {
|
|
47199
|
+
case "world":
|
|
47200
|
+
return tier <= 1 && (kind === "ocean" || kind === "sea");
|
|
47201
|
+
case "continental":
|
|
47202
|
+
return tier <= 2;
|
|
47203
|
+
case "regional":
|
|
47204
|
+
return tier <= 3;
|
|
47205
|
+
case "local":
|
|
47206
|
+
return tier <= 4;
|
|
47207
|
+
}
|
|
47208
|
+
}
|
|
47209
|
+
function insideViewport(p, width, height) {
|
|
47210
|
+
return !!p && Number.isFinite(p[0]) && Number.isFinite(p[1]) && p[0] >= 0 && p[0] <= width && p[1] >= 0 && p[1] <= height;
|
|
47211
|
+
}
|
|
47212
|
+
function labelWidth(text, letterSpacing) {
|
|
47213
|
+
const spacing = letterSpacing > 0 ? Math.max(0, text.length - 1) * letterSpacing : 0;
|
|
47214
|
+
return measureLegendText(text, FONT) + spacing + 2 * PADX;
|
|
47215
|
+
}
|
|
47216
|
+
function wrapLabel2(text, letterSpacing) {
|
|
47217
|
+
const words = text.split(/\s+/).filter(Boolean);
|
|
47218
|
+
if (words.length <= 1) return [text];
|
|
47219
|
+
const maxLines = words.length >= 4 ? 3 : 2;
|
|
47220
|
+
const n = words.length;
|
|
47221
|
+
let best = null;
|
|
47222
|
+
for (let mask = 0; mask < 1 << n - 1; mask++) {
|
|
47223
|
+
const lines = [];
|
|
47224
|
+
let cur = [words[0]];
|
|
47225
|
+
for (let i = 1; i < n; i++) {
|
|
47226
|
+
if (mask & 1 << i - 1) {
|
|
47227
|
+
lines.push(cur.join(" "));
|
|
47228
|
+
cur = [words[i]];
|
|
47229
|
+
} else cur.push(words[i]);
|
|
46523
47230
|
}
|
|
47231
|
+
lines.push(cur.join(" "));
|
|
47232
|
+
if (lines.length > maxLines) continue;
|
|
47233
|
+
const cost = Math.round(
|
|
47234
|
+
Math.max(...lines.map((l) => labelWidth(l, letterSpacing)))
|
|
47235
|
+
);
|
|
47236
|
+
const head = labelWidth(lines[0], letterSpacing);
|
|
47237
|
+
if (!best || cost < best.cost || cost === best.cost && lines.length < best.lines.length || cost === best.cost && lines.length === best.lines.length && head > best.head)
|
|
47238
|
+
best = { lines, cost, head };
|
|
46524
47239
|
}
|
|
46525
|
-
|
|
46526
|
-
`map data assets not found near ${baseDir} (looked in ${CANDIDATE_DIRS.join(", ")}). Run \`pnpm build:map-data\` and \`pnpm build\`.`
|
|
46527
|
-
);
|
|
47240
|
+
return best?.lines ?? [text];
|
|
46528
47241
|
}
|
|
46529
|
-
function
|
|
46530
|
-
const
|
|
46531
|
-
|
|
46532
|
-
|
|
46533
|
-
}
|
|
46534
|
-
return data;
|
|
47242
|
+
function rectAround(cx, cy, lines, letterSpacing) {
|
|
47243
|
+
const w = Math.max(...lines.map((l) => labelWidth(l, letterSpacing)));
|
|
47244
|
+
const h = (lines.length - 1) * LINE_HEIGHT + FONT + 2 * PADY;
|
|
47245
|
+
return { x: cx - w / 2, y: cy - h / 2, w, h };
|
|
46535
47246
|
}
|
|
46536
|
-
function
|
|
46537
|
-
|
|
46538
|
-
const url = import.meta.url;
|
|
46539
|
-
if (url) return nb.dirname(nb.fileURLToPath(url));
|
|
46540
|
-
} catch {
|
|
46541
|
-
}
|
|
46542
|
-
if (typeof __dirname !== "undefined") return __dirname;
|
|
46543
|
-
return process.cwd();
|
|
47247
|
+
function rectFits(r, width, height) {
|
|
47248
|
+
return r.x >= 0 && r.y >= 0 && r.x + r.w <= width && r.y + r.h <= height;
|
|
46544
47249
|
}
|
|
46545
|
-
function
|
|
46546
|
-
|
|
46547
|
-
|
|
46548
|
-
|
|
46549
|
-
|
|
46550
|
-
|
|
46551
|
-
|
|
46552
|
-
|
|
46553
|
-
|
|
46554
|
-
|
|
46555
|
-
|
|
46556
|
-
|
|
46557
|
-
|
|
46558
|
-
|
|
46559
|
-
|
|
46560
|
-
|
|
46561
|
-
|
|
46562
|
-
|
|
46563
|
-
|
|
46564
|
-
|
|
46565
|
-
|
|
46566
|
-
|
|
46567
|
-
|
|
46568
|
-
|
|
46569
|
-
|
|
46570
|
-
|
|
46571
|
-
|
|
46572
|
-
|
|
46573
|
-
|
|
46574
|
-
|
|
46575
|
-
|
|
46576
|
-
|
|
46577
|
-
|
|
47250
|
+
function overlapsPadded(a, b, pad2) {
|
|
47251
|
+
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;
|
|
47252
|
+
}
|
|
47253
|
+
function placeContextLabels(args) {
|
|
47254
|
+
const {
|
|
47255
|
+
projection,
|
|
47256
|
+
dLonSpan,
|
|
47257
|
+
dLatSpan,
|
|
47258
|
+
width,
|
|
47259
|
+
height,
|
|
47260
|
+
waterBodies,
|
|
47261
|
+
countries,
|
|
47262
|
+
palette,
|
|
47263
|
+
project,
|
|
47264
|
+
collides,
|
|
47265
|
+
overLand
|
|
47266
|
+
} = args;
|
|
47267
|
+
void projection;
|
|
47268
|
+
const band = tierBand(Math.max(dLonSpan, dLatSpan));
|
|
47269
|
+
const budget = labelBudget(width, height, band);
|
|
47270
|
+
if (budget <= 0) return [];
|
|
47271
|
+
const waterColor = mix(palette.colors.blue, palette.textMuted, 50);
|
|
47272
|
+
const countryColor = palette.textMuted;
|
|
47273
|
+
const haloColor = palette.bg;
|
|
47274
|
+
const candidates = [];
|
|
47275
|
+
const center = [width / 2, height / 2];
|
|
47276
|
+
for (const e of waterBodies?.entries ?? []) {
|
|
47277
|
+
const [lat, lon, name, tier, kind, alt] = e;
|
|
47278
|
+
if (!waterEligible(tier, kind, band)) continue;
|
|
47279
|
+
const wlines = wrapLabel2(name, WATER_LETTER_SPACING);
|
|
47280
|
+
const anchorsLngLat = [[lon, lat]];
|
|
47281
|
+
for (const a of alt ?? []) anchorsLngLat.push([a[1], a[0]]);
|
|
47282
|
+
let best = null;
|
|
47283
|
+
let bestD = Infinity;
|
|
47284
|
+
let nearestProj = null;
|
|
47285
|
+
let nearestProjD = Infinity;
|
|
47286
|
+
for (const [aLon, aLat] of anchorsLngLat) {
|
|
47287
|
+
const p = project(aLon, aLat);
|
|
47288
|
+
if (!p || !Number.isFinite(p[0]) || !Number.isFinite(p[1])) continue;
|
|
47289
|
+
const d = (p[0] - center[0]) ** 2 + (p[1] - center[1]) ** 2;
|
|
47290
|
+
if (d < nearestProjD) {
|
|
47291
|
+
nearestProjD = d;
|
|
47292
|
+
nearestProj = p;
|
|
47293
|
+
}
|
|
47294
|
+
if (!insideViewport(p, width, height)) continue;
|
|
47295
|
+
if (d < bestD) {
|
|
47296
|
+
bestD = d;
|
|
47297
|
+
best = p;
|
|
47298
|
+
}
|
|
47299
|
+
}
|
|
47300
|
+
if (!best && tier === 0 && nearestProj) {
|
|
47301
|
+
const overX = Math.max(0, -nearestProj[0], nearestProj[0] - width);
|
|
47302
|
+
const overY = Math.max(0, -nearestProj[1], nearestProj[1] - height);
|
|
47303
|
+
if (overX <= width * EDGE_CLAMP_OVERSHOOT && overY <= height * EDGE_CLAMP_OVERSHOOT) {
|
|
47304
|
+
const halfW = Math.max(...wlines.map((l) => labelWidth(l, WATER_LETTER_SPACING))) / 2;
|
|
47305
|
+
const halfH = ((wlines.length - 1) * LINE_HEIGHT + FONT + 2 * PADY) / 2;
|
|
47306
|
+
const m = EDGE_CLAMP_MARGIN;
|
|
47307
|
+
best = [
|
|
47308
|
+
Math.min(Math.max(nearestProj[0], halfW + m), width - halfW - m),
|
|
47309
|
+
Math.min(Math.max(nearestProj[1], halfH + m), height - halfH - m)
|
|
47310
|
+
];
|
|
47311
|
+
}
|
|
47312
|
+
}
|
|
47313
|
+
if (!best) continue;
|
|
47314
|
+
candidates.push({
|
|
47315
|
+
text: name,
|
|
47316
|
+
lines: wlines,
|
|
47317
|
+
cx: best[0],
|
|
47318
|
+
cy: best[1],
|
|
47319
|
+
italic: true,
|
|
47320
|
+
letterSpacing: WATER_LETTER_SPACING,
|
|
47321
|
+
color: waterColor,
|
|
47322
|
+
// Water before any country (×1000), then by tier, then kind, then name.
|
|
47323
|
+
sort: tier * 10 + KIND_ORDER[kind]
|
|
46578
47324
|
});
|
|
46579
|
-
}
|
|
46580
|
-
|
|
46581
|
-
|
|
46582
|
-
|
|
46583
|
-
|
|
47325
|
+
}
|
|
47326
|
+
const ranked = countries.map((c) => {
|
|
47327
|
+
const [x0, y0, x1, y1] = c.bbox;
|
|
47328
|
+
const w = x1 - x0;
|
|
47329
|
+
const h = y1 - y0;
|
|
47330
|
+
return { c, w, h, area: w * h };
|
|
47331
|
+
}).filter((r) => Number.isFinite(r.area) && r.area > 0).sort((a, b) => b.area - a.area);
|
|
47332
|
+
let ci = 0;
|
|
47333
|
+
for (const r of ranked) {
|
|
47334
|
+
const { c, w, h } = r;
|
|
47335
|
+
if (w > width * 0.66 || h > height * 0.66) continue;
|
|
47336
|
+
if (!insideViewport(c.anchor, width, height)) continue;
|
|
47337
|
+
const text = c.name;
|
|
47338
|
+
const tw = labelWidth(text, 0);
|
|
47339
|
+
if (tw > w || FONT + 2 * PADY > h) continue;
|
|
47340
|
+
candidates.push({
|
|
47341
|
+
text,
|
|
47342
|
+
lines: [text],
|
|
47343
|
+
cx: c.anchor[0],
|
|
47344
|
+
cy: c.anchor[1],
|
|
47345
|
+
italic: false,
|
|
47346
|
+
letterSpacing: 0,
|
|
47347
|
+
color: countryColor,
|
|
47348
|
+
// Always after every water body (+1e6); larger area = earlier.
|
|
47349
|
+
sort: 1e6 + ci++
|
|
47350
|
+
});
|
|
47351
|
+
}
|
|
47352
|
+
candidates.sort((a, b) => a.sort - b.sort);
|
|
47353
|
+
const placed = [];
|
|
47354
|
+
const placedRects = [];
|
|
47355
|
+
for (const cand of candidates) {
|
|
47356
|
+
if (placed.length >= budget) break;
|
|
47357
|
+
const rect = rectAround(cand.cx, cand.cy, cand.lines, cand.letterSpacing);
|
|
47358
|
+
if (!rectFits(rect, width, height)) continue;
|
|
47359
|
+
if (cand.italic && overLand) {
|
|
47360
|
+
const inset = 2;
|
|
47361
|
+
const top = cand.cy - (cand.lines.length - 1) / 2 * LINE_HEIGHT;
|
|
47362
|
+
const touchesLand = cand.lines.some((line12, li) => {
|
|
47363
|
+
const lw = labelWidth(line12, cand.letterSpacing);
|
|
47364
|
+
const x0 = cand.cx - lw / 2 + inset;
|
|
47365
|
+
const x1 = cand.cx + lw / 2 - inset;
|
|
47366
|
+
const xs = [x0, (x0 + cand.cx) / 2, cand.cx, (cand.cx + x1) / 2, x1];
|
|
47367
|
+
const base = top + li * LINE_HEIGHT;
|
|
47368
|
+
return [base, base - FONT * 0.4, base - FONT * 0.8].some(
|
|
47369
|
+
(y) => xs.some((x) => overLand(x, y))
|
|
47370
|
+
);
|
|
47371
|
+
});
|
|
47372
|
+
if (touchesLand) continue;
|
|
47373
|
+
}
|
|
47374
|
+
if (collides(rect)) continue;
|
|
47375
|
+
if (placedRects.some((r) => overlapsPadded(rect, r, CONTEXT_PAD))) continue;
|
|
47376
|
+
placedRects.push(rect);
|
|
47377
|
+
placed.push({
|
|
47378
|
+
x: cand.cx,
|
|
47379
|
+
y: cand.cy,
|
|
47380
|
+
text: cand.text,
|
|
47381
|
+
anchor: "middle",
|
|
47382
|
+
color: cand.color,
|
|
47383
|
+
// No halo: the bg-coloured outline reads as a ghost box behind the text
|
|
47384
|
+
// over the tinted water/land. Context labels are muted enough to sit
|
|
47385
|
+
// cleanly on the basemap without one.
|
|
47386
|
+
halo: false,
|
|
47387
|
+
haloColor,
|
|
47388
|
+
italic: cand.italic,
|
|
47389
|
+
letterSpacing: cand.letterSpacing,
|
|
47390
|
+
...cand.lines.length > 1 ? { lines: cand.lines } : {},
|
|
47391
|
+
lineNumber: 0
|
|
47392
|
+
});
|
|
47393
|
+
}
|
|
47394
|
+
return placed;
|
|
46584
47395
|
}
|
|
46585
|
-
var
|
|
46586
|
-
var
|
|
46587
|
-
"src/map/
|
|
47396
|
+
var FONT, LINE_HEIGHT, PADX, PADY, WATER_LETTER_SPACING, CONTEXT_PAD, EDGE_CLAMP_MARGIN, EDGE_CLAMP_OVERSHOOT, KIND_ORDER;
|
|
47397
|
+
var init_context_labels = __esm({
|
|
47398
|
+
"src/map/context-labels.ts"() {
|
|
46588
47399
|
"use strict";
|
|
46589
|
-
|
|
46590
|
-
|
|
46591
|
-
|
|
46592
|
-
|
|
46593
|
-
|
|
46594
|
-
|
|
46595
|
-
|
|
46596
|
-
|
|
46597
|
-
|
|
47400
|
+
init_color_utils();
|
|
47401
|
+
init_legend_constants();
|
|
47402
|
+
FONT = 11;
|
|
47403
|
+
LINE_HEIGHT = FONT + 2;
|
|
47404
|
+
PADX = 4;
|
|
47405
|
+
PADY = 3;
|
|
47406
|
+
WATER_LETTER_SPACING = 1.5;
|
|
47407
|
+
CONTEXT_PAD = 4;
|
|
47408
|
+
EDGE_CLAMP_MARGIN = 8;
|
|
47409
|
+
EDGE_CLAMP_OVERSHOOT = 0.35;
|
|
47410
|
+
KIND_ORDER = {
|
|
47411
|
+
ocean: 0,
|
|
47412
|
+
sea: 1,
|
|
47413
|
+
gulf: 2,
|
|
47414
|
+
bay: 3,
|
|
47415
|
+
strait: 4,
|
|
47416
|
+
channel: 5,
|
|
47417
|
+
sound: 6
|
|
46598
47418
|
};
|
|
46599
|
-
CANDIDATE_DIRS = [
|
|
46600
|
-
"./data",
|
|
46601
|
-
"./map-data",
|
|
46602
|
-
"../map-data",
|
|
46603
|
-
"../src/map/data"
|
|
46604
|
-
];
|
|
46605
47419
|
}
|
|
46606
47420
|
});
|
|
46607
47421
|
|
|
@@ -46609,6 +47423,7 @@ var init_load_data = __esm({
|
|
|
46609
47423
|
import {
|
|
46610
47424
|
geoPath,
|
|
46611
47425
|
geoNaturalEarth1,
|
|
47426
|
+
geoEqualEarth,
|
|
46612
47427
|
geoEquirectangular,
|
|
46613
47428
|
geoConicEqualArea,
|
|
46614
47429
|
geoMercator,
|
|
@@ -46620,12 +47435,34 @@ function geomObject2(topo) {
|
|
|
46620
47435
|
const key = Object.keys(topo.objects)[0];
|
|
46621
47436
|
return topo.objects[key];
|
|
46622
47437
|
}
|
|
47438
|
+
function mergeFeatures(a, b) {
|
|
47439
|
+
const polysOf = (f) => {
|
|
47440
|
+
const g = f.geometry;
|
|
47441
|
+
if (!g) return null;
|
|
47442
|
+
if (g.type === "Polygon") return [g.coordinates];
|
|
47443
|
+
if (g.type === "MultiPolygon") return g.coordinates;
|
|
47444
|
+
return null;
|
|
47445
|
+
};
|
|
47446
|
+
const pa = polysOf(a);
|
|
47447
|
+
const pb = polysOf(b);
|
|
47448
|
+
if (!pa || !pb) return a;
|
|
47449
|
+
return {
|
|
47450
|
+
...a,
|
|
47451
|
+
geometry: { type: "MultiPolygon", coordinates: [...pa, ...pb] }
|
|
47452
|
+
};
|
|
47453
|
+
}
|
|
46623
47454
|
function decodeLayer(topo) {
|
|
47455
|
+
const cached = decodeCache.get(topo);
|
|
47456
|
+
if (cached) return cached;
|
|
46624
47457
|
const out = /* @__PURE__ */ new Map();
|
|
46625
47458
|
for (const g of geomObject2(topo).geometries) {
|
|
46626
47459
|
const f = feature2(topo, g);
|
|
46627
|
-
|
|
47460
|
+
if (!f.geometry) continue;
|
|
47461
|
+
const tagged = { ...f, id: g.id };
|
|
47462
|
+
const existing = out.get(g.id);
|
|
47463
|
+
out.set(g.id, existing ? mergeFeatures(existing, tagged) : tagged);
|
|
46628
47464
|
}
|
|
47465
|
+
decodeCache.set(topo, out);
|
|
46629
47466
|
return out;
|
|
46630
47467
|
}
|
|
46631
47468
|
function projectionFor(family) {
|
|
@@ -46634,38 +47471,35 @@ function projectionFor(family) {
|
|
|
46634
47471
|
return usConusProjection();
|
|
46635
47472
|
case "mercator":
|
|
46636
47473
|
return geoMercator();
|
|
47474
|
+
case "equal-earth":
|
|
47475
|
+
return geoEqualEarth();
|
|
47476
|
+
case "equirectangular":
|
|
47477
|
+
return geoEquirectangular();
|
|
46637
47478
|
case "natural-earth":
|
|
46638
47479
|
return geoNaturalEarth1();
|
|
46639
|
-
case "equirectangular":
|
|
46640
47480
|
default:
|
|
46641
47481
|
return geoEquirectangular();
|
|
46642
47482
|
}
|
|
46643
47483
|
}
|
|
46644
|
-
function mapBackgroundColor(palette, isDark = false,
|
|
46645
|
-
|
|
46646
|
-
|
|
46647
|
-
|
|
46648
|
-
|
|
46649
|
-
|
|
46650
|
-
);
|
|
46651
|
-
return mix(palette.colors.blue, palette.bg, WATER_TINT);
|
|
47484
|
+
function mapBackgroundColor(palette, isDark = false, _dataActive = false) {
|
|
47485
|
+
return mix(
|
|
47486
|
+
palette.colors.blue,
|
|
47487
|
+
palette.bg,
|
|
47488
|
+
isDark ? WATER_TINT_DARK : WATER_TINT_LIGHT
|
|
47489
|
+
);
|
|
46652
47490
|
}
|
|
46653
|
-
function mapNeutralLandColor(palette, isDark,
|
|
46654
|
-
if (dataActive)
|
|
46655
|
-
return isDark ? mix(palette.colors.gray, palette.bg, MUTED_LAND_DARK) : palette.bg;
|
|
47491
|
+
function mapNeutralLandColor(palette, isDark, _dataActive = false) {
|
|
46656
47492
|
return mix(
|
|
46657
47493
|
palette.colors.green,
|
|
46658
47494
|
palette.bg,
|
|
46659
47495
|
isDark ? LAND_TINT_DARK : LAND_TINT_LIGHT
|
|
46660
47496
|
);
|
|
46661
47497
|
}
|
|
46662
|
-
function
|
|
46663
|
-
const { palette, isDark } = opts;
|
|
46664
|
-
const { width, height } = size;
|
|
47498
|
+
function buildMapProjection(resolved, data) {
|
|
46665
47499
|
const wantsUsStates = resolved.basemaps.subdivisions.includes("us-states");
|
|
46666
|
-
const usCrisp = resolved.projection === "albers-usa" && wantsUsStates && !!data.naLand;
|
|
47500
|
+
const usCrisp = (resolved.projection === "albers-usa" || resolved.projection === "mercator") && wantsUsStates && !!data.naLand;
|
|
46667
47501
|
const worldTopo = usCrisp ? data.worldDetail : resolved.basemaps.world === "detail" ? data.worldDetail : data.worldCoarse;
|
|
46668
|
-
const worldLayer = decodeLayer(worldTopo);
|
|
47502
|
+
const worldLayer = new Map(decodeLayer(worldTopo));
|
|
46669
47503
|
if (usCrisp && data.naLand) {
|
|
46670
47504
|
const [nbW, nbS, nbE, nbN] = [-140, 10, -52, 66];
|
|
46671
47505
|
const crisp = decodeLayer(data.naLand);
|
|
@@ -46674,17 +47508,110 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46674
47508
|
if (!base) continue;
|
|
46675
47509
|
const [[bw, bs], [be, bn]] = geoBounds2(base);
|
|
46676
47510
|
if (bw >= nbW && be <= nbE && bs >= nbS && bn <= nbN)
|
|
46677
|
-
worldLayer.set(iso, cf);
|
|
47511
|
+
worldLayer.set(iso, { ...cf, properties: base.properties });
|
|
46678
47512
|
}
|
|
46679
47513
|
}
|
|
46680
47514
|
const usLayer = wantsUsStates ? decodeLayer(data.usStates) : null;
|
|
47515
|
+
const extentOutline = () => {
|
|
47516
|
+
const [[w, s], [e, n]] = resolved.extent;
|
|
47517
|
+
const N = 16;
|
|
47518
|
+
const coords = [];
|
|
47519
|
+
for (let i = 0; i <= N; i++) {
|
|
47520
|
+
const t = i / N;
|
|
47521
|
+
const lon = w + (e - w) * t;
|
|
47522
|
+
const lat = s + (n - s) * t;
|
|
47523
|
+
coords.push([lon, s], [lon, n], [w, lat], [e, lat]);
|
|
47524
|
+
}
|
|
47525
|
+
return {
|
|
47526
|
+
type: "Feature",
|
|
47527
|
+
properties: {},
|
|
47528
|
+
geometry: { type: "MultiPoint", coordinates: coords }
|
|
47529
|
+
};
|
|
47530
|
+
};
|
|
47531
|
+
let fitFeatures;
|
|
47532
|
+
if (resolved.projection === "albers-usa" && usLayer) {
|
|
47533
|
+
fitFeatures = [...usLayer.entries()].filter(([iso]) => !US_NON_CONUS.has(iso)).map(([, f]) => f);
|
|
47534
|
+
const neighborPoints = resolved.pois.filter((p) => !inAlaska(p.lon, p.lat) && !inHawaii(p.lon, p.lat)).map((p) => [p.lon, p.lat]);
|
|
47535
|
+
if (neighborPoints.length > 0) {
|
|
47536
|
+
fitFeatures.push({
|
|
47537
|
+
type: "Feature",
|
|
47538
|
+
properties: {},
|
|
47539
|
+
geometry: { type: "MultiPoint", coordinates: neighborPoints }
|
|
47540
|
+
});
|
|
47541
|
+
}
|
|
47542
|
+
for (const r of resolved.regions) {
|
|
47543
|
+
if (r.layer === "country" && (r.iso === "CA" || r.iso === "MX")) {
|
|
47544
|
+
const cf = worldLayer.get(r.iso);
|
|
47545
|
+
if (cf) fitFeatures.push(cf);
|
|
47546
|
+
}
|
|
47547
|
+
}
|
|
47548
|
+
} else {
|
|
47549
|
+
fitFeatures = [extentOutline()];
|
|
47550
|
+
}
|
|
47551
|
+
const fitTarget = { type: "FeatureCollection", features: fitFeatures };
|
|
47552
|
+
const projection = projectionFor(resolved.projection);
|
|
47553
|
+
if (resolved.projection !== "albers-usa") {
|
|
47554
|
+
let centerLon = (resolved.extent[0][0] + resolved.extent[1][0]) / 2;
|
|
47555
|
+
if (centerLon > 180) centerLon -= 360;
|
|
47556
|
+
projection.rotate([-centerLon, 0]);
|
|
47557
|
+
}
|
|
47558
|
+
const fitGB = geoBounds2(fitTarget);
|
|
47559
|
+
const fitIsGlobal = fitGB[1][0] - fitGB[0][0] >= 270 || fitGB[1][1] - fitGB[0][1] >= 130;
|
|
47560
|
+
return {
|
|
47561
|
+
projection,
|
|
47562
|
+
fitTarget,
|
|
47563
|
+
fitIsGlobal,
|
|
47564
|
+
worldLayer,
|
|
47565
|
+
usLayer,
|
|
47566
|
+
usCrisp,
|
|
47567
|
+
wantsUsStates,
|
|
47568
|
+
worldTopo
|
|
47569
|
+
};
|
|
47570
|
+
}
|
|
47571
|
+
function parsePathRings(d) {
|
|
47572
|
+
const rings = [];
|
|
47573
|
+
let cur = [];
|
|
47574
|
+
const re = /([MLZ])([^MLZ]*)/g;
|
|
47575
|
+
let m;
|
|
47576
|
+
while (m = re.exec(d)) {
|
|
47577
|
+
if (m[1] === "Z") {
|
|
47578
|
+
if (cur.length) rings.push(cur);
|
|
47579
|
+
cur = [];
|
|
47580
|
+
continue;
|
|
47581
|
+
}
|
|
47582
|
+
if (m[1] === "M" && cur.length) {
|
|
47583
|
+
rings.push(cur);
|
|
47584
|
+
cur = [];
|
|
47585
|
+
}
|
|
47586
|
+
const nums = m[2].split(/[ ,]+/).map(Number);
|
|
47587
|
+
for (let i = 0; i + 1 < nums.length; i += 2) {
|
|
47588
|
+
const x = nums[i];
|
|
47589
|
+
const y = nums[i + 1];
|
|
47590
|
+
if (Number.isFinite(x) && Number.isFinite(y)) cur.push([x, y]);
|
|
47591
|
+
}
|
|
47592
|
+
}
|
|
47593
|
+
if (cur.length) rings.push(cur);
|
|
47594
|
+
return rings;
|
|
47595
|
+
}
|
|
47596
|
+
function layoutMap(resolved, data, size, opts) {
|
|
47597
|
+
const { palette, isDark } = opts;
|
|
47598
|
+
const { width, height } = size;
|
|
47599
|
+
const {
|
|
47600
|
+
projection,
|
|
47601
|
+
fitTarget,
|
|
47602
|
+
fitIsGlobal,
|
|
47603
|
+
worldLayer,
|
|
47604
|
+
usLayer,
|
|
47605
|
+
usCrisp,
|
|
47606
|
+
worldTopo
|
|
47607
|
+
} = buildMapProjection(resolved, data);
|
|
46681
47608
|
const usContext = usLayer !== null;
|
|
46682
47609
|
const regionStroke = isDark ? mix(palette.bg, palette.text, 78) : mix(palette.text, palette.bg, 78);
|
|
46683
47610
|
const values = resolved.regions.filter((r) => r.value !== void 0).map((r) => r.value);
|
|
46684
|
-
const
|
|
46685
|
-
const rampMin =
|
|
46686
|
-
const rampMax =
|
|
46687
|
-
const rampHue = palette.colors.red;
|
|
47611
|
+
const allNonNegative = values.length > 0 && values.every((v) => v >= 0);
|
|
47612
|
+
const rampMin = allNonNegative ? 0 : Math.min(...values);
|
|
47613
|
+
const rampMax = Math.max(...values);
|
|
47614
|
+
const rampHue = resolveColor(resolved.directives.regionMetricColor ?? "", palette) ?? palette.colors.red;
|
|
46688
47615
|
const hasRamp = values.length > 0;
|
|
46689
47616
|
const VALUE_NAME = hasRamp ? resolved.directives.regionMetric?.trim() || "Value" : null;
|
|
46690
47617
|
const matchColorGroup = (v) => {
|
|
@@ -46704,14 +47631,48 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46704
47631
|
activeGroup = VALUE_NAME ?? (resolved.tagGroups.length > 0 ? resolved.tagGroups[0].name : null);
|
|
46705
47632
|
}
|
|
46706
47633
|
const activeIsScore = VALUE_NAME !== null && activeGroup === VALUE_NAME;
|
|
46707
|
-
const mutedBasemap =
|
|
47634
|
+
const mutedBasemap = activeGroup !== null;
|
|
46708
47635
|
const neutralFill = mapNeutralLandColor(palette, isDark, mutedBasemap);
|
|
46709
47636
|
const water = mapBackgroundColor(palette, isDark, mutedBasemap);
|
|
47637
|
+
const lakeStroke = mix(regionStroke, water, 45);
|
|
46710
47638
|
const foreignFill = mix(
|
|
46711
47639
|
palette.colors.gray,
|
|
46712
47640
|
palette.bg,
|
|
46713
47641
|
mutedBasemap ? isDark ? MUTED_FOREIGN_DARK : MUTED_FOREIGN_LIGHT : isDark ? FOREIGN_TINT_DARK : FOREIGN_TINT_LIGHT
|
|
46714
47642
|
);
|
|
47643
|
+
const colorizeActive = resolved.directives.noColorize !== true && !hasRamp && resolved.tagGroups.length === 0;
|
|
47644
|
+
const colorByIso = /* @__PURE__ */ new Map();
|
|
47645
|
+
if (colorizeActive) {
|
|
47646
|
+
const adjacency = /* @__PURE__ */ new Map();
|
|
47647
|
+
const addEdges = (src) => {
|
|
47648
|
+
for (const [iso, ns] of src) {
|
|
47649
|
+
const cur = adjacency.get(iso);
|
|
47650
|
+
if (cur) cur.push(...ns);
|
|
47651
|
+
else adjacency.set(iso, [...ns]);
|
|
47652
|
+
}
|
|
47653
|
+
};
|
|
47654
|
+
addEdges(buildAdjacency(worldTopo));
|
|
47655
|
+
if (usLayer) {
|
|
47656
|
+
addEdges(buildAdjacency(data.usStates));
|
|
47657
|
+
for (const [country, states] of Object.entries(FOREIGN_BORDER)) {
|
|
47658
|
+
const cn = adjacency.get(country);
|
|
47659
|
+
if (!cn) continue;
|
|
47660
|
+
for (const st of states) {
|
|
47661
|
+
const sn = adjacency.get(st);
|
|
47662
|
+
if (!sn) continue;
|
|
47663
|
+
cn.push(st);
|
|
47664
|
+
sn.push(country);
|
|
47665
|
+
}
|
|
47666
|
+
}
|
|
47667
|
+
}
|
|
47668
|
+
const { byIso, huesNeeded } = assignColors(
|
|
47669
|
+
[...adjacency.keys()],
|
|
47670
|
+
adjacency
|
|
47671
|
+
);
|
|
47672
|
+
const tints = politicalTints(palette, huesNeeded, isDark);
|
|
47673
|
+
for (const [iso, idx] of byIso) colorByIso.set(iso, tints[idx]);
|
|
47674
|
+
}
|
|
47675
|
+
const colorizeStroke = (fill2) => mix(fill2, palette.text, 35);
|
|
46715
47676
|
const rampBase = isDark ? mix(palette.surface, palette.text, 28) : palette.bg;
|
|
46716
47677
|
const fillForValue = (s) => {
|
|
46717
47678
|
const t = rampMax > rampMin ? (s - rampMin) / (rampMax - rampMin) : 1;
|
|
@@ -46736,47 +47697,26 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46736
47697
|
isDark ? TAG_TINT_DARK : TAG_TINT_LIGHT
|
|
46737
47698
|
);
|
|
46738
47699
|
};
|
|
47700
|
+
const directFill = (name) => {
|
|
47701
|
+
const hex = name ? resolveColor(name, palette) : null;
|
|
47702
|
+
if (!hex) return null;
|
|
47703
|
+
return mix(hex, palette.bg, isDark ? TAG_TINT_DARK : TAG_TINT_LIGHT);
|
|
47704
|
+
};
|
|
46739
47705
|
const regionFill = (r) => {
|
|
47706
|
+
const direct = directFill(r.color);
|
|
47707
|
+
if (direct) return direct;
|
|
46740
47708
|
if (activeIsScore) {
|
|
46741
47709
|
return r.value !== void 0 ? fillForValue(r.value) : neutralFill;
|
|
46742
47710
|
}
|
|
47711
|
+
if (colorizeActive) return (r.iso && colorByIso.get(r.iso)) ?? neutralFill;
|
|
46743
47712
|
return tagFill(r.tags, activeGroup) ?? neutralFill;
|
|
46744
47713
|
};
|
|
46745
47714
|
const regionById = new Map(resolved.regions.map((r) => [r.iso, r]));
|
|
46746
|
-
const
|
|
46747
|
-
const [[w, s], [e, n]] = resolved.extent;
|
|
46748
|
-
const N = 16;
|
|
46749
|
-
const coords = [];
|
|
46750
|
-
for (let i = 0; i <= N; i++) {
|
|
46751
|
-
const t = i / N;
|
|
46752
|
-
const lon = w + (e - w) * t;
|
|
46753
|
-
const lat = s + (n - s) * t;
|
|
46754
|
-
coords.push([lon, s], [lon, n], [w, lat], [e, lat]);
|
|
46755
|
-
}
|
|
46756
|
-
return {
|
|
46757
|
-
type: "Feature",
|
|
46758
|
-
properties: {},
|
|
46759
|
-
geometry: { type: "MultiPoint", coordinates: coords }
|
|
46760
|
-
};
|
|
46761
|
-
};
|
|
46762
|
-
let fitFeatures;
|
|
46763
|
-
if (resolved.projection === "albers-usa" && usLayer) {
|
|
46764
|
-
fitFeatures = [...usLayer.entries()].filter(([iso]) => !US_NON_CONUS.has(iso)).map(([, f]) => f);
|
|
46765
|
-
} else {
|
|
46766
|
-
fitFeatures = [extentOutline()];
|
|
46767
|
-
}
|
|
46768
|
-
const fitTarget = { type: "FeatureCollection", features: fitFeatures };
|
|
46769
|
-
const projection = projectionFor(resolved.projection);
|
|
46770
|
-
if (resolved.projection !== "albers-usa") {
|
|
46771
|
-
let centerLon = (resolved.extent[0][0] + resolved.extent[1][0]) / 2;
|
|
46772
|
-
if (centerLon > 180) centerLon -= 360;
|
|
46773
|
-
projection.rotate([-centerLon, 0]);
|
|
46774
|
-
}
|
|
46775
|
-
const TITLE_GAP = 16;
|
|
47715
|
+
const TITLE_GAP2 = 16;
|
|
46776
47716
|
let topPad = FIT_PAD;
|
|
46777
47717
|
if (resolved.title && resolved.pois.length > 0) {
|
|
46778
47718
|
const bannerBottom = (resolved.subtitle ? TITLE_Y + TITLE_FONT_SIZE : TITLE_Y) + TITLE_FONT_SIZE / 2;
|
|
46779
|
-
topPad = Math.max(FIT_PAD, bannerBottom +
|
|
47719
|
+
topPad = Math.max(FIT_PAD, bannerBottom + TITLE_GAP2);
|
|
46780
47720
|
}
|
|
46781
47721
|
const fitBox = [
|
|
46782
47722
|
[FIT_PAD, topPad],
|
|
@@ -46786,11 +47726,10 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46786
47726
|
]
|
|
46787
47727
|
];
|
|
46788
47728
|
projection.fitExtent(fitBox, fitTarget);
|
|
46789
|
-
const fitGB = geoBounds2(fitTarget);
|
|
46790
|
-
const fitIsGlobal = fitGB[1][0] - fitGB[0][0] >= 270 || fitGB[1][1] - fitGB[0][1] >= 130;
|
|
46791
47729
|
let path;
|
|
46792
47730
|
let project;
|
|
46793
|
-
|
|
47731
|
+
let stretchParams = null;
|
|
47732
|
+
if (fitIsGlobal && !opts.preferContain) {
|
|
46794
47733
|
const cb = geoPath(projection).bounds(fitTarget);
|
|
46795
47734
|
const bx0 = cb[0][0];
|
|
46796
47735
|
const by0 = cb[0][1];
|
|
@@ -46800,6 +47739,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46800
47739
|
const oy = fitBox[0][1];
|
|
46801
47740
|
const sx = cw > 0 ? (fitBox[1][0] - ox) / cw : 1;
|
|
46802
47741
|
const sy = ch > 0 ? (fitBox[1][1] - oy) / ch : 1;
|
|
47742
|
+
stretchParams = { sx, sy, ox, oy, bx0, by0 };
|
|
46803
47743
|
const stretch = (x, y) => [
|
|
46804
47744
|
ox + (x - bx0) * sx,
|
|
46805
47745
|
oy + (y - by0) * sy
|
|
@@ -46831,7 +47771,9 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46831
47771
|
const insets = [];
|
|
46832
47772
|
const insetRegions = [];
|
|
46833
47773
|
const insetLabelSeeds = [];
|
|
46834
|
-
|
|
47774
|
+
const akRef = resolved.regions.some((r) => r.iso === "US-AK") || resolved.pois.some((p) => inAlaska(p.lon, p.lat));
|
|
47775
|
+
const hiRef = resolved.regions.some((r) => r.iso === "US-HI") || resolved.pois.some((p) => inHawaii(p.lon, p.lat));
|
|
47776
|
+
if (resolved.projection === "albers-usa" && usLayer && (akRef || hiRef)) {
|
|
46835
47777
|
const PAD = 8;
|
|
46836
47778
|
const GAP = 12;
|
|
46837
47779
|
const yB = height - FIT_PAD;
|
|
@@ -46862,38 +47804,14 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46862
47804
|
}
|
|
46863
47805
|
return y;
|
|
46864
47806
|
};
|
|
46865
|
-
const
|
|
47807
|
+
const coastFloor = (x0, xr) => {
|
|
46866
47808
|
const n = 24;
|
|
46867
|
-
const pts = [];
|
|
46868
47809
|
let maxY = -Infinity;
|
|
46869
47810
|
for (let i = 0; i <= n; i++) {
|
|
46870
|
-
const
|
|
46871
|
-
|
|
46872
|
-
|
|
46873
|
-
|
|
46874
|
-
if (y > maxY) maxY = y;
|
|
46875
|
-
}
|
|
46876
|
-
}
|
|
46877
|
-
if (pts.length === 0) return () => yB - height * 0.42;
|
|
46878
|
-
let m = 0;
|
|
46879
|
-
if (pts.length >= 2) {
|
|
46880
|
-
let sx = 0, sy = 0, sxx = 0, sxy = 0;
|
|
46881
|
-
for (const [x, y] of pts) {
|
|
46882
|
-
sx += x;
|
|
46883
|
-
sy += y;
|
|
46884
|
-
sxx += x * x;
|
|
46885
|
-
sxy += x * y;
|
|
46886
|
-
}
|
|
46887
|
-
const den = pts.length * sxx - sx * sx;
|
|
46888
|
-
if (den !== 0) m = (pts.length * sxy - sx * sy) / den;
|
|
46889
|
-
}
|
|
46890
|
-
m = Math.max(-0.35, Math.min(0.35, m));
|
|
46891
|
-
let c = -Infinity;
|
|
46892
|
-
for (const [x, y] of pts) {
|
|
46893
|
-
const need = y - m * x + GAP;
|
|
46894
|
-
if (need > c) c = need;
|
|
46895
|
-
}
|
|
46896
|
-
return (x) => m * x + c;
|
|
47811
|
+
const y = at(x0 + (xr - x0) * i / n);
|
|
47812
|
+
if (y > maxY) maxY = y;
|
|
47813
|
+
}
|
|
47814
|
+
return maxY;
|
|
46897
47815
|
};
|
|
46898
47816
|
const placeInset = (iso, proj, boxX, iwReq) => {
|
|
46899
47817
|
const f = usLayer.get(iso);
|
|
@@ -46902,19 +47820,15 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46902
47820
|
const iw = Math.min(iwReq, width - FIT_PAD - x0 - 2 * PAD);
|
|
46903
47821
|
if (iw < 24) return boxX;
|
|
46904
47822
|
const xr = x0 + iw + 2 * PAD;
|
|
46905
|
-
const
|
|
46906
|
-
const
|
|
46907
|
-
const yR = top(xr);
|
|
47823
|
+
const floor = coastFloor(x0, xr);
|
|
47824
|
+
const topGuess = floor > -Infinity ? floor + GAP : yB - height * 0.42;
|
|
46908
47825
|
proj.fitWidth(iw, f);
|
|
46909
47826
|
const bb = geoPath(proj).bounds(f);
|
|
46910
47827
|
const sh = Number.isFinite(bb[0][0]) ? bb[1][1] - bb[0][1] : iw;
|
|
46911
47828
|
const needH = sh + 2 * PAD;
|
|
46912
|
-
let topFit =
|
|
47829
|
+
let topFit = topGuess;
|
|
46913
47830
|
const bottom = Math.min(topFit + needH, yB);
|
|
46914
47831
|
if (bottom - topFit < needH) topFit = bottom - needH;
|
|
46915
|
-
const lift = topFit - Math.max(yL, yR);
|
|
46916
|
-
const topL = yL + lift;
|
|
46917
|
-
const topR = yR + lift;
|
|
46918
47832
|
proj.fitExtent(
|
|
46919
47833
|
[
|
|
46920
47834
|
[x0 + PAD, topFit + PAD],
|
|
@@ -46924,8 +47838,18 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46924
47838
|
);
|
|
46925
47839
|
const d = geoPath(proj)(f) ?? "";
|
|
46926
47840
|
if (!d) return xr;
|
|
47841
|
+
let contextLand;
|
|
47842
|
+
if (iso === "US-AK") {
|
|
47843
|
+
const can = worldLayer.get("CA");
|
|
47844
|
+
const cd = can ? geoPath(proj)(can) ?? "" : "";
|
|
47845
|
+
if (cd)
|
|
47846
|
+
contextLand = {
|
|
47847
|
+
d: cd,
|
|
47848
|
+
fill: colorizeActive ? colorByIso.get("CA") ?? foreignFill : foreignFill
|
|
47849
|
+
};
|
|
47850
|
+
}
|
|
46927
47851
|
const r = regionById.get(iso);
|
|
46928
|
-
let fill2 = neutralFill;
|
|
47852
|
+
let fill2 = colorizeActive ? colorByIso.get(iso) ?? neutralFill : neutralFill;
|
|
46929
47853
|
let lineNumber = -1;
|
|
46930
47854
|
if (r?.layer === "us-state") {
|
|
46931
47855
|
fill2 = regionFill(r);
|
|
@@ -46933,21 +47857,25 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46933
47857
|
}
|
|
46934
47858
|
insets.push({
|
|
46935
47859
|
x: x0,
|
|
46936
|
-
y:
|
|
47860
|
+
y: topFit,
|
|
46937
47861
|
w: xr - x0,
|
|
46938
|
-
h: bottom -
|
|
47862
|
+
h: bottom - topFit,
|
|
46939
47863
|
points: [
|
|
46940
|
-
[x0,
|
|
46941
|
-
[xr,
|
|
47864
|
+
[x0, topFit],
|
|
47865
|
+
[xr, topFit],
|
|
46942
47866
|
[xr, bottom],
|
|
46943
47867
|
[x0, bottom]
|
|
46944
|
-
]
|
|
47868
|
+
],
|
|
47869
|
+
// The FITTED inset projection (just fit to this box) — captured so the
|
|
47870
|
+
// geo-query can invert pixels inside the frame back to AK/HI coords.
|
|
47871
|
+
projection: proj,
|
|
47872
|
+
...contextLand && { contextLand }
|
|
46945
47873
|
});
|
|
46946
47874
|
insetRegions.push({
|
|
46947
47875
|
id: iso,
|
|
46948
47876
|
d,
|
|
46949
47877
|
fill: fill2,
|
|
46950
|
-
stroke: regionStroke,
|
|
47878
|
+
stroke: colorizeActive ? colorizeStroke(fill2) : regionStroke,
|
|
46951
47879
|
lineNumber,
|
|
46952
47880
|
layer: "us-state",
|
|
46953
47881
|
...r?.value !== void 0 && { value: r.value },
|
|
@@ -46960,13 +47888,16 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46960
47888
|
}
|
|
46961
47889
|
return xr;
|
|
46962
47890
|
};
|
|
46963
|
-
|
|
46964
|
-
|
|
46965
|
-
alaskaProjection(),
|
|
46966
|
-
|
|
46967
|
-
|
|
46968
|
-
|
|
46969
|
-
|
|
47891
|
+
let akRight = FIT_PAD;
|
|
47892
|
+
if (akRef)
|
|
47893
|
+
akRight = placeInset("US-AK", alaskaProjection(), FIT_PAD, width * 0.15);
|
|
47894
|
+
if (hiRef)
|
|
47895
|
+
placeInset(
|
|
47896
|
+
"US-HI",
|
|
47897
|
+
hawaiiProjection(),
|
|
47898
|
+
akRef ? akRight + 24 : FIT_PAD,
|
|
47899
|
+
width * 0.1
|
|
47900
|
+
);
|
|
46970
47901
|
}
|
|
46971
47902
|
const conusFit = resolved.projection === "albers-usa" && !!usLayer;
|
|
46972
47903
|
const classifyExtent = conusFit ? geoBounds2(fitTarget) : resolved.extent;
|
|
@@ -46982,15 +47913,24 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46982
47913
|
};
|
|
46983
47914
|
const ringOverlapsView = (ring) => {
|
|
46984
47915
|
let loMin = Infinity, loMax = -Infinity, rawMin = Infinity, rawMax = -Infinity;
|
|
47916
|
+
const lons = [];
|
|
46985
47917
|
for (const [rawLon] of ring) {
|
|
46986
47918
|
const lon = normLon(rawLon);
|
|
47919
|
+
lons.push(lon);
|
|
46987
47920
|
if (lon < loMin) loMin = lon;
|
|
46988
47921
|
if (lon > loMax) loMax = lon;
|
|
46989
47922
|
if (rawLon < rawMin) rawMin = rawLon;
|
|
46990
47923
|
if (rawLon > rawMax) rawMax = rawLon;
|
|
46991
47924
|
}
|
|
46992
|
-
|
|
46993
|
-
|
|
47925
|
+
lons.sort((a, b) => a - b);
|
|
47926
|
+
let maxGap = 0;
|
|
47927
|
+
for (let i = 1; i < lons.length; i++)
|
|
47928
|
+
maxGap = Math.max(maxGap, lons[i] - lons[i - 1]);
|
|
47929
|
+
if (lons.length > 1)
|
|
47930
|
+
maxGap = Math.max(maxGap, lons[0] + 360 - lons[lons.length - 1]);
|
|
47931
|
+
const occupiedArc = 360 - maxGap;
|
|
47932
|
+
if (occupiedArc > 270) return false;
|
|
47933
|
+
if (rawMax - rawMin > 180 && occupiedArc < 90) return false;
|
|
46994
47934
|
let px0 = Infinity, py0 = Infinity, px1 = -Infinity, py1 = -Infinity, anyFinite = false;
|
|
46995
47935
|
for (const [lon, lat] of ring) {
|
|
46996
47936
|
const p = project(lon, lat);
|
|
@@ -47063,7 +48003,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47063
48003
|
const regions = [];
|
|
47064
48004
|
const pushRegionLayer = (layerFeatures, layerKind, shouldCull) => {
|
|
47065
48005
|
for (const [iso, f] of layerFeatures) {
|
|
47066
|
-
if (layerKind === "us-state" && usContext && INSET_STATES.has(iso))
|
|
48006
|
+
if (layerKind === "us-state" && usContext && resolved.projection === "albers-usa" && INSET_STATES.has(iso))
|
|
47067
48007
|
continue;
|
|
47068
48008
|
if (layerKind === "country" && usContext && iso === "US") continue;
|
|
47069
48009
|
if (layerKind === "country" && iso === "AQ" && !regionById.has("AQ"))
|
|
@@ -47075,7 +48015,8 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47075
48015
|
if (!d) continue;
|
|
47076
48016
|
const isThisLayer = r?.layer === layerKind;
|
|
47077
48017
|
const isForeign = layerKind === "country" && usContext && iso !== "US";
|
|
47078
|
-
|
|
48018
|
+
const baseFill = isForeign ? foreignFill : neutralFill;
|
|
48019
|
+
let fill2 = colorizeActive ? colorByIso.get(iso) ?? baseFill : baseFill;
|
|
47079
48020
|
let label;
|
|
47080
48021
|
let lineNumber = -1;
|
|
47081
48022
|
let layer = "base";
|
|
@@ -47084,12 +48025,14 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47084
48025
|
lineNumber = r.lineNumber;
|
|
47085
48026
|
layer = layerKind;
|
|
47086
48027
|
label = r.name;
|
|
48028
|
+
} else {
|
|
48029
|
+
label = f.properties?.name;
|
|
47087
48030
|
}
|
|
47088
48031
|
regions.push({
|
|
47089
48032
|
id: iso,
|
|
47090
48033
|
d,
|
|
47091
48034
|
fill: fill2,
|
|
47092
|
-
stroke: regionStroke,
|
|
48035
|
+
stroke: colorizeActive ? colorizeStroke(fill2) : regionStroke,
|
|
47093
48036
|
lineNumber,
|
|
47094
48037
|
layer,
|
|
47095
48038
|
...label !== void 0 && { label },
|
|
@@ -47111,13 +48054,88 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47111
48054
|
id: "lake",
|
|
47112
48055
|
d,
|
|
47113
48056
|
fill: water,
|
|
47114
|
-
stroke:
|
|
48057
|
+
stroke: lakeStroke,
|
|
47115
48058
|
lineNumber: -1,
|
|
47116
48059
|
layer: "base"
|
|
47117
48060
|
});
|
|
47118
48061
|
}
|
|
47119
48062
|
}
|
|
47120
|
-
const
|
|
48063
|
+
const pointInRings = (px, py, rings) => {
|
|
48064
|
+
let inside = false;
|
|
48065
|
+
for (const ring of rings) {
|
|
48066
|
+
for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
|
|
48067
|
+
const [xi, yi] = ring[i];
|
|
48068
|
+
const [xj, yj] = ring[j];
|
|
48069
|
+
if (yi > py !== yj > py && px < (xj - xi) * (py - yi) / (yj - yi) + xi)
|
|
48070
|
+
inside = !inside;
|
|
48071
|
+
}
|
|
48072
|
+
}
|
|
48073
|
+
return inside;
|
|
48074
|
+
};
|
|
48075
|
+
const fillHitTargets = [...regions, ...insetRegions].map((r) => ({
|
|
48076
|
+
fill: r.fill,
|
|
48077
|
+
rings: parsePathRings(r.d)
|
|
48078
|
+
}));
|
|
48079
|
+
const fillAt = (x, y) => {
|
|
48080
|
+
let hit = water;
|
|
48081
|
+
for (const t of fillHitTargets)
|
|
48082
|
+
if (pointInRings(x, y, t.rings)) hit = t.fill;
|
|
48083
|
+
return hit;
|
|
48084
|
+
};
|
|
48085
|
+
const labelOnFill = (fill2) => {
|
|
48086
|
+
const color = contrastRatio(fill2, palette.textOnFillDark) >= contrastRatio(fill2, palette.textOnFillLight) ? palette.textOnFillDark : palette.textOnFillLight;
|
|
48087
|
+
const haloColor = color === palette.textOnFillLight ? palette.textOnFillDark : palette.textOnFillLight;
|
|
48088
|
+
return {
|
|
48089
|
+
color,
|
|
48090
|
+
halo: contrastRatio(fill2, color) < REGION_LABEL_HALO_RATIO,
|
|
48091
|
+
haloColor
|
|
48092
|
+
};
|
|
48093
|
+
};
|
|
48094
|
+
const reliefAllowed = resolved.directives.noRelief !== true;
|
|
48095
|
+
const relief = [];
|
|
48096
|
+
let reliefHatch = null;
|
|
48097
|
+
if (reliefAllowed && data.mountainRanges) {
|
|
48098
|
+
for (const [, f] of decodeLayer(data.mountainRanges)) {
|
|
48099
|
+
const viewF = isGlobalView ? dropFrameFillers(f) : cullFeatureToView(f);
|
|
48100
|
+
if (!viewF) continue;
|
|
48101
|
+
const area2 = path.area(viewF);
|
|
48102
|
+
if (!Number.isFinite(area2) || area2 < RELIEF_MIN_AREA) continue;
|
|
48103
|
+
const box = path.bounds(viewF);
|
|
48104
|
+
if (box[1][0] - box[0][0] < RELIEF_MIN_DIM || box[1][1] - box[0][1] < RELIEF_MIN_DIM)
|
|
48105
|
+
continue;
|
|
48106
|
+
const d = path(viewF) ?? "";
|
|
48107
|
+
if (!d) continue;
|
|
48108
|
+
relief.push({ d });
|
|
48109
|
+
}
|
|
48110
|
+
if (relief.length) {
|
|
48111
|
+
const darkTone = isDark ? palette.bg : palette.text;
|
|
48112
|
+
const lightTone = isDark ? palette.text : palette.bg;
|
|
48113
|
+
const reliefLandRef = colorizeActive ? isDark ? palette.surface : palette.bg : neutralFill;
|
|
48114
|
+
const landLum = relativeLuminance(reliefLandRef);
|
|
48115
|
+
const tone = Math.abs(landLum - relativeLuminance(darkTone)) > 0.04 ? darkTone : lightTone;
|
|
48116
|
+
reliefHatch = {
|
|
48117
|
+
color: mix(tone, reliefLandRef, RELIEF_HATCH_STRENGTH),
|
|
48118
|
+
spacing: RELIEF_HATCH_SPACING,
|
|
48119
|
+
width: RELIEF_HATCH_WIDTH
|
|
48120
|
+
};
|
|
48121
|
+
}
|
|
48122
|
+
}
|
|
48123
|
+
let coastlineStyle = null;
|
|
48124
|
+
if (resolved.directives.noCoastline !== true) {
|
|
48125
|
+
const minDim = Math.min(width, height);
|
|
48126
|
+
coastlineStyle = {
|
|
48127
|
+
color: mix(regionStroke, water, COASTLINE_STROKE_MIX),
|
|
48128
|
+
// N equal-width rings: distance steps outward by COASTLINE_STEP; opacity
|
|
48129
|
+
// fades linearly from NEAR (innermost) to FAR (outermost).
|
|
48130
|
+
lines: Array.from({ length: COASTLINE_RING_COUNT }, (_, k) => ({
|
|
48131
|
+
d: (COASTLINE_D0 + k * COASTLINE_STEP) * minDim,
|
|
48132
|
+
thickness: COASTLINE_THICKNESS * minDim,
|
|
48133
|
+
opacity: COASTLINE_OPACITY_NEAR + (COASTLINE_OPACITY_FAR - COASTLINE_OPACITY_NEAR) * k / (COASTLINE_RING_COUNT - 1)
|
|
48134
|
+
})),
|
|
48135
|
+
minExtent: (isGlobalView ? COASTLINE_MIN_EXTENT_GLOBAL : COASTLINE_MIN_EXTENT) * minDim
|
|
48136
|
+
};
|
|
48137
|
+
}
|
|
48138
|
+
const riverColor = mix(palette.colors.blue, water, 32);
|
|
47121
48139
|
const rivers = [];
|
|
47122
48140
|
if (data.rivers) {
|
|
47123
48141
|
for (const [, f] of decodeLayer(data.rivers)) {
|
|
@@ -47138,6 +48156,9 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47138
48156
|
return R_MIN + Math.max(0, Math.min(1, t)) * (R_MAX - R_MIN);
|
|
47139
48157
|
};
|
|
47140
48158
|
const poiFill = (p) => {
|
|
48159
|
+
const directHex = p.color ? resolveColor(p.color, palette) : null;
|
|
48160
|
+
if (directHex)
|
|
48161
|
+
return { fill: directHex, stroke: mix(directHex, palette.text, 18) };
|
|
47141
48162
|
for (const group of resolved.tagGroups) {
|
|
47142
48163
|
const val = p.tags[group.name.toLowerCase()];
|
|
47143
48164
|
if (!val) continue;
|
|
@@ -47170,38 +48191,108 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47170
48191
|
const xy = project(p.lon, p.lat);
|
|
47171
48192
|
if (xy) projected.push({ p, xy });
|
|
47172
48193
|
}
|
|
47173
|
-
const
|
|
48194
|
+
const placePoi = (e, cx, cy, clusterId) => {
|
|
48195
|
+
const { fill: fill2, stroke: stroke2 } = poiFill(e.p);
|
|
48196
|
+
poiScreen.set(e.p.id, { cx, cy, r: radiusFor(e.p) });
|
|
48197
|
+
const num = routeNumberById.get(e.p.id);
|
|
48198
|
+
pois.push({
|
|
48199
|
+
id: e.p.id,
|
|
48200
|
+
cx,
|
|
48201
|
+
cy,
|
|
48202
|
+
r: radiusFor(e.p),
|
|
48203
|
+
fill: fill2,
|
|
48204
|
+
stroke: stroke2,
|
|
48205
|
+
lineNumber: e.p.lineNumber,
|
|
48206
|
+
implicit: !!e.p.implicit,
|
|
48207
|
+
isOrigin: originIds.has(e.p.id),
|
|
48208
|
+
...num !== void 0 && { routeNumber: num },
|
|
48209
|
+
...Object.keys(e.p.tags).length > 0 && { tags: e.p.tags },
|
|
48210
|
+
...clusterId !== void 0 && { clusterId }
|
|
48211
|
+
});
|
|
48212
|
+
};
|
|
48213
|
+
const clusters = [];
|
|
48214
|
+
const connected = /* @__PURE__ */ new Set();
|
|
48215
|
+
for (const e of resolved.edges) {
|
|
48216
|
+
connected.add(e.fromId);
|
|
48217
|
+
connected.add(e.toId);
|
|
48218
|
+
}
|
|
48219
|
+
for (const rt of resolved.routes) {
|
|
48220
|
+
rt.stopIds.forEach((id) => connected.add(id));
|
|
48221
|
+
}
|
|
48222
|
+
const radiusOf = (e) => radiusFor(e.p);
|
|
47174
48223
|
for (const e of projected) {
|
|
47175
|
-
|
|
47176
|
-
|
|
47177
|
-
|
|
47178
|
-
|
|
47179
|
-
|
|
47180
|
-
|
|
47181
|
-
|
|
47182
|
-
|
|
47183
|
-
|
|
47184
|
-
|
|
47185
|
-
|
|
47186
|
-
|
|
47187
|
-
|
|
47188
|
-
|
|
47189
|
-
|
|
47190
|
-
|
|
47191
|
-
|
|
47192
|
-
|
|
47193
|
-
|
|
47194
|
-
|
|
47195
|
-
|
|
47196
|
-
|
|
47197
|
-
|
|
47198
|
-
|
|
47199
|
-
|
|
47200
|
-
|
|
47201
|
-
|
|
47202
|
-
|
|
47203
|
-
|
|
47204
|
-
|
|
48224
|
+
if (connected.has(e.p.id)) placePoi(e, e.xy[0], e.xy[1]);
|
|
48225
|
+
}
|
|
48226
|
+
const groups = [];
|
|
48227
|
+
for (const e of projected) {
|
|
48228
|
+
if (connected.has(e.p.id)) continue;
|
|
48229
|
+
const r = radiusOf(e);
|
|
48230
|
+
const near = groups.find(
|
|
48231
|
+
(g) => g.some(
|
|
48232
|
+
(q) => Math.hypot(q.xy[0] - e.xy[0], q.xy[1] - e.xy[1]) < (r + radiusOf(q)) * STACK_OVERLAP
|
|
48233
|
+
)
|
|
48234
|
+
);
|
|
48235
|
+
if (near) near.push(e);
|
|
48236
|
+
else groups.push([e]);
|
|
48237
|
+
}
|
|
48238
|
+
for (const g of groups) {
|
|
48239
|
+
if (g.length === 1) {
|
|
48240
|
+
placePoi(g[0], g[0].xy[0], g[0].xy[1]);
|
|
48241
|
+
continue;
|
|
48242
|
+
}
|
|
48243
|
+
const clusterId = g[0].p.id;
|
|
48244
|
+
const cx0 = g.reduce((s, e) => s + e.xy[0], 0) / g.length;
|
|
48245
|
+
const cy0 = g.reduce((s, e) => s + e.xy[1], 0) / g.length;
|
|
48246
|
+
const maxR = Math.max(...g.map(radiusOf));
|
|
48247
|
+
const sep = 2 * maxR + STACK_RING_GAP;
|
|
48248
|
+
const ringR = Math.max(
|
|
48249
|
+
COLO_R,
|
|
48250
|
+
sep / (2 * Math.sin(Math.PI / Math.max(g.length, 2)))
|
|
48251
|
+
);
|
|
48252
|
+
const positions = g.map((e, i) => {
|
|
48253
|
+
if (g.length <= STACK_RING_MAX) {
|
|
48254
|
+
const ang2 = -Math.PI / 2 + i * 2 * Math.PI / g.length;
|
|
48255
|
+
return {
|
|
48256
|
+
e,
|
|
48257
|
+
mx: cx0 + Math.cos(ang2) * ringR,
|
|
48258
|
+
my: cy0 + Math.sin(ang2) * ringR
|
|
48259
|
+
};
|
|
48260
|
+
}
|
|
48261
|
+
const ang = i * GOLDEN_ANGLE;
|
|
48262
|
+
const rr = ringR * Math.sqrt((i + 1) / g.length);
|
|
48263
|
+
return { e, mx: cx0 + Math.cos(ang) * rr, my: cy0 + Math.sin(ang) * rr };
|
|
48264
|
+
});
|
|
48265
|
+
let minX = cx0 - maxR;
|
|
48266
|
+
let maxX = cx0 + maxR;
|
|
48267
|
+
let minY = cy0 - maxR;
|
|
48268
|
+
let maxY = cy0 + maxR;
|
|
48269
|
+
for (const { mx, my, e } of positions) {
|
|
48270
|
+
const r = radiusOf(e);
|
|
48271
|
+
minX = Math.min(minX, mx - r);
|
|
48272
|
+
maxX = Math.max(maxX, mx + r);
|
|
48273
|
+
minY = Math.min(minY, my - r);
|
|
48274
|
+
maxY = Math.max(maxY, my + r);
|
|
48275
|
+
}
|
|
48276
|
+
let dx = 0;
|
|
48277
|
+
let dy = 0;
|
|
48278
|
+
if (minX + dx < 2) dx = 2 - minX;
|
|
48279
|
+
if (maxX + dx > width - 2) dx = width - 2 - maxX;
|
|
48280
|
+
if (minY + dy < 2) dy = 2 - minY;
|
|
48281
|
+
if (maxY + dy > height - 2) dy = height - 2 - maxY;
|
|
48282
|
+
const legsOut = [];
|
|
48283
|
+
for (const { e, mx, my } of positions) {
|
|
48284
|
+
const fx = mx + dx;
|
|
48285
|
+
const fy = my + dy;
|
|
48286
|
+
placePoi(e, fx, fy, clusterId);
|
|
48287
|
+
legsOut.push({ x2: fx, y2: fy, color: poiFill(e.p).fill });
|
|
48288
|
+
}
|
|
48289
|
+
clusters.push({
|
|
48290
|
+
id: clusterId,
|
|
48291
|
+
cx: cx0 + dx,
|
|
48292
|
+
cy: cy0 + dy,
|
|
48293
|
+
count: g.length,
|
|
48294
|
+
hitR: ringR + maxR + 6,
|
|
48295
|
+
legs: legsOut
|
|
47205
48296
|
});
|
|
47206
48297
|
}
|
|
47207
48298
|
const legs = [];
|
|
@@ -47251,16 +48342,26 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47251
48342
|
if (!a || !b) continue;
|
|
47252
48343
|
const mx = (a.cx + b.cx) / 2;
|
|
47253
48344
|
const my = (a.cy + b.cy) / 2;
|
|
48345
|
+
const bow = {
|
|
48346
|
+
curved: leg.style === "arc",
|
|
48347
|
+
offset: 0,
|
|
48348
|
+
labelX: mx,
|
|
48349
|
+
labelY: my - 4
|
|
48350
|
+
};
|
|
48351
|
+
const routeLabelStyle = leg.label !== void 0 ? labelOnFill(fillAt(bow.labelX, bow.labelY)) : void 0;
|
|
47254
48352
|
legs.push({
|
|
47255
|
-
d: legPath(a, b,
|
|
48353
|
+
d: legPath(a, b, bow.curved, bow.offset),
|
|
47256
48354
|
width: routeWidthFor(Number(leg.value)),
|
|
47257
48355
|
color: mix(palette.text, palette.bg, 72),
|
|
47258
48356
|
arrow: true,
|
|
47259
48357
|
lineNumber: leg.lineNumber,
|
|
47260
48358
|
...leg.label !== void 0 && {
|
|
47261
48359
|
label: leg.label,
|
|
47262
|
-
labelX:
|
|
47263
|
-
labelY:
|
|
48360
|
+
labelX: bow.labelX,
|
|
48361
|
+
labelY: bow.labelY,
|
|
48362
|
+
labelColor: routeLabelStyle.color,
|
|
48363
|
+
labelHalo: routeLabelStyle.halo,
|
|
48364
|
+
labelHaloColor: routeLabelStyle.haloColor
|
|
47264
48365
|
}
|
|
47265
48366
|
});
|
|
47266
48367
|
}
|
|
@@ -47288,20 +48389,29 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47288
48389
|
const a = poiScreen.get(e.fromId);
|
|
47289
48390
|
const b = poiScreen.get(e.toId);
|
|
47290
48391
|
if (!a || !b) return;
|
|
47291
|
-
const
|
|
47292
|
-
const offset = n > 1 ? (i - (n - 1) / 2) * FAN_STEP : 0;
|
|
48392
|
+
const fanOffset = n > 1 ? (i - (n - 1) / 2) * FAN_STEP : 0;
|
|
47293
48393
|
const mx = (a.cx + b.cx) / 2;
|
|
47294
48394
|
const my = (a.cy + b.cy) / 2;
|
|
48395
|
+
const bow = {
|
|
48396
|
+
curved: e.style === "arc" || n > 1,
|
|
48397
|
+
offset: fanOffset,
|
|
48398
|
+
labelX: mx,
|
|
48399
|
+
labelY: my - 4
|
|
48400
|
+
};
|
|
48401
|
+
const edgeLabelStyle = e.label !== void 0 ? labelOnFill(fillAt(bow.labelX, bow.labelY)) : void 0;
|
|
47295
48402
|
legs.push({
|
|
47296
|
-
d: legPath(a, b, curved, offset),
|
|
48403
|
+
d: legPath(a, b, bow.curved, bow.offset),
|
|
47297
48404
|
width: widthFor(e),
|
|
47298
48405
|
color: mix(palette.text, palette.bg, 66),
|
|
47299
48406
|
arrow: e.directed,
|
|
47300
48407
|
lineNumber: e.lineNumber,
|
|
47301
48408
|
...e.label !== void 0 && {
|
|
47302
48409
|
label: e.label,
|
|
47303
|
-
labelX:
|
|
47304
|
-
labelY:
|
|
48410
|
+
labelX: bow.labelX,
|
|
48411
|
+
labelY: bow.labelY,
|
|
48412
|
+
labelColor: edgeLabelStyle.color,
|
|
48413
|
+
labelHalo: edgeLabelStyle.halo,
|
|
48414
|
+
labelHaloColor: edgeLabelStyle.haloColor
|
|
47305
48415
|
}
|
|
47306
48416
|
});
|
|
47307
48417
|
});
|
|
@@ -47343,25 +48453,25 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47343
48453
|
}
|
|
47344
48454
|
}
|
|
47345
48455
|
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));
|
|
47346
|
-
const
|
|
48456
|
+
const showRegionLabels = resolved.directives.noRegionLabels !== true;
|
|
48457
|
+
const isCompact = width < COMPACT_WIDTH_PX;
|
|
47347
48458
|
const LABEL_PADX = 6;
|
|
47348
48459
|
const LABEL_PADY = 3;
|
|
47349
|
-
const labelW = (text) => measureLegendText(text,
|
|
47350
|
-
const labelH =
|
|
48460
|
+
const labelW = (text) => measureLegendText(text, FONT2) + 2 * LABEL_PADX;
|
|
48461
|
+
const labelH = FONT2 + 2 * LABEL_PADY;
|
|
47351
48462
|
const pushRegionLabel = (x, y, text, fill2, lineNumber) => {
|
|
47352
|
-
const color =
|
|
47353
|
-
|
|
47354
|
-
|
|
47355
|
-
|
|
48463
|
+
const { color, haloColor } = labelOnFill(fill2);
|
|
48464
|
+
const halfW = measureLegendText(text, FONT2) / 2;
|
|
48465
|
+
const overflows = [y - FONT2 * 0.55, y - FONT2 * 0.1].some(
|
|
48466
|
+
(sy) => fillAt(x - halfW, sy) !== fill2 || fillAt(x + halfW, sy) !== fill2
|
|
47356
48467
|
);
|
|
47357
|
-
const haloColor = color === palette.textOnFillLight ? palette.textOnFillDark : palette.textOnFillLight;
|
|
47358
48468
|
labels.push({
|
|
47359
48469
|
x,
|
|
47360
48470
|
y,
|
|
47361
48471
|
text,
|
|
47362
48472
|
anchor: "middle",
|
|
47363
48473
|
color,
|
|
47364
|
-
halo:
|
|
48474
|
+
halo: overflows,
|
|
47365
48475
|
haloColor,
|
|
47366
48476
|
lineNumber
|
|
47367
48477
|
});
|
|
@@ -47370,21 +48480,50 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47370
48480
|
US: [-98.5, 39.5]
|
|
47371
48481
|
// CONUS geographic centre (near Lebanon, Kansas)
|
|
47372
48482
|
};
|
|
47373
|
-
|
|
47374
|
-
|
|
47375
|
-
|
|
47376
|
-
|
|
47377
|
-
|
|
48483
|
+
const REGION_LABEL_GAP = 2;
|
|
48484
|
+
const regionLabelRect = (cx, cy, text) => {
|
|
48485
|
+
const w = measureLegendText(text, FONT2) + 2 * REGION_LABEL_GAP;
|
|
48486
|
+
return { x: cx - w / 2, y: cy - FONT2 / 2, w, h: FONT2 };
|
|
48487
|
+
};
|
|
48488
|
+
if (showRegionLabels) {
|
|
48489
|
+
const frameContainers = new Set(resolved.poiFrameContainers);
|
|
48490
|
+
const entries = regions.map((r) => {
|
|
48491
|
+
const isContainer = frameContainers.has(r.id);
|
|
48492
|
+
if (r.layer === "base" && !isContainer || r.label === void 0)
|
|
48493
|
+
return null;
|
|
48494
|
+
const isUsState = r.layer === "us-state" || r.id.startsWith("US-");
|
|
48495
|
+
const f = isUsState ? usLayer?.get(r.id) : worldLayer.get(r.id);
|
|
48496
|
+
if (!f) return null;
|
|
47378
48497
|
const [[x0, y0], [x1, y1]] = path.bounds(f);
|
|
47379
|
-
const
|
|
47380
|
-
|
|
47381
|
-
const
|
|
48498
|
+
const boxW = x1 - x0;
|
|
48499
|
+
const boxH = y1 - y0;
|
|
48500
|
+
const abbrev = isUsState ? r.id.replace(/^US-/, "") : void 0;
|
|
48501
|
+
const candidates = abbrev !== void 0 ? isCompact ? [abbrev, r.label] : [r.label, abbrev] : [r.label];
|
|
48502
|
+
const anchor = !isUsState ? WORLD_LABEL_ANCHORS[r.id] : void 0;
|
|
47382
48503
|
const c = anchor ? project(anchor[0], anchor[1]) : path.centroid(f);
|
|
47383
|
-
if (!c || !Number.isFinite(c[0]))
|
|
48504
|
+
if (!c || !Number.isFinite(c[0])) return null;
|
|
48505
|
+
return { r, c, boxW, boxH, area: boxW * boxH, candidates };
|
|
48506
|
+
}).filter((e) => e !== null).sort((a, b) => b.area - a.area || a.r.lineNumber - b.r.lineNumber);
|
|
48507
|
+
const placedRegionRects = [];
|
|
48508
|
+
const POI_LABEL_PAD = 14;
|
|
48509
|
+
const poiObstacles = pois.map((p) => ({
|
|
48510
|
+
x: p.cx - p.r - POI_LABEL_PAD,
|
|
48511
|
+
y: p.cy - p.r - POI_LABEL_PAD,
|
|
48512
|
+
w: 2 * (p.r + POI_LABEL_PAD),
|
|
48513
|
+
h: 2 * (p.r + POI_LABEL_PAD)
|
|
48514
|
+
}));
|
|
48515
|
+
for (const { r, c, boxW, boxH, candidates } of entries) {
|
|
48516
|
+
const text = candidates.find((t) => {
|
|
48517
|
+
if (labelW(t) > boxW || labelH > boxH) return false;
|
|
48518
|
+
const rect = regionLabelRect(c[0], c[1], t);
|
|
48519
|
+
return !placedRegionRects.some((p) => rectsOverlap(rect, p)) && !poiObstacles.some((o) => rectsOverlap(rect, o));
|
|
48520
|
+
});
|
|
48521
|
+
if (text === void 0) continue;
|
|
48522
|
+
placedRegionRects.push(regionLabelRect(c[0], c[1], text));
|
|
47384
48523
|
pushRegionLabel(c[0], c[1], text, r.fill, r.lineNumber);
|
|
47385
48524
|
}
|
|
47386
48525
|
for (const seed of insetLabelSeeds) {
|
|
47387
|
-
const text =
|
|
48526
|
+
const text = isCompact ? seed.iso.replace(/^US-/, "") : seed.name;
|
|
47388
48527
|
const src = regionById.get(seed.iso);
|
|
47389
48528
|
pushRegionLabel(
|
|
47390
48529
|
seed.x,
|
|
@@ -47395,22 +48534,26 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47395
48534
|
);
|
|
47396
48535
|
}
|
|
47397
48536
|
}
|
|
47398
|
-
|
|
47399
|
-
|
|
47400
|
-
const ordered = [...pois].sort(
|
|
47401
|
-
(a, b) => a.lineNumber - b.lineNumber || (a.id < b.id ? -1 : 1)
|
|
47402
|
-
);
|
|
48537
|
+
if (resolved.directives.noPoiLabels !== true) {
|
|
48538
|
+
const ordered = [...pois].filter((p) => p.clusterId === void 0).sort((a, b) => a.lineNumber - b.lineNumber || (a.id < b.id ? -1 : 1));
|
|
47403
48539
|
const poiById = new Map(resolved.pois.map((q) => [q.id, q]));
|
|
47404
48540
|
const labelText = (p) => {
|
|
47405
48541
|
const src = poiById.get(p.id);
|
|
47406
48542
|
return src?.label ?? src?.name ?? p.id;
|
|
47407
48543
|
};
|
|
47408
|
-
const poiLabH =
|
|
48544
|
+
const poiLabH = FONT2 * 1.25;
|
|
47409
48545
|
const labelInfo = (p) => {
|
|
47410
48546
|
const text = labelText(p);
|
|
47411
|
-
return { text, w: measureLegendText(text,
|
|
48547
|
+
return { text, w: measureLegendText(text, FONT2) };
|
|
47412
48548
|
};
|
|
47413
48549
|
const GAP = 3;
|
|
48550
|
+
const clusterMembersById = /* @__PURE__ */ new Map();
|
|
48551
|
+
for (const p of pois) {
|
|
48552
|
+
if (p.clusterId === void 0) continue;
|
|
48553
|
+
const arr = clusterMembersById.get(p.clusterId);
|
|
48554
|
+
if (arr) arr.push(p);
|
|
48555
|
+
else clusterMembersById.set(p.clusterId, [p]);
|
|
48556
|
+
}
|
|
47414
48557
|
const inlineRect = (p, w, side) => {
|
|
47415
48558
|
switch (side) {
|
|
47416
48559
|
case "right":
|
|
@@ -47440,11 +48583,11 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47440
48583
|
const x = side === "right" ? rect.x : side === "left" ? rect.x + w : p.cx;
|
|
47441
48584
|
labels.push({
|
|
47442
48585
|
x,
|
|
47443
|
-
y: rect.y + poiLabH / 2 +
|
|
48586
|
+
y: rect.y + poiLabH / 2 + FONT2 / 3,
|
|
47444
48587
|
text,
|
|
47445
48588
|
anchor,
|
|
47446
48589
|
color: palette.text,
|
|
47447
|
-
halo:
|
|
48590
|
+
halo: false,
|
|
47448
48591
|
haloColor: palette.bg,
|
|
47449
48592
|
poiId: p.id,
|
|
47450
48593
|
lineNumber: p.lineNumber
|
|
@@ -47455,43 +48598,60 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47455
48598
|
return rect.x >= 0 && rect.x + rect.w <= width && rect.y >= 0 && rect.y + rect.h <= height && !collides(rect);
|
|
47456
48599
|
};
|
|
47457
48600
|
const GROUP_R = 30;
|
|
47458
|
-
const
|
|
48601
|
+
const groups2 = [];
|
|
47459
48602
|
for (const p of ordered) {
|
|
47460
|
-
const near =
|
|
48603
|
+
const near = groups2.find(
|
|
47461
48604
|
(g) => g.some((q) => Math.hypot(q.cx - p.cx, q.cy - p.cy) < GROUP_R)
|
|
47462
48605
|
);
|
|
47463
48606
|
if (near) near.push(p);
|
|
47464
|
-
else
|
|
48607
|
+
else groups2.push([p]);
|
|
47465
48608
|
}
|
|
47466
48609
|
const ROW_GAP2 = 3;
|
|
47467
48610
|
const step = poiLabH + ROW_GAP2;
|
|
47468
48611
|
const COL_GAP = 16;
|
|
47469
|
-
const
|
|
47470
|
-
|
|
48612
|
+
const makeItems = (group) => group.map((p) => ({ p, ...labelInfo(p) })).sort((a, b) => a.p.cy - b.p.cy || (a.text < b.text ? -1 : 1));
|
|
48613
|
+
const columnRows = (items, side) => {
|
|
47471
48614
|
const left = Math.min(...items.map((o) => o.p.cx - o.p.r));
|
|
47472
48615
|
const right = Math.max(...items.map((o) => o.p.cx + o.p.r));
|
|
47473
|
-
const cyMid = (Math.min(...items.map((o) => o.p.cy)) + Math.max(...items.map((o) => o.p.cy))) / 2;
|
|
47474
48616
|
const maxW = Math.max(...items.map((o) => o.w));
|
|
47475
|
-
const
|
|
47476
|
-
const colX = side === "right" ? right + COL_GAP : left - COL_GAP;
|
|
48617
|
+
const cyMid = (Math.min(...items.map((o) => o.p.cy)) + Math.max(...items.map((o) => o.p.cy))) / 2;
|
|
48618
|
+
const colX = side === "right" ? Math.min(right + COL_GAP, width - 2 - maxW) : Math.max(left - COL_GAP, 2 + maxW);
|
|
47477
48619
|
const totalH = items.length * step;
|
|
47478
48620
|
let startY = cyMid - totalH / 2;
|
|
47479
48621
|
startY = Math.max(2, Math.min(startY, height - totalH - 2));
|
|
47480
|
-
items.
|
|
48622
|
+
return items.map((o, i) => {
|
|
47481
48623
|
const rowCy = startY + i * step + step / 2;
|
|
47482
|
-
|
|
47483
|
-
|
|
47484
|
-
|
|
47485
|
-
|
|
47486
|
-
|
|
47487
|
-
|
|
48624
|
+
return {
|
|
48625
|
+
o,
|
|
48626
|
+
colX,
|
|
48627
|
+
rowCy,
|
|
48628
|
+
rect: {
|
|
48629
|
+
x: side === "right" ? colX : colX - o.w,
|
|
48630
|
+
y: rowCy - poiLabH / 2,
|
|
48631
|
+
w: o.w,
|
|
48632
|
+
h: poiLabH
|
|
48633
|
+
}
|
|
48634
|
+
};
|
|
48635
|
+
});
|
|
48636
|
+
};
|
|
48637
|
+
const wouldColumnBeClean = (items, side) => columnRows(items, side).every(
|
|
48638
|
+
({ rect }) => rect.x >= 0 && rect.x + rect.w <= width && rect.y >= 0 && rect.y + rect.h <= height && !collides(rect)
|
|
48639
|
+
);
|
|
48640
|
+
const defaultColumnSide = (items) => {
|
|
48641
|
+
const right = Math.max(...items.map((o) => o.p.cx + o.p.r));
|
|
48642
|
+
const maxW = Math.max(...items.map((o) => o.w));
|
|
48643
|
+
return right + COL_GAP + maxW <= width - 2 ? "right" : "left";
|
|
48644
|
+
};
|
|
48645
|
+
const commitColumn = (items, side, clusterId) => {
|
|
48646
|
+
for (const { o, colX, rowCy, rect } of columnRows(items, side)) {
|
|
48647
|
+
obstacles.push(rect);
|
|
47488
48648
|
labels.push({
|
|
47489
48649
|
x: colX,
|
|
47490
|
-
y: rowCy +
|
|
48650
|
+
y: rowCy + FONT2 / 3,
|
|
47491
48651
|
text: o.text,
|
|
47492
48652
|
anchor: side === "right" ? "start" : "end",
|
|
47493
48653
|
color: palette.text,
|
|
47494
|
-
halo:
|
|
48654
|
+
halo: false,
|
|
47495
48655
|
haloColor: palette.bg,
|
|
47496
48656
|
leader: {
|
|
47497
48657
|
x1: o.p.cx,
|
|
@@ -47501,24 +48661,141 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47501
48661
|
},
|
|
47502
48662
|
leaderColor: o.p.fill,
|
|
47503
48663
|
poiId: o.p.id,
|
|
47504
|
-
lineNumber: o.p.lineNumber
|
|
48664
|
+
lineNumber: o.p.lineNumber,
|
|
48665
|
+
...clusterId !== void 0 && { clusterMember: clusterId }
|
|
47505
48666
|
});
|
|
48667
|
+
}
|
|
48668
|
+
};
|
|
48669
|
+
const pushHidden = (p) => {
|
|
48670
|
+
const { text, w } = labelInfo(p);
|
|
48671
|
+
let x = p.cx + p.r + GAP;
|
|
48672
|
+
let anchor = "start";
|
|
48673
|
+
if (x + w > width) {
|
|
48674
|
+
x = p.cx - p.r - GAP - w;
|
|
48675
|
+
anchor = "end";
|
|
48676
|
+
}
|
|
48677
|
+
const y = Math.max(0, Math.min(p.cy - poiLabH / 2, height - poiLabH));
|
|
48678
|
+
labels.push({
|
|
48679
|
+
x: anchor === "start" ? x : x + w,
|
|
48680
|
+
y: y + poiLabH / 2 + FONT2 / 3,
|
|
48681
|
+
text,
|
|
48682
|
+
anchor,
|
|
48683
|
+
color: palette.text,
|
|
48684
|
+
halo: false,
|
|
48685
|
+
haloColor: palette.bg,
|
|
48686
|
+
poiId: p.id,
|
|
48687
|
+
hidden: true,
|
|
48688
|
+
lineNumber: p.lineNumber
|
|
47506
48689
|
});
|
|
47507
48690
|
};
|
|
47508
|
-
for (const
|
|
48691
|
+
for (const [clusterId, members] of clusterMembersById) {
|
|
48692
|
+
if (members.length === 0) continue;
|
|
48693
|
+
const items = makeItems(members);
|
|
48694
|
+
const side = wouldColumnBeClean(items, "right") ? "right" : wouldColumnBeClean(items, "left") ? "left" : defaultColumnSide(items);
|
|
48695
|
+
commitColumn(items, side, clusterId);
|
|
48696
|
+
}
|
|
48697
|
+
const maxExtent = MAX_CLUSTER_EXTENT_FACTOR * Math.min(width, height);
|
|
48698
|
+
const clusterPending = [];
|
|
48699
|
+
for (const g of groups2) {
|
|
48700
|
+
const items = makeItems(g);
|
|
47509
48701
|
if (g.length === 1) {
|
|
47510
|
-
const p =
|
|
47511
|
-
const { text, w } = labelInfo(p);
|
|
48702
|
+
const { p, text, w } = items[0];
|
|
47512
48703
|
const side = ["right", "left", "above", "below"].find(
|
|
47513
48704
|
(s) => inlineFits(p, w, s)
|
|
47514
48705
|
);
|
|
47515
|
-
if (side)
|
|
47516
|
-
|
|
47517
|
-
|
|
48706
|
+
if (side) pushInline(p, text, w, side);
|
|
48707
|
+
else commitColumn(items, defaultColumnSide(items));
|
|
48708
|
+
continue;
|
|
48709
|
+
}
|
|
48710
|
+
const left = Math.min(...items.map((o) => o.p.cx - o.p.r));
|
|
48711
|
+
const right = Math.max(...items.map((o) => o.p.cx + o.p.r));
|
|
48712
|
+
const minCy = Math.min(...items.map((o) => o.p.cy));
|
|
48713
|
+
const maxCy = Math.max(...items.map((o) => o.p.cy));
|
|
48714
|
+
const diag = Math.hypot(right - left, maxCy - minCy);
|
|
48715
|
+
if (diag > maxExtent || items.length > MAX_COLUMN_ROWS) {
|
|
48716
|
+
items.forEach((o) => pushHidden(o.p));
|
|
48717
|
+
} else {
|
|
48718
|
+
clusterPending.push(items);
|
|
48719
|
+
}
|
|
48720
|
+
}
|
|
48721
|
+
for (const items of clusterPending) {
|
|
48722
|
+
const side = ["right", "left"].find(
|
|
48723
|
+
(s) => wouldColumnBeClean(items, s)
|
|
48724
|
+
);
|
|
48725
|
+
if (side) commitColumn(items, side);
|
|
48726
|
+
else items.forEach((o) => pushHidden(o.p));
|
|
48727
|
+
}
|
|
48728
|
+
}
|
|
48729
|
+
if (resolved.directives.noContextLabels !== true) {
|
|
48730
|
+
for (const l of labels) {
|
|
48731
|
+
if (l.hidden) continue;
|
|
48732
|
+
const w = labelW(l.text);
|
|
48733
|
+
const x = l.anchor === "start" ? l.x : l.anchor === "end" ? l.x - w : l.x - w / 2;
|
|
48734
|
+
obstacles.push({ x, y: l.y - labelH / 2, w, h: labelH });
|
|
48735
|
+
}
|
|
48736
|
+
for (const box of insets)
|
|
48737
|
+
obstacles.push({ x: box.x, y: box.y, w: box.w, h: box.h });
|
|
48738
|
+
const countryCandidates = [];
|
|
48739
|
+
for (const f of worldLayer.values()) {
|
|
48740
|
+
const iso = typeof f.id === "string" ? f.id : String(f.id ?? "");
|
|
48741
|
+
if (!iso || regionById.has(iso)) continue;
|
|
48742
|
+
let hasReferencedSub = false;
|
|
48743
|
+
for (const k of regionById.keys())
|
|
48744
|
+
if (k.startsWith(iso + "-")) {
|
|
48745
|
+
hasReferencedSub = true;
|
|
48746
|
+
break;
|
|
47518
48747
|
}
|
|
48748
|
+
if (hasReferencedSub) continue;
|
|
48749
|
+
const b = path.bounds(f);
|
|
48750
|
+
const [x0, y0] = b[0];
|
|
48751
|
+
const [x1, y1] = b[1];
|
|
48752
|
+
if (!Number.isFinite(x0) || !Number.isFinite(x1)) continue;
|
|
48753
|
+
const anchorLngLat = WORLD_LABEL_ANCHORS[iso];
|
|
48754
|
+
const a = anchorLngLat ? project(anchorLngLat[0], anchorLngLat[1]) : path.centroid(f);
|
|
48755
|
+
countryCandidates.push({
|
|
48756
|
+
name: f.properties?.name ?? iso,
|
|
48757
|
+
bbox: [x0, y0, x1, y1],
|
|
48758
|
+
anchor: a && Number.isFinite(a[0]) ? [a[0], a[1]] : null
|
|
48759
|
+
});
|
|
48760
|
+
}
|
|
48761
|
+
const framedStateContainers = (resolved.poiFrameContainers ?? []).some(
|
|
48762
|
+
(id) => id.startsWith("US-")
|
|
48763
|
+
);
|
|
48764
|
+
if (usLayer && framedStateContainers) {
|
|
48765
|
+
const containerSet = new Set(resolved.poiFrameContainers);
|
|
48766
|
+
for (const [iso, f] of usLayer) {
|
|
48767
|
+
if (containerSet.has(iso) || regionById.has(iso)) continue;
|
|
48768
|
+
const viewF = cullFeatureToView(f);
|
|
48769
|
+
if (!viewF) continue;
|
|
48770
|
+
const b = path.bounds(viewF);
|
|
48771
|
+
const [x0, y0] = b[0];
|
|
48772
|
+
const [x1, y1] = b[1];
|
|
48773
|
+
if (!Number.isFinite(x0) || !Number.isFinite(x1)) continue;
|
|
48774
|
+
const a = path.centroid(viewF);
|
|
48775
|
+
countryCandidates.push({
|
|
48776
|
+
name: f.properties?.name ?? iso,
|
|
48777
|
+
bbox: [x0, y0, x1, y1],
|
|
48778
|
+
anchor: a && Number.isFinite(a[0]) ? [a[0], a[1]] : null
|
|
48779
|
+
});
|
|
47519
48780
|
}
|
|
47520
|
-
placeColumn(g);
|
|
47521
48781
|
}
|
|
48782
|
+
const contextLabels = placeContextLabels({
|
|
48783
|
+
projection: resolved.projection,
|
|
48784
|
+
dLonSpan,
|
|
48785
|
+
dLatSpan,
|
|
48786
|
+
width,
|
|
48787
|
+
height,
|
|
48788
|
+
waterBodies: data.waterBodies,
|
|
48789
|
+
countries: countryCandidates,
|
|
48790
|
+
palette,
|
|
48791
|
+
project,
|
|
48792
|
+
collides,
|
|
48793
|
+
// Water labels must stay over open water — `fillAt` returns the ocean
|
|
48794
|
+
// backdrop colour off-land and a region fill on-land (lakes/states count
|
|
48795
|
+
// as land here, which is the safe side for an ocean name).
|
|
48796
|
+
overLand: (x, y) => fillAt(x, y) !== water
|
|
48797
|
+
});
|
|
48798
|
+
labels.push(...contextLabels);
|
|
47522
48799
|
}
|
|
47523
48800
|
let legend = null;
|
|
47524
48801
|
if (!resolved.directives.noLegend) {
|
|
@@ -47553,22 +48830,33 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47553
48830
|
...resolved.caption !== void 0 && { caption: resolved.caption },
|
|
47554
48831
|
regions,
|
|
47555
48832
|
rivers,
|
|
48833
|
+
relief,
|
|
48834
|
+
reliefHatch,
|
|
48835
|
+
coastlineStyle,
|
|
47556
48836
|
legs,
|
|
47557
48837
|
pois,
|
|
48838
|
+
clusters,
|
|
47558
48839
|
labels,
|
|
47559
48840
|
legend,
|
|
47560
48841
|
insets,
|
|
47561
|
-
insetRegions
|
|
48842
|
+
insetRegions,
|
|
48843
|
+
projection,
|
|
48844
|
+
stretch: stretchParams,
|
|
48845
|
+
diagnostics: []
|
|
47562
48846
|
};
|
|
47563
48847
|
}
|
|
47564
|
-
var FIT_PAD, RAMP_FLOOR, R_DEFAULT, R_MIN, R_MAX, W_MIN, W_MAX,
|
|
48848
|
+
var FIT_PAD, RAMP_FLOOR, R_DEFAULT, R_MIN, R_MAX, W_MIN, W_MAX, FONT2, MAX_CLUSTER_EXTENT_FACTOR, MAX_COLUMN_ROWS, REGION_LABEL_HALO_RATIO, LAND_TINT_LIGHT, LAND_TINT_DARK, TAG_TINT_LIGHT, TAG_TINT_DARK, WATER_TINT_LIGHT, WATER_TINT_DARK, RIVER_WIDTH, COMPACT_WIDTH_PX, RELIEF_MIN_AREA, RELIEF_MIN_DIM, RELIEF_HATCH_SPACING, RELIEF_HATCH_WIDTH, RELIEF_HATCH_STRENGTH, COASTLINE_RING_COUNT, COASTLINE_D0, COASTLINE_STEP, COASTLINE_THICKNESS, COASTLINE_OPACITY_NEAR, COASTLINE_OPACITY_FAR, COASTLINE_MIN_EXTENT, COASTLINE_MIN_EXTENT_GLOBAL, COASTLINE_STROKE_MIX, FOREIGN_TINT_LIGHT, FOREIGN_TINT_DARK, MUTED_FOREIGN_LIGHT, MUTED_FOREIGN_DARK, COLO_R, GOLDEN_ANGLE, STACK_OVERLAP, STACK_RING_MAX, STACK_RING_GAP, FAN_STEP, ARC_CURVE_FRAC, decodeCache, usConusProjection, alaskaProjection, hawaiiProjection, INSET_STATES, inAlaska, inHawaii, FOREIGN_BORDER, US_NON_CONUS;
|
|
47565
48849
|
var init_layout15 = __esm({
|
|
47566
48850
|
"src/map/layout.ts"() {
|
|
47567
48851
|
"use strict";
|
|
47568
48852
|
init_color_utils();
|
|
48853
|
+
init_geo();
|
|
48854
|
+
init_colorize();
|
|
48855
|
+
init_colors();
|
|
47569
48856
|
init_label_layout();
|
|
47570
48857
|
init_legend_constants();
|
|
47571
48858
|
init_title_constants();
|
|
48859
|
+
init_context_labels();
|
|
47572
48860
|
FIT_PAD = 24;
|
|
47573
48861
|
RAMP_FLOOR = 15;
|
|
47574
48862
|
R_DEFAULT = 6;
|
|
@@ -47576,29 +48864,66 @@ var init_layout15 = __esm({
|
|
|
47576
48864
|
R_MAX = 22;
|
|
47577
48865
|
W_MIN = 1.25;
|
|
47578
48866
|
W_MAX = 8;
|
|
47579
|
-
|
|
47580
|
-
|
|
47581
|
-
|
|
47582
|
-
|
|
48867
|
+
FONT2 = 11;
|
|
48868
|
+
MAX_CLUSTER_EXTENT_FACTOR = 0.18;
|
|
48869
|
+
MAX_COLUMN_ROWS = 7;
|
|
48870
|
+
REGION_LABEL_HALO_RATIO = 4.5;
|
|
48871
|
+
LAND_TINT_LIGHT = 12;
|
|
48872
|
+
LAND_TINT_DARK = 24;
|
|
47583
48873
|
TAG_TINT_LIGHT = 60;
|
|
47584
48874
|
TAG_TINT_DARK = 68;
|
|
47585
|
-
|
|
48875
|
+
WATER_TINT_LIGHT = 24;
|
|
48876
|
+
WATER_TINT_DARK = 24;
|
|
47586
48877
|
RIVER_WIDTH = 1.3;
|
|
48878
|
+
COMPACT_WIDTH_PX = 480;
|
|
48879
|
+
RELIEF_MIN_AREA = 12;
|
|
48880
|
+
RELIEF_MIN_DIM = 2;
|
|
48881
|
+
RELIEF_HATCH_SPACING = 2;
|
|
48882
|
+
RELIEF_HATCH_WIDTH = 0.15;
|
|
48883
|
+
RELIEF_HATCH_STRENGTH = 32;
|
|
48884
|
+
COASTLINE_RING_COUNT = 5;
|
|
48885
|
+
COASTLINE_D0 = 16e-4;
|
|
48886
|
+
COASTLINE_STEP = 28e-4;
|
|
48887
|
+
COASTLINE_THICKNESS = 14e-4;
|
|
48888
|
+
COASTLINE_OPACITY_NEAR = 0.5;
|
|
48889
|
+
COASTLINE_OPACITY_FAR = 0.1;
|
|
48890
|
+
COASTLINE_MIN_EXTENT = 6e-4;
|
|
48891
|
+
COASTLINE_MIN_EXTENT_GLOBAL = 6e-4;
|
|
48892
|
+
COASTLINE_STROKE_MIX = 32;
|
|
47587
48893
|
FOREIGN_TINT_LIGHT = 30;
|
|
47588
48894
|
FOREIGN_TINT_DARK = 62;
|
|
47589
|
-
MUTED_WATER_LIGHT = 14;
|
|
47590
|
-
MUTED_WATER_DARK = 10;
|
|
47591
48895
|
MUTED_FOREIGN_LIGHT = 28;
|
|
47592
48896
|
MUTED_FOREIGN_DARK = 16;
|
|
47593
|
-
MUTED_LAND_DARK = 24;
|
|
47594
48897
|
COLO_R = 9;
|
|
47595
48898
|
GOLDEN_ANGLE = 2.399963229728653;
|
|
48899
|
+
STACK_OVERLAP = 1;
|
|
48900
|
+
STACK_RING_MAX = 8;
|
|
48901
|
+
STACK_RING_GAP = 4;
|
|
47596
48902
|
FAN_STEP = 16;
|
|
47597
48903
|
ARC_CURVE_FRAC = 0.18;
|
|
48904
|
+
decodeCache = /* @__PURE__ */ new WeakMap();
|
|
47598
48905
|
usConusProjection = () => geoConicEqualArea().parallels([29.5, 45.5]).rotate([96, 0]);
|
|
47599
48906
|
alaskaProjection = () => geoConicEqualArea().rotate([154, 0]).center([-2, 58.5]).parallels([55, 65]);
|
|
47600
48907
|
hawaiiProjection = () => geoMercator();
|
|
47601
48908
|
INSET_STATES = /* @__PURE__ */ new Set(["US-AK", "US-HI"]);
|
|
48909
|
+
inAlaska = (lon, lat) => lat >= 51 && (lon <= -129 || lon >= 172);
|
|
48910
|
+
inHawaii = (lon, lat) => lat >= 18 && lat <= 23 && lon >= -161 && lon <= -154;
|
|
48911
|
+
FOREIGN_BORDER = {
|
|
48912
|
+
CA: [
|
|
48913
|
+
"US-AK",
|
|
48914
|
+
"US-WA",
|
|
48915
|
+
"US-ID",
|
|
48916
|
+
"US-MT",
|
|
48917
|
+
"US-ND",
|
|
48918
|
+
"US-MN",
|
|
48919
|
+
"US-MI",
|
|
48920
|
+
"US-NY",
|
|
48921
|
+
"US-VT",
|
|
48922
|
+
"US-NH",
|
|
48923
|
+
"US-ME"
|
|
48924
|
+
],
|
|
48925
|
+
MX: ["US-CA", "US-AZ", "US-NM", "US-TX"]
|
|
48926
|
+
};
|
|
47602
48927
|
US_NON_CONUS = /* @__PURE__ */ new Set([
|
|
47603
48928
|
"US-AK",
|
|
47604
48929
|
"US-HI",
|
|
@@ -47618,6 +48943,58 @@ __export(renderer_exports16, {
|
|
|
47618
48943
|
renderMapForExport: () => renderMapForExport
|
|
47619
48944
|
});
|
|
47620
48945
|
import * as d3Selection18 from "d3-selection";
|
|
48946
|
+
function pointInRing2(px, py, ring) {
|
|
48947
|
+
let inside = false;
|
|
48948
|
+
for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
|
|
48949
|
+
const [xi, yi] = ring[i];
|
|
48950
|
+
const [xj, yj] = ring[j];
|
|
48951
|
+
if (yi > py !== yj > py && px < (xj - xi) * (py - yi) / (yj - yi) + xi)
|
|
48952
|
+
inside = !inside;
|
|
48953
|
+
}
|
|
48954
|
+
return inside;
|
|
48955
|
+
}
|
|
48956
|
+
function ringToPath(ring) {
|
|
48957
|
+
let d = "";
|
|
48958
|
+
for (let i = 0; i < ring.length; i++)
|
|
48959
|
+
d += (i ? "L" : "M") + ring[i][0] + "," + ring[i][1];
|
|
48960
|
+
return d + "Z";
|
|
48961
|
+
}
|
|
48962
|
+
function coastlineOuterRings(regions, minExtent) {
|
|
48963
|
+
const paths = [];
|
|
48964
|
+
for (const r of regions) {
|
|
48965
|
+
const rings = parsePathRings(r.d);
|
|
48966
|
+
for (let i = 0; i < rings.length; i++) {
|
|
48967
|
+
const ring = rings[i];
|
|
48968
|
+
if (ring.length < 3) continue;
|
|
48969
|
+
let minX = Infinity;
|
|
48970
|
+
let minY = Infinity;
|
|
48971
|
+
let maxX = -Infinity;
|
|
48972
|
+
let maxY = -Infinity;
|
|
48973
|
+
for (const [x, y] of ring) {
|
|
48974
|
+
if (x < minX) minX = x;
|
|
48975
|
+
if (x > maxX) maxX = x;
|
|
48976
|
+
if (y < minY) minY = y;
|
|
48977
|
+
if (y > maxY) maxY = y;
|
|
48978
|
+
}
|
|
48979
|
+
if (Math.max(maxX - minX, maxY - minY) < minExtent) continue;
|
|
48980
|
+
const [fx, fy] = ring[0];
|
|
48981
|
+
let depth = 0;
|
|
48982
|
+
for (let j = 0; j < rings.length; j++)
|
|
48983
|
+
if (j !== i && pointInRing2(fx, fy, rings[j])) depth++;
|
|
48984
|
+
if (depth % 2 === 1) continue;
|
|
48985
|
+
paths.push(ringToPath(ring));
|
|
48986
|
+
}
|
|
48987
|
+
}
|
|
48988
|
+
return paths;
|
|
48989
|
+
}
|
|
48990
|
+
function appendWaterLines(g, outerRings, style, flatWater) {
|
|
48991
|
+
const d = outerRings.join(" ");
|
|
48992
|
+
const linesOuterFirst = [...style.lines].sort((a, b) => b.d - a.d);
|
|
48993
|
+
for (const line12 of linesOuterFirst) {
|
|
48994
|
+
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");
|
|
48995
|
+
g.append("path").attr("d", d).attr("stroke", flatWater).attr("stroke-width", 2 * line12.d).attr("stroke-linejoin", "round").attr("stroke-linecap", "round");
|
|
48996
|
+
}
|
|
48997
|
+
}
|
|
47621
48998
|
function renderMap(container, resolved, data, palette, isDark, onClickItem, exportDims, activeGroupOverride) {
|
|
47622
48999
|
d3Selection18.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
47623
49000
|
const width = exportDims?.width ?? container.clientWidth;
|
|
@@ -47630,6 +49007,11 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47630
49007
|
{
|
|
47631
49008
|
palette,
|
|
47632
49009
|
isDark,
|
|
49010
|
+
// Export-only: forward the contain-fit request from mapExportDimensions so a
|
|
49011
|
+
// clamped/floored (off-aspect) export canvas letterboxes instead of
|
|
49012
|
+
// stretch-distorting. The in-app preview pane passes no exportDims → unset →
|
|
49013
|
+
// keeps the global stretch-fill.
|
|
49014
|
+
preferContain: exportDims?.preferContain ?? false,
|
|
47633
49015
|
...activeGroupOverride !== void 0 && {
|
|
47634
49016
|
activeGroup: activeGroupOverride
|
|
47635
49017
|
}
|
|
@@ -47643,6 +49025,7 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47643
49025
|
const gRegions = svg.append("g").attr("class", "dgmo-map-regions");
|
|
47644
49026
|
const drawRegion = (g, r, strokeWidth) => {
|
|
47645
49027
|
const p = g.append("path").attr("d", r.d).attr("fill", r.fill).attr("stroke", r.stroke).attr("stroke-width", strokeWidth);
|
|
49028
|
+
if (r.label) p.attr("data-region-name", r.label);
|
|
47646
49029
|
if (r.layer !== "base") {
|
|
47647
49030
|
p.classed("dgmo-map-region", true).attr("data-region", r.id);
|
|
47648
49031
|
if (r.value !== void 0) p.attr("data-value", r.value);
|
|
@@ -47663,6 +49046,52 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47663
49046
|
}
|
|
47664
49047
|
};
|
|
47665
49048
|
for (const r of layout.regions) drawRegion(gRegions, r, 0.5);
|
|
49049
|
+
if (layout.relief.length && layout.reliefHatch) {
|
|
49050
|
+
const h = layout.reliefHatch;
|
|
49051
|
+
const rangeClipId = "dgmo-relief-clip";
|
|
49052
|
+
const landClipId = "dgmo-relief-land";
|
|
49053
|
+
const rangeClip = defs.append("clipPath").attr("id", rangeClipId);
|
|
49054
|
+
for (const s of layout.relief) rangeClip.append("path").attr("d", s.d);
|
|
49055
|
+
const landClip = defs.append("clipPath").attr("id", landClipId);
|
|
49056
|
+
for (const r of layout.regions)
|
|
49057
|
+
if (r.id !== "lake") landClip.append("path").attr("d", r.d);
|
|
49058
|
+
const gRelief = svg.append("g").attr("clip-path", `url(#${landClipId})`).append("g").attr("class", "dgmo-map-relief").attr("clip-path", `url(#${rangeClipId})`).attr("stroke", h.color).attr("stroke-width", h.width).attr("vector-effect", "non-scaling-stroke");
|
|
49059
|
+
for (let y = h.spacing; y < height; y += h.spacing) {
|
|
49060
|
+
gRelief.append("line").attr("x1", 0).attr("y1", y).attr("x2", width).attr("y2", y);
|
|
49061
|
+
}
|
|
49062
|
+
}
|
|
49063
|
+
if (layout.coastlineStyle) {
|
|
49064
|
+
const cs = layout.coastlineStyle;
|
|
49065
|
+
const maskId = "dgmo-map-water-mask";
|
|
49066
|
+
const mask = defs.append("mask").attr("id", maskId).attr("maskUnits", "userSpaceOnUse").attr("x", 0).attr("y", 0).attr("width", width).attr("height", height);
|
|
49067
|
+
mask.append("rect").attr("x", 0).attr("y", 0).attr("width", width).attr("height", height).attr("fill", "white");
|
|
49068
|
+
const landD = layout.regions.filter((r) => r.id !== "lake").map((r) => r.d).join(" ");
|
|
49069
|
+
const lakeD = layout.regions.filter((r) => r.id === "lake").map((r) => r.d).join(" ");
|
|
49070
|
+
if (landD) mask.append("path").attr("d", landD).attr("fill", "black");
|
|
49071
|
+
if (lakeD) mask.append("path").attr("d", lakeD).attr("fill", "white");
|
|
49072
|
+
if (layout.insets.length) {
|
|
49073
|
+
const reach = Math.max(0, ...cs.lines.map((l) => l.d + l.thickness));
|
|
49074
|
+
for (const box of layout.insets) {
|
|
49075
|
+
const d = box.points.map((p, i) => `${i ? "L" : "M"}${p[0]},${p[1]}`).join("") + "Z";
|
|
49076
|
+
mask.append("path").attr("d", d).attr("fill", "black").attr("stroke", "black").attr("stroke-width", 2 * reach).attr("stroke-linejoin", "round");
|
|
49077
|
+
}
|
|
49078
|
+
}
|
|
49079
|
+
const gWater = svg.append("g").attr("class", "dgmo-map-water-lines").attr("fill", "none").attr("mask", `url(#${maskId})`);
|
|
49080
|
+
appendWaterLines(
|
|
49081
|
+
gWater,
|
|
49082
|
+
coastlineOuterRings(layout.regions, cs.minExtent),
|
|
49083
|
+
cs,
|
|
49084
|
+
layout.background
|
|
49085
|
+
);
|
|
49086
|
+
const byStroke = /* @__PURE__ */ new Map();
|
|
49087
|
+
for (const r of layout.regions) {
|
|
49088
|
+
const arr = byStroke.get(r.stroke);
|
|
49089
|
+
if (arr) arr.push(r.d);
|
|
49090
|
+
else byStroke.set(r.stroke, [r.d]);
|
|
49091
|
+
}
|
|
49092
|
+
for (const [stroke2, ds] of byStroke)
|
|
49093
|
+
gWater.append("path").attr("d", ds.join(" ")).attr("stroke", stroke2).attr("stroke-width", 0.5).attr("stroke-linejoin", "round");
|
|
49094
|
+
}
|
|
47666
49095
|
if (layout.rivers.length) {
|
|
47667
49096
|
const gRivers = svg.append("g").attr("class", "dgmo-map-rivers").attr("fill", "none");
|
|
47668
49097
|
for (const r of layout.rivers) {
|
|
@@ -47671,15 +49100,61 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47671
49100
|
}
|
|
47672
49101
|
if (layout.insets.length) {
|
|
47673
49102
|
const insetG = svg.append("g").attr("class", "dgmo-map-insets");
|
|
47674
|
-
|
|
49103
|
+
layout.insets.forEach((box, bi) => {
|
|
47675
49104
|
const d = box.points.map((p, i) => `${i ? "L" : "M"}${p[0]},${p[1]}`).join("") + "Z";
|
|
47676
49105
|
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");
|
|
47677
|
-
|
|
49106
|
+
if (box.contextLand) {
|
|
49107
|
+
const clipId = `dgmo-map-inset-clip-${bi}`;
|
|
49108
|
+
defs.append("clipPath").attr("id", clipId).append("path").attr("d", d);
|
|
49109
|
+
insetG.append("path").attr("d", box.contextLand.d).attr("fill", box.contextLand.fill).attr("clip-path", `url(#${clipId})`);
|
|
49110
|
+
}
|
|
49111
|
+
});
|
|
47678
49112
|
for (const r of layout.insetRegions) drawRegion(insetG, r, 0.5);
|
|
47679
|
-
|
|
49113
|
+
if (layout.coastlineStyle) {
|
|
49114
|
+
const cs = layout.coastlineStyle;
|
|
49115
|
+
const maskId = "dgmo-map-inset-water-mask";
|
|
49116
|
+
const mask = defs.append("mask").attr("id", maskId).attr("maskUnits", "userSpaceOnUse").attr("x", 0).attr("y", 0).attr("width", width).attr("height", height);
|
|
49117
|
+
for (const box of layout.insets) {
|
|
49118
|
+
const d = box.points.map((p, i) => `${i ? "L" : "M"}${p[0]},${p[1]}`).join("") + "Z";
|
|
49119
|
+
mask.append("path").attr("d", d).attr("fill", "white");
|
|
49120
|
+
}
|
|
49121
|
+
layout.insets.forEach((box, bi) => {
|
|
49122
|
+
if (box.contextLand)
|
|
49123
|
+
mask.append("path").attr("d", box.contextLand.d).attr("fill", "black").attr("clip-path", `url(#dgmo-map-inset-clip-${bi})`);
|
|
49124
|
+
});
|
|
49125
|
+
for (const r of layout.insetRegions)
|
|
49126
|
+
if (r.id !== "lake")
|
|
49127
|
+
mask.append("path").attr("d", r.d).attr("fill", "black");
|
|
49128
|
+
for (const r of layout.insetRegions)
|
|
49129
|
+
if (r.id === "lake")
|
|
49130
|
+
mask.append("path").attr("d", r.d).attr("fill", "white");
|
|
49131
|
+
const clipId = "dgmo-map-inset-water-clip";
|
|
49132
|
+
const clip = defs.append("clipPath").attr("id", clipId);
|
|
49133
|
+
for (const box of layout.insets) {
|
|
49134
|
+
const d = box.points.map((p, i) => `${i ? "L" : "M"}${p[0]},${p[1]}`).join("") + "Z";
|
|
49135
|
+
clip.append("path").attr("d", d);
|
|
49136
|
+
}
|
|
49137
|
+
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})`);
|
|
49138
|
+
appendWaterLines(
|
|
49139
|
+
gInsetWater,
|
|
49140
|
+
coastlineOuterRings(layout.insetRegions, cs.minExtent),
|
|
49141
|
+
cs,
|
|
49142
|
+
layout.background
|
|
49143
|
+
);
|
|
49144
|
+
for (const r of layout.insetRegions)
|
|
49145
|
+
gInsetWater.append("path").attr("d", r.d).attr("stroke", r.stroke).attr("stroke-width", 0.5).attr("stroke-linejoin", "round");
|
|
49146
|
+
}
|
|
49147
|
+
}
|
|
49148
|
+
const wireSync = (sel, lineNumber) => {
|
|
49149
|
+
if (lineNumber < 1) return;
|
|
49150
|
+
sel.attr("data-line-number", lineNumber);
|
|
49151
|
+
if (onClickItem)
|
|
49152
|
+
sel.style("cursor", "pointer").on("click", () => onClickItem(lineNumber));
|
|
49153
|
+
};
|
|
47680
49154
|
const gLegs = svg.append("g").attr("class", "dgmo-map-legs").attr("fill", "none");
|
|
47681
49155
|
layout.legs.forEach((leg, i) => {
|
|
47682
49156
|
const p = gLegs.append("path").attr("d", leg.d).attr("stroke", leg.color).attr("stroke-width", leg.width).attr("stroke-linecap", "round");
|
|
49157
|
+
wireSync(p, leg.lineNumber);
|
|
47683
49158
|
if (leg.arrow) {
|
|
47684
49159
|
const id = `dgmo-map-arrow-${i}`;
|
|
47685
49160
|
const s = arrowSize(leg.width);
|
|
@@ -47687,25 +49162,38 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47687
49162
|
p.attr("marker-end", `url(#${id})`);
|
|
47688
49163
|
}
|
|
47689
49164
|
if (leg.label !== void 0 && leg.labelX !== void 0) {
|
|
47690
|
-
emitText(
|
|
49165
|
+
const lt = emitText(
|
|
47691
49166
|
gLegs,
|
|
47692
49167
|
leg.labelX,
|
|
47693
49168
|
leg.labelY ?? 0,
|
|
47694
49169
|
leg.label,
|
|
47695
49170
|
"middle",
|
|
47696
|
-
palette.textMuted,
|
|
47697
|
-
haloColor,
|
|
47698
|
-
true,
|
|
49171
|
+
leg.labelColor ?? palette.textMuted,
|
|
49172
|
+
leg.labelHaloColor ?? haloColor,
|
|
49173
|
+
leg.labelHalo ?? true,
|
|
47699
49174
|
LABEL_FONT - 1
|
|
47700
49175
|
);
|
|
49176
|
+
wireSync(lt, leg.lineNumber);
|
|
47701
49177
|
}
|
|
47702
49178
|
});
|
|
49179
|
+
const gSpider = svg.append("g").attr("class", "dgmo-map-spider");
|
|
49180
|
+
for (const cl of layout.clusters) {
|
|
49181
|
+
if (!exportDims) {
|
|
49182
|
+
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");
|
|
49183
|
+
}
|
|
49184
|
+
for (const leg of cl.legs) {
|
|
49185
|
+
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");
|
|
49186
|
+
}
|
|
49187
|
+
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");
|
|
49188
|
+
}
|
|
47703
49189
|
const gPois = svg.append("g").attr("class", "dgmo-map-pois");
|
|
47704
49190
|
for (const poi of layout.pois) {
|
|
47705
49191
|
if (poi.isOrigin) {
|
|
47706
49192
|
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);
|
|
47707
49193
|
}
|
|
47708
49194
|
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);
|
|
49195
|
+
if (poi.clusterId !== void 0)
|
|
49196
|
+
c.attr("data-cluster-member", poi.clusterId);
|
|
47709
49197
|
if (poi.tags) {
|
|
47710
49198
|
for (const [group, value] of Object.entries(poi.tags)) {
|
|
47711
49199
|
c.attr(`data-tag-${group.toLowerCase()}`, value.toLowerCase());
|
|
@@ -47733,12 +49221,32 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47733
49221
|
}
|
|
47734
49222
|
const gLabels = svg.append("g").attr("class", "dgmo-map-labels");
|
|
47735
49223
|
for (const lab of layout.labels) {
|
|
49224
|
+
if (lab.hidden) {
|
|
49225
|
+
if (exportDims) continue;
|
|
49226
|
+
emitText(
|
|
49227
|
+
gLabels,
|
|
49228
|
+
lab.x,
|
|
49229
|
+
lab.y,
|
|
49230
|
+
lab.text,
|
|
49231
|
+
lab.anchor,
|
|
49232
|
+
lab.color,
|
|
49233
|
+
lab.haloColor,
|
|
49234
|
+
lab.halo,
|
|
49235
|
+
LABEL_FONT,
|
|
49236
|
+
lab.italic,
|
|
49237
|
+
lab.letterSpacing
|
|
49238
|
+
).attr("data-poi", lab.poiId ?? null).attr("data-poi-hidden", "").style("opacity", 0).style("pointer-events", "none");
|
|
49239
|
+
continue;
|
|
49240
|
+
}
|
|
47736
49241
|
if (lab.leader) {
|
|
47737
49242
|
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(
|
|
47738
49243
|
"stroke",
|
|
47739
49244
|
lab.leaderColor ?? mix(palette.textMuted, palette.bg, 60)
|
|
47740
49245
|
).attr("stroke-width", lab.leaderColor ? 1 : 0.75);
|
|
47741
49246
|
if (lab.poiId !== void 0) line12.attr("data-poi", lab.poiId);
|
|
49247
|
+
if (lab.clusterMember !== void 0)
|
|
49248
|
+
line12.attr("data-cluster-member", lab.clusterMember);
|
|
49249
|
+
wireSync(line12, lab.lineNumber);
|
|
47742
49250
|
}
|
|
47743
49251
|
const t = emitText(
|
|
47744
49252
|
gLabels,
|
|
@@ -47749,11 +49257,38 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47749
49257
|
lab.color,
|
|
47750
49258
|
lab.haloColor,
|
|
47751
49259
|
lab.halo,
|
|
47752
|
-
LABEL_FONT
|
|
49260
|
+
LABEL_FONT,
|
|
49261
|
+
lab.italic,
|
|
49262
|
+
lab.letterSpacing,
|
|
49263
|
+
lab.lines
|
|
47753
49264
|
);
|
|
47754
49265
|
if (lab.poiId !== void 0) {
|
|
47755
49266
|
t.attr("data-poi", lab.poiId).style("cursor", "default");
|
|
47756
49267
|
}
|
|
49268
|
+
if (lab.clusterMember !== void 0) {
|
|
49269
|
+
t.attr("data-cluster-member", lab.clusterMember);
|
|
49270
|
+
}
|
|
49271
|
+
wireSync(t, lab.lineNumber);
|
|
49272
|
+
}
|
|
49273
|
+
if (!exportDims && layout.clusters.length) {
|
|
49274
|
+
const gBadge = svg.append("g").attr("class", "dgmo-map-cluster-badges");
|
|
49275
|
+
for (const cl of layout.clusters) {
|
|
49276
|
+
const g = gBadge.append("g").attr("data-cluster", cl.id).style("opacity", 0).style("pointer-events", "none");
|
|
49277
|
+
const R = 9;
|
|
49278
|
+
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);
|
|
49279
|
+
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);
|
|
49280
|
+
emitText(
|
|
49281
|
+
g,
|
|
49282
|
+
cl.cx,
|
|
49283
|
+
cl.cy + 3,
|
|
49284
|
+
String(cl.count),
|
|
49285
|
+
"middle",
|
|
49286
|
+
palette.text,
|
|
49287
|
+
palette.bg,
|
|
49288
|
+
false,
|
|
49289
|
+
LABEL_FONT
|
|
49290
|
+
);
|
|
49291
|
+
}
|
|
47757
49292
|
}
|
|
47758
49293
|
if (layout.legend) {
|
|
47759
49294
|
const legendY = (layout.title ? TITLE_Y + TITLE_FONT_SIZE : 0) + (layout.subtitle ? TITLE_FONT_SIZE : 0) + 8;
|
|
@@ -47787,10 +49322,10 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47787
49322
|
}
|
|
47788
49323
|
}
|
|
47789
49324
|
if (layout.title) {
|
|
47790
|
-
svg.append("text").attr("x", width / 2).attr("y", TITLE_Y).attr("text-anchor", "middle").attr("font-size", TITLE_FONT_SIZE).attr("font-weight", TITLE_FONT_WEIGHT).attr("fill", palette.text).attr("paint-order", "stroke fill").attr("stroke", palette.bg).attr("stroke-width", 4).attr("stroke-linejoin", "round").attr("stroke-opacity", 0.7).text(layout.title);
|
|
49325
|
+
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);
|
|
47791
49326
|
}
|
|
47792
49327
|
if (layout.subtitle) {
|
|
47793
|
-
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);
|
|
49328
|
+
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);
|
|
47794
49329
|
}
|
|
47795
49330
|
if (layout.caption) {
|
|
47796
49331
|
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);
|
|
@@ -47799,10 +49334,21 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47799
49334
|
function renderMapForExport(container, resolved, data, palette, isDark, exportDims) {
|
|
47800
49335
|
renderMap(container, resolved, data, palette, isDark, void 0, exportDims);
|
|
47801
49336
|
}
|
|
47802
|
-
function emitText(g, x, y, text, anchor, color, halo, withHalo, fontSize) {
|
|
47803
|
-
const t = g.append("text").attr("x", x).attr("y", y).attr("text-anchor", anchor).attr("font-size", fontSize).attr("fill", color)
|
|
49337
|
+
function emitText(g, x, y, text, anchor, color, halo, withHalo, fontSize, italic, letterSpacing, lines) {
|
|
49338
|
+
const t = g.append("text").attr("x", x).attr("y", y).attr("text-anchor", anchor).attr("font-size", fontSize).attr("fill", color);
|
|
49339
|
+
if (lines && lines.length > 1) {
|
|
49340
|
+
const lineHeight = fontSize + 2;
|
|
49341
|
+
const startDy = -((lines.length - 1) / 2) * lineHeight;
|
|
49342
|
+
lines.forEach((ln, i) => {
|
|
49343
|
+
t.append("tspan").attr("x", x).attr("dy", i === 0 ? startDy : lineHeight).text(ln);
|
|
49344
|
+
});
|
|
49345
|
+
} else {
|
|
49346
|
+
t.text(text);
|
|
49347
|
+
}
|
|
49348
|
+
if (italic) t.attr("font-style", "italic");
|
|
49349
|
+
if (letterSpacing) t.attr("letter-spacing", letterSpacing);
|
|
47804
49350
|
if (withHalo) {
|
|
47805
|
-
t.attr("paint-order", "stroke fill").attr("stroke", halo).attr("stroke-width",
|
|
49351
|
+
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);
|
|
47806
49352
|
}
|
|
47807
49353
|
return t;
|
|
47808
49354
|
}
|
|
@@ -47819,6 +49365,178 @@ var init_renderer16 = __esm({
|
|
|
47819
49365
|
}
|
|
47820
49366
|
});
|
|
47821
49367
|
|
|
49368
|
+
// src/map/dimensions.ts
|
|
49369
|
+
var dimensions_exports = {};
|
|
49370
|
+
__export(dimensions_exports, {
|
|
49371
|
+
mapContentAspect: () => mapContentAspect,
|
|
49372
|
+
mapExportDimensions: () => mapExportDimensions
|
|
49373
|
+
});
|
|
49374
|
+
import { geoPath as geoPath2 } from "d3-geo";
|
|
49375
|
+
function mapContentAspect(resolved, data, ref = REF) {
|
|
49376
|
+
const { projection, fitTarget } = buildMapProjection(resolved, data);
|
|
49377
|
+
projection.fitSize([ref, ref], fitTarget);
|
|
49378
|
+
const b = geoPath2(projection).bounds(fitTarget);
|
|
49379
|
+
const w = b[1][0] - b[0][0];
|
|
49380
|
+
const h = b[1][1] - b[0][1];
|
|
49381
|
+
const aspect = w / h;
|
|
49382
|
+
return Number.isFinite(aspect) && aspect > 0 ? aspect : FALLBACK_ASPECT;
|
|
49383
|
+
}
|
|
49384
|
+
function mapExportDimensions(resolved, data, baseWidth = 1200) {
|
|
49385
|
+
const raw = mapContentAspect(resolved, data);
|
|
49386
|
+
const clamped = Math.max(ASPECT_MIN, Math.min(ASPECT_MAX, raw));
|
|
49387
|
+
const width = baseWidth;
|
|
49388
|
+
let height = Math.round(width / clamped);
|
|
49389
|
+
let chromeReserve = 0;
|
|
49390
|
+
if (resolved.title && resolved.pois.length > 0) {
|
|
49391
|
+
const bannerBottom = (resolved.subtitle ? TITLE_Y + TITLE_FONT_SIZE : TITLE_Y) + TITLE_FONT_SIZE / 2;
|
|
49392
|
+
chromeReserve += Math.max(FIT_PAD2, bannerBottom + TITLE_GAP) - FIT_PAD2;
|
|
49393
|
+
}
|
|
49394
|
+
let floored = false;
|
|
49395
|
+
if (height - chromeReserve < MIN_MAP_BAND) {
|
|
49396
|
+
height = Math.round(chromeReserve + MIN_MAP_BAND);
|
|
49397
|
+
floored = true;
|
|
49398
|
+
}
|
|
49399
|
+
const preferContain = clamped !== raw || floored;
|
|
49400
|
+
return { width, height, preferContain };
|
|
49401
|
+
}
|
|
49402
|
+
var FIT_PAD2, TITLE_GAP, ASPECT_MAX, ASPECT_MIN, MIN_MAP_BAND, FALLBACK_ASPECT, REF;
|
|
49403
|
+
var init_dimensions = __esm({
|
|
49404
|
+
"src/map/dimensions.ts"() {
|
|
49405
|
+
"use strict";
|
|
49406
|
+
init_title_constants();
|
|
49407
|
+
init_layout15();
|
|
49408
|
+
FIT_PAD2 = 24;
|
|
49409
|
+
TITLE_GAP = 16;
|
|
49410
|
+
ASPECT_MAX = 3;
|
|
49411
|
+
ASPECT_MIN = 0.9;
|
|
49412
|
+
MIN_MAP_BAND = 200;
|
|
49413
|
+
FALLBACK_ASPECT = 1.5;
|
|
49414
|
+
REF = 1e3;
|
|
49415
|
+
}
|
|
49416
|
+
});
|
|
49417
|
+
|
|
49418
|
+
// src/map/load-data.ts
|
|
49419
|
+
var load_data_exports = {};
|
|
49420
|
+
__export(load_data_exports, {
|
|
49421
|
+
loadMapData: () => loadMapData
|
|
49422
|
+
});
|
|
49423
|
+
async function loadNodeBuiltins() {
|
|
49424
|
+
const [{ readFile }, { fileURLToPath }, { dirname: dirname2, resolve }] = await Promise.all([
|
|
49425
|
+
import("fs/promises"),
|
|
49426
|
+
import("url"),
|
|
49427
|
+
import("path")
|
|
49428
|
+
]);
|
|
49429
|
+
return { readFile, fileURLToPath, dirname: dirname2, resolve };
|
|
49430
|
+
}
|
|
49431
|
+
async function readJson(nb, dir, name) {
|
|
49432
|
+
return JSON.parse(await nb.readFile(nb.resolve(dir, name), "utf8"));
|
|
49433
|
+
}
|
|
49434
|
+
async function firstExistingDir(nb, baseDir) {
|
|
49435
|
+
for (const rel of CANDIDATE_DIRS) {
|
|
49436
|
+
const dir = nb.resolve(baseDir, rel);
|
|
49437
|
+
try {
|
|
49438
|
+
await nb.readFile(nb.resolve(dir, FILES.gazetteer), "utf8");
|
|
49439
|
+
return dir;
|
|
49440
|
+
} catch {
|
|
49441
|
+
}
|
|
49442
|
+
}
|
|
49443
|
+
throw new Error(
|
|
49444
|
+
`map data assets not found near ${baseDir} (looked in ${CANDIDATE_DIRS.join(", ")}). Run \`pnpm build:map-data\` and \`pnpm build\`.`
|
|
49445
|
+
);
|
|
49446
|
+
}
|
|
49447
|
+
function validate(data) {
|
|
49448
|
+
const topoOk = (t) => !!t && t.type === "Topology" && !!t.objects;
|
|
49449
|
+
if (!topoOk(data.worldCoarse) || !topoOk(data.worldDetail) || !topoOk(data.usStates) || !data.gazetteer || !Array.isArray(data.gazetteer.cities) || !data.gazetteer.byName) {
|
|
49450
|
+
throw new Error("map data assets are malformed (failed shape validation)");
|
|
49451
|
+
}
|
|
49452
|
+
return data;
|
|
49453
|
+
}
|
|
49454
|
+
function moduleBaseDir(nb) {
|
|
49455
|
+
try {
|
|
49456
|
+
const url = import.meta.url;
|
|
49457
|
+
if (url) return nb.dirname(nb.fileURLToPath(url));
|
|
49458
|
+
} catch {
|
|
49459
|
+
}
|
|
49460
|
+
if (typeof __dirname !== "undefined") return __dirname;
|
|
49461
|
+
return process.cwd();
|
|
49462
|
+
}
|
|
49463
|
+
function loadMapData() {
|
|
49464
|
+
cache ??= (async () => {
|
|
49465
|
+
const nb = await loadNodeBuiltins();
|
|
49466
|
+
const dir = await firstExistingDir(nb, moduleBaseDir(nb));
|
|
49467
|
+
const [
|
|
49468
|
+
worldCoarse,
|
|
49469
|
+
worldDetail,
|
|
49470
|
+
usStates,
|
|
49471
|
+
lakes,
|
|
49472
|
+
rivers,
|
|
49473
|
+
mountainRanges,
|
|
49474
|
+
naLand,
|
|
49475
|
+
naLakes,
|
|
49476
|
+
waterBodies,
|
|
49477
|
+
gazetteer
|
|
49478
|
+
] = await Promise.all([
|
|
49479
|
+
// worldCoarse (110m) is LOAD-BEARING but NOT a render source: the world
|
|
49480
|
+
// basemap renders from worldDetail (50m) at all scales (resolver pins
|
|
49481
|
+
// basemaps.world = 'detail'). Coarse stays as the authoritative region
|
|
49482
|
+
// name index + dominant-landmass bbox source in resolver.ts. Do not drop it.
|
|
49483
|
+
readJson(nb, dir, FILES.worldCoarse),
|
|
49484
|
+
readJson(nb, dir, FILES.worldDetail),
|
|
49485
|
+
readJson(nb, dir, FILES.usStates),
|
|
49486
|
+
// Lakes/rivers/mountain/NA/water assets are optional — older bundles may predate them.
|
|
49487
|
+
readJson(nb, dir, FILES.lakes).catch(() => void 0),
|
|
49488
|
+
readJson(nb, dir, FILES.rivers).catch(() => void 0),
|
|
49489
|
+
readJson(nb, dir, FILES.mountainRanges).catch(
|
|
49490
|
+
() => void 0
|
|
49491
|
+
),
|
|
49492
|
+
readJson(nb, dir, FILES.naLand).catch(() => void 0),
|
|
49493
|
+
readJson(nb, dir, FILES.naLakes).catch(() => void 0),
|
|
49494
|
+
readJson(nb, dir, FILES.waterBodies).catch(() => void 0),
|
|
49495
|
+
readJson(nb, dir, FILES.gazetteer)
|
|
49496
|
+
]);
|
|
49497
|
+
return validate({
|
|
49498
|
+
worldCoarse,
|
|
49499
|
+
worldDetail,
|
|
49500
|
+
usStates,
|
|
49501
|
+
gazetteer,
|
|
49502
|
+
...lakes && { lakes },
|
|
49503
|
+
...rivers && { rivers },
|
|
49504
|
+
...mountainRanges && { mountainRanges },
|
|
49505
|
+
...naLand && { naLand },
|
|
49506
|
+
...naLakes && { naLakes },
|
|
49507
|
+
...waterBodies && { waterBodies }
|
|
49508
|
+
});
|
|
49509
|
+
})().catch((e) => {
|
|
49510
|
+
cache = void 0;
|
|
49511
|
+
throw e;
|
|
49512
|
+
});
|
|
49513
|
+
return cache;
|
|
49514
|
+
}
|
|
49515
|
+
var FILES, CANDIDATE_DIRS, cache;
|
|
49516
|
+
var init_load_data = __esm({
|
|
49517
|
+
"src/map/load-data.ts"() {
|
|
49518
|
+
"use strict";
|
|
49519
|
+
FILES = {
|
|
49520
|
+
worldCoarse: "world-coarse.json",
|
|
49521
|
+
worldDetail: "world-detail.json",
|
|
49522
|
+
usStates: "us-states.json",
|
|
49523
|
+
lakes: "lakes.json",
|
|
49524
|
+
rivers: "rivers.json",
|
|
49525
|
+
mountainRanges: "mountain-ranges.json",
|
|
49526
|
+
naLand: "na-land.json",
|
|
49527
|
+
naLakes: "na-lakes.json",
|
|
49528
|
+
waterBodies: "water-bodies.json",
|
|
49529
|
+
gazetteer: "gazetteer.json"
|
|
49530
|
+
};
|
|
49531
|
+
CANDIDATE_DIRS = [
|
|
49532
|
+
"./data",
|
|
49533
|
+
"./map-data",
|
|
49534
|
+
"../map-data",
|
|
49535
|
+
"../src/map/data"
|
|
49536
|
+
];
|
|
49537
|
+
}
|
|
49538
|
+
});
|
|
49539
|
+
|
|
47822
49540
|
// src/pyramid/renderer.ts
|
|
47823
49541
|
var renderer_exports17 = {};
|
|
47824
49542
|
__export(renderer_exports17, {
|
|
@@ -49821,8 +51539,8 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
|
|
|
49821
51539
|
const lines = splitParticipantLabel(p.label, LABEL_MAX_CHARS);
|
|
49822
51540
|
if (lines.length === 0) continue;
|
|
49823
51541
|
const widest = Math.max(...lines.map((l) => l.length));
|
|
49824
|
-
const
|
|
49825
|
-
uniformBoxWidth = Math.max(uniformBoxWidth,
|
|
51542
|
+
const labelWidth2 = widest * LABEL_CHAR_WIDTH + 10;
|
|
51543
|
+
uniformBoxWidth = Math.max(uniformBoxWidth, labelWidth2);
|
|
49826
51544
|
}
|
|
49827
51545
|
uniformBoxWidth = Math.min(MAX_BOX_WIDTH, uniformBoxWidth);
|
|
49828
51546
|
const effectiveGap = Math.max(PARTICIPANT_GAP, uniformBoxWidth + 30);
|
|
@@ -52521,15 +54239,15 @@ function renderArcDiagram(container, parsed, palette, _isDark, onClickItem, expo
|
|
|
52521
54239
|
textColor,
|
|
52522
54240
|
onClickItem
|
|
52523
54241
|
);
|
|
52524
|
-
const
|
|
52525
|
-
for (const node of nodes)
|
|
54242
|
+
const neighbors2 = /* @__PURE__ */ new Map();
|
|
54243
|
+
for (const node of nodes) neighbors2.set(node, /* @__PURE__ */ new Set());
|
|
52526
54244
|
for (const link of links) {
|
|
52527
|
-
|
|
52528
|
-
|
|
54245
|
+
neighbors2.get(link.source).add(link.target);
|
|
54246
|
+
neighbors2.get(link.target).add(link.source);
|
|
52529
54247
|
}
|
|
52530
54248
|
const FADE_OPACITY3 = 0.1;
|
|
52531
54249
|
function handleMouseEnter(hovered) {
|
|
52532
|
-
const connected =
|
|
54250
|
+
const connected = neighbors2.get(hovered);
|
|
52533
54251
|
g.selectAll(".arc-link").each(function() {
|
|
52534
54252
|
const el = d3Selection23.select(this);
|
|
52535
54253
|
const src = el.attr("data-source");
|
|
@@ -54520,7 +56238,7 @@ function renderVenn(container, parsed, palette, _isDark, onClickItem, exportDims
|
|
|
54520
56238
|
8,
|
|
54521
56239
|
Math.floor(OVERLAP_WRAP_TARGET_W / OVERLAP_CH_W)
|
|
54522
56240
|
);
|
|
54523
|
-
function
|
|
56241
|
+
function wrapLabel3(text, maxChars) {
|
|
54524
56242
|
const words = text.split(/\s+/).filter(Boolean);
|
|
54525
56243
|
const lines = [];
|
|
54526
56244
|
let cur = "";
|
|
@@ -54566,7 +56284,7 @@ function renderVenn(container, parsed, palette, _isDark, onClickItem, exportDims
|
|
|
54566
56284
|
if (!ov.label) continue;
|
|
54567
56285
|
const idxs = ov.sets.map((s) => vennSets.findIndex((vs) => vs.name === s));
|
|
54568
56286
|
if (idxs.some((idx) => idx < 0)) continue;
|
|
54569
|
-
const lines =
|
|
56287
|
+
const lines = wrapLabel3(ov.label, MAX_WRAP_CHARS);
|
|
54570
56288
|
wrappedOverlapLabels.set(ov, lines);
|
|
54571
56289
|
const dir = predictOverlapDirRaw(idxs);
|
|
54572
56290
|
const longest = lines.reduce((m, l) => Math.max(m, l.length), 0);
|
|
@@ -56003,25 +57721,29 @@ async function renderForExport(content, theme, palette, viewState, options) {
|
|
|
56003
57721
|
if (detectedType === "map") {
|
|
56004
57722
|
const { parseMap: parseMap2 } = await Promise.resolve().then(() => (init_parser12(), parser_exports11));
|
|
56005
57723
|
const { resolveMap: resolveMap2 } = await Promise.resolve().then(() => (init_resolver2(), resolver_exports));
|
|
56006
|
-
const { loadMapData: loadMapData2 } = await Promise.resolve().then(() => (init_load_data(), load_data_exports));
|
|
56007
57724
|
const { renderMapForExport: renderMapForExport2 } = await Promise.resolve().then(() => (init_renderer16(), renderer_exports16));
|
|
57725
|
+
const { mapExportDimensions: mapExportDimensions2 } = await Promise.resolve().then(() => (init_dimensions(), dimensions_exports));
|
|
56008
57726
|
const effectivePalette2 = await resolveExportPalette(theme, palette);
|
|
56009
57727
|
const mapParsed = parseMap2(content);
|
|
56010
|
-
let mapData;
|
|
56011
|
-
|
|
56012
|
-
|
|
56013
|
-
|
|
56014
|
-
|
|
57728
|
+
let mapData = options?.mapData;
|
|
57729
|
+
if (!mapData) {
|
|
57730
|
+
const { loadMapData: loadMapData2 } = await Promise.resolve().then(() => (init_load_data(), load_data_exports));
|
|
57731
|
+
try {
|
|
57732
|
+
mapData = await loadMapData2();
|
|
57733
|
+
} catch {
|
|
57734
|
+
return "";
|
|
57735
|
+
}
|
|
56015
57736
|
}
|
|
56016
57737
|
const mapResolved = resolveMap2(mapParsed, mapData);
|
|
56017
|
-
const
|
|
57738
|
+
const dims2 = mapExportDimensions2(mapResolved, mapData, EXPORT_WIDTH);
|
|
57739
|
+
const container2 = createExportContainer(dims2.width, dims2.height);
|
|
56018
57740
|
renderMapForExport2(
|
|
56019
57741
|
container2,
|
|
56020
57742
|
mapResolved,
|
|
56021
57743
|
mapData,
|
|
56022
57744
|
effectivePalette2,
|
|
56023
57745
|
theme === "dark",
|
|
56024
|
-
|
|
57746
|
+
dims2
|
|
56025
57747
|
);
|
|
56026
57748
|
return finalizeSvgExport(container2, theme, effectivePalette2);
|
|
56027
57749
|
}
|
|
@@ -56868,7 +58590,8 @@ async function render(content, options) {
|
|
|
56868
58590
|
...options?.c4Container !== void 0 && {
|
|
56869
58591
|
c4Container: options.c4Container
|
|
56870
58592
|
},
|
|
56871
|
-
...options?.tagGroup !== void 0 && { tagGroup: options.tagGroup }
|
|
58593
|
+
...options?.tagGroup !== void 0 && { tagGroup: options.tagGroup },
|
|
58594
|
+
...options?.mapData !== void 0 && { mapData: options.mapData }
|
|
56872
58595
|
});
|
|
56873
58596
|
if (chartType === "map") {
|
|
56874
58597
|
try {
|
|
@@ -56879,7 +58602,7 @@ async function render(content, options) {
|
|
|
56879
58602
|
Promise.resolve().then(() => (init_load_data(), load_data_exports))
|
|
56880
58603
|
]
|
|
56881
58604
|
);
|
|
56882
|
-
const data = await loadMapData2();
|
|
58605
|
+
const data = options?.mapData ?? await loadMapData2();
|
|
56883
58606
|
diagnostics = [...resolveMap2(parseMap2(content), data).diagnostics];
|
|
56884
58607
|
} catch {
|
|
56885
58608
|
}
|
|
@@ -57118,8 +58841,8 @@ function detectCycles(parsed) {
|
|
|
57118
58841
|
const parent = /* @__PURE__ */ new Map();
|
|
57119
58842
|
function dfs(nodeId3) {
|
|
57120
58843
|
color.set(nodeId3, 1);
|
|
57121
|
-
const
|
|
57122
|
-
for (const next of
|
|
58844
|
+
const neighbors2 = adj.get(nodeId3) ?? [];
|
|
58845
|
+
for (const next of neighbors2) {
|
|
57123
58846
|
const c = color.get(next) ?? 0;
|
|
57124
58847
|
if (c === 1) {
|
|
57125
58848
|
const lineKey = `${nodeId3}->${next}`;
|
|
@@ -57304,6 +59027,163 @@ init_resolver2();
|
|
|
57304
59027
|
init_load_data();
|
|
57305
59028
|
init_layout15();
|
|
57306
59029
|
init_renderer16();
|
|
59030
|
+
init_dimensions();
|
|
59031
|
+
|
|
59032
|
+
// src/map/geo-query.ts
|
|
59033
|
+
init_parser12();
|
|
59034
|
+
init_resolver2();
|
|
59035
|
+
init_layout15();
|
|
59036
|
+
init_geo();
|
|
59037
|
+
|
|
59038
|
+
// src/map/invert.ts
|
|
59039
|
+
function inInsetFrame(inset, px, py) {
|
|
59040
|
+
return px >= inset.x && px <= inset.x + inset.w && py >= inset.y && py <= inset.y + inset.h;
|
|
59041
|
+
}
|
|
59042
|
+
function unstretch(layout, px, py) {
|
|
59043
|
+
const s = layout.stretch;
|
|
59044
|
+
return [
|
|
59045
|
+
s.bx0 + (s.sx !== 0 ? (px - s.ox) / s.sx : 0),
|
|
59046
|
+
s.by0 + (s.sy !== 0 ? (py - s.oy) / s.sy : 0)
|
|
59047
|
+
];
|
|
59048
|
+
}
|
|
59049
|
+
function applyStretch(layout, x, y) {
|
|
59050
|
+
const s = layout.stretch;
|
|
59051
|
+
return [s.ox + (x - s.bx0) * s.sx, s.oy + (y - s.by0) * s.sy];
|
|
59052
|
+
}
|
|
59053
|
+
function pixelToLonLat(layout, px, py) {
|
|
59054
|
+
for (const inset of layout.insets) {
|
|
59055
|
+
if (inInsetFrame(inset, px, py)) {
|
|
59056
|
+
const ll2 = inset.projection.invert?.([px, py]);
|
|
59057
|
+
return ll2 && Number.isFinite(ll2[0]) && Number.isFinite(ll2[1]) ? [ll2[0], ll2[1]] : null;
|
|
59058
|
+
}
|
|
59059
|
+
}
|
|
59060
|
+
const [x, y] = layout.stretch ? unstretch(layout, px, py) : [px, py];
|
|
59061
|
+
const ll = layout.projection.invert?.([x, y]);
|
|
59062
|
+
return ll && Number.isFinite(ll[0]) && Number.isFinite(ll[1]) ? [ll[0], ll[1]] : null;
|
|
59063
|
+
}
|
|
59064
|
+
function lonLatToPixel(layout, lonLat) {
|
|
59065
|
+
const pt = [lonLat[0], lonLat[1]];
|
|
59066
|
+
const main = layout.projection(pt);
|
|
59067
|
+
const mainPx = main && Number.isFinite(main[0]) && Number.isFinite(main[1]) ? layout.stretch ? applyStretch(layout, main[0], main[1]) : [main[0], main[1]] : null;
|
|
59068
|
+
const onCanvas = !!mainPx && mainPx[0] >= 0 && mainPx[0] <= layout.width && mainPx[1] >= 0 && mainPx[1] <= layout.height;
|
|
59069
|
+
if (onCanvas) return mainPx;
|
|
59070
|
+
for (const inset of layout.insets) {
|
|
59071
|
+
const p = inset.projection(pt);
|
|
59072
|
+
if (p && Number.isFinite(p[0]) && Number.isFinite(p[1]) && inInsetFrame(inset, p[0], p[1]))
|
|
59073
|
+
return [p[0], p[1]];
|
|
59074
|
+
}
|
|
59075
|
+
return mainPx;
|
|
59076
|
+
}
|
|
59077
|
+
|
|
59078
|
+
// src/map/geo-query.ts
|
|
59079
|
+
var EARTH_R_KM = 6371;
|
|
59080
|
+
var DEG = Math.PI / 180;
|
|
59081
|
+
function haversineKm(lat1, lon1, lat2, lon2) {
|
|
59082
|
+
const dLat = (lat2 - lat1) * DEG;
|
|
59083
|
+
const dLon = (lon2 - lon1) * DEG;
|
|
59084
|
+
const a = Math.sin(dLat / 2) ** 2 + Math.cos(lat1 * DEG) * Math.cos(lat2 * DEG) * Math.sin(dLon / 2) ** 2;
|
|
59085
|
+
return 2 * EARTH_R_KM * Math.asin(Math.min(1, Math.sqrt(a)));
|
|
59086
|
+
}
|
|
59087
|
+
var POP_PULL_KM = 12;
|
|
59088
|
+
function nearestCity(lonLat, gazetteer) {
|
|
59089
|
+
const [lon, lat] = lonLat;
|
|
59090
|
+
let best = null;
|
|
59091
|
+
const cities = gazetteer.cities;
|
|
59092
|
+
for (let i = 0; i < cities.length; i++) {
|
|
59093
|
+
const c2 = cities[i];
|
|
59094
|
+
const dist = haversineKm(lat, lon, c2[0], c2[1]);
|
|
59095
|
+
const score = dist - POP_PULL_KM * Math.log10((c2[3] || 0) + 1);
|
|
59096
|
+
if (!best || score < best.score) best = { score, idx: i, dist };
|
|
59097
|
+
}
|
|
59098
|
+
if (!best) return null;
|
|
59099
|
+
const c = cities[best.idx];
|
|
59100
|
+
return {
|
|
59101
|
+
name: c[4],
|
|
59102
|
+
iso: c[2],
|
|
59103
|
+
...c[5] !== void 0 && { sub: c[5] },
|
|
59104
|
+
distanceKm: best.dist,
|
|
59105
|
+
lat: c[0],
|
|
59106
|
+
lon: c[1]
|
|
59107
|
+
};
|
|
59108
|
+
}
|
|
59109
|
+
function roundCoord(n) {
|
|
59110
|
+
return Number(n.toFixed(2));
|
|
59111
|
+
}
|
|
59112
|
+
function buildTokens(lonLat, region, city) {
|
|
59113
|
+
const coordPoiLine = `poi ${roundCoord(lonLat[1])} ${roundCoord(lonLat[0])}`;
|
|
59114
|
+
let stateTok = null;
|
|
59115
|
+
if (region.state) {
|
|
59116
|
+
const { iso, name } = region.state;
|
|
59117
|
+
stateTok = { primary: `${name} ${iso}`, alternates: [iso, name] };
|
|
59118
|
+
}
|
|
59119
|
+
let countryTok = null;
|
|
59120
|
+
if (region.country) {
|
|
59121
|
+
const { iso, name } = region.country;
|
|
59122
|
+
countryTok = { primary: name, alternates: [iso] };
|
|
59123
|
+
}
|
|
59124
|
+
let cityTok = null;
|
|
59125
|
+
if (city) {
|
|
59126
|
+
const scope = city.sub ?? (city.iso || "");
|
|
59127
|
+
cityTok = scope ? { token: `poi ${city.name} ${scope}`, ambiguous: false } : { token: `poi ${city.name}`, ambiguous: true };
|
|
59128
|
+
}
|
|
59129
|
+
return { coordPoiLine, state: stateTok, country: countryTok, city: cityTok };
|
|
59130
|
+
}
|
|
59131
|
+
var MAX_CITY_DOTS = 250;
|
|
59132
|
+
function createMapGeoQuery(opts) {
|
|
59133
|
+
const { content, width, height, data, palette, isDark } = opts;
|
|
59134
|
+
const resolved = resolveMap(parseMap(content), data);
|
|
59135
|
+
const layout = layoutMap(
|
|
59136
|
+
resolved,
|
|
59137
|
+
data,
|
|
59138
|
+
{ width, height },
|
|
59139
|
+
{ palette, isDark }
|
|
59140
|
+
);
|
|
59141
|
+
const countries = decodeFeatures(data.worldDetail);
|
|
59142
|
+
const states = decodeFeatures(data.usStates);
|
|
59143
|
+
const gazetteer = data.gazetteer;
|
|
59144
|
+
const invert = (px, py) => pixelToLonLat(layout, px, py);
|
|
59145
|
+
const project = (lonLat) => lonLatToPixel(layout, lonLat);
|
|
59146
|
+
const locate = (px, py) => {
|
|
59147
|
+
const lonLat = invert(px, py);
|
|
59148
|
+
if (!lonLat) return null;
|
|
59149
|
+
const region = regionAt(lonLat, countries, states);
|
|
59150
|
+
const city = nearestCity(lonLat, gazetteer);
|
|
59151
|
+
return {
|
|
59152
|
+
lonLat,
|
|
59153
|
+
country: region.country,
|
|
59154
|
+
state: region.state,
|
|
59155
|
+
nearestCity: city,
|
|
59156
|
+
tokens: buildTokens(lonLat, region, city)
|
|
59157
|
+
};
|
|
59158
|
+
};
|
|
59159
|
+
const cities = (extent2) => {
|
|
59160
|
+
const sorted = [...gazetteer.cities].sort((a, b) => b[3] - a[3]);
|
|
59161
|
+
const out = [];
|
|
59162
|
+
for (const c of sorted) {
|
|
59163
|
+
const [lat, lon, iso, pop, name, sub] = c;
|
|
59164
|
+
if (extent2) {
|
|
59165
|
+
const [[w, s], [e, n]] = extent2;
|
|
59166
|
+
if (lon < w || lon > e || lat < s || lat > n) continue;
|
|
59167
|
+
}
|
|
59168
|
+
const p = project([lon, lat]);
|
|
59169
|
+
if (!p) continue;
|
|
59170
|
+
if (p[0] < 0 || p[0] > width || p[1] < 0 || p[1] > height) continue;
|
|
59171
|
+
out.push({
|
|
59172
|
+
name,
|
|
59173
|
+
iso,
|
|
59174
|
+
...sub !== void 0 && { sub },
|
|
59175
|
+
lon,
|
|
59176
|
+
lat,
|
|
59177
|
+
px: p[0],
|
|
59178
|
+
py: p[1],
|
|
59179
|
+
pop
|
|
59180
|
+
});
|
|
59181
|
+
if (out.length >= MAX_CITY_DOTS) break;
|
|
59182
|
+
}
|
|
59183
|
+
return out;
|
|
59184
|
+
};
|
|
59185
|
+
return { invert, project, locate, cities, diagnostics: layout.diagnostics };
|
|
59186
|
+
}
|
|
57307
59187
|
|
|
57308
59188
|
// src/map/completion.ts
|
|
57309
59189
|
var fold2 = (s) => s.normalize("NFD").replace(/\p{Diacritic}/gu, "").toLowerCase().trim();
|
|
@@ -58028,9 +59908,12 @@ var GLOBAL_DIRECTIVES = {
|
|
|
58028
59908
|
"gruvbox",
|
|
58029
59909
|
"tokyo-night",
|
|
58030
59910
|
"one-dark",
|
|
58031
|
-
"bold",
|
|
58032
59911
|
"dracula",
|
|
58033
|
-
"monokai"
|
|
59912
|
+
"monokai",
|
|
59913
|
+
"atlas",
|
|
59914
|
+
"blueprint",
|
|
59915
|
+
"slate",
|
|
59916
|
+
"tidewater"
|
|
58034
59917
|
]
|
|
58035
59918
|
},
|
|
58036
59919
|
theme: {
|
|
@@ -58426,18 +60309,12 @@ var COMPLETION_REGISTRY = /* @__PURE__ */ new Map([
|
|
|
58426
60309
|
],
|
|
58427
60310
|
[
|
|
58428
60311
|
"map",
|
|
58429
|
-
// Geographic map directives (§24B.2/.7).
|
|
58430
|
-
//
|
|
58431
|
-
//
|
|
60312
|
+
// Geographic map directives (§24B.2/.7). Cosmetics are ON by default — the
|
|
60313
|
+
// only switches are bare `no-*` opt-outs, surfaced proactively so a
|
|
60314
|
+
// zero-config map still hints at what can be turned off. `poi`/`route` are
|
|
60315
|
+
// content keywords, not directives; metadata keys (value/label/style) live
|
|
60316
|
+
// in the reserved-key registry.
|
|
58432
60317
|
withGlobals({
|
|
58433
|
-
region: {
|
|
58434
|
-
description: "Basemap: us-states (force US state mesh + scoping) | world (inert \u2014 already the default)",
|
|
58435
|
-
values: ["us-states", "world"]
|
|
58436
|
-
},
|
|
58437
|
-
projection: {
|
|
58438
|
-
description: "Override the auto projection",
|
|
58439
|
-
values: ["equirectangular", "natural-earth", "albers-usa", "mercator"]
|
|
58440
|
-
},
|
|
58441
60318
|
"region-metric": { description: "Label for the region value ramp" },
|
|
58442
60319
|
"poi-metric": {
|
|
58443
60320
|
description: "Label for the POI value (marker size) channel"
|
|
@@ -58445,20 +60322,30 @@ var COMPLETION_REGISTRY = /* @__PURE__ */ new Map([
|
|
|
58445
60322
|
"flow-metric": {
|
|
58446
60323
|
description: "Label for the edge/leg value (thickness) channel"
|
|
58447
60324
|
},
|
|
58448
|
-
|
|
58449
|
-
|
|
58450
|
-
description: "Subdivision name labels",
|
|
58451
|
-
values: ["full", "abbrev", "off"]
|
|
60325
|
+
locale: {
|
|
60326
|
+
description: "Default country/state for bare place names, e.g. locale US-GA"
|
|
58452
60327
|
},
|
|
58453
|
-
"
|
|
58454
|
-
description: "
|
|
58455
|
-
values: ["off", "auto", "all"]
|
|
60328
|
+
"active-tag": {
|
|
60329
|
+
description: "Which tag group leads when several are present"
|
|
58456
60330
|
},
|
|
58457
|
-
|
|
58458
|
-
"default-state": { description: "ISO subdivision scope" },
|
|
60331
|
+
caption: { description: "Caption line (data-source attribution)" },
|
|
58459
60332
|
"no-legend": { description: "Suppress the legend" },
|
|
58460
|
-
|
|
58461
|
-
|
|
60333
|
+
"no-coastline": {
|
|
60334
|
+
description: "Turn off coastal water-lines (on by default)"
|
|
60335
|
+
},
|
|
60336
|
+
"no-relief": {
|
|
60337
|
+
description: "Turn off mountain-range relief shading (on by default)"
|
|
60338
|
+
},
|
|
60339
|
+
"no-context-labels": {
|
|
60340
|
+
description: "Turn off orientation labels for water + nearby countries"
|
|
60341
|
+
},
|
|
60342
|
+
"no-region-labels": {
|
|
60343
|
+
description: "Turn off subdivision name labels (on by default)"
|
|
60344
|
+
},
|
|
60345
|
+
"no-poi-labels": { description: "Turn off POI labels (on by default)" },
|
|
60346
|
+
"no-colorize": {
|
|
60347
|
+
description: "Force plain green-land reference dress (regions are auto-coloured by default)"
|
|
60348
|
+
}
|
|
58462
60349
|
})
|
|
58463
60350
|
]
|
|
58464
60351
|
]);
|
|
@@ -59933,7 +61820,8 @@ export {
|
|
|
59933
61820
|
applyCollapseProjection,
|
|
59934
61821
|
applyGroupOrdering,
|
|
59935
61822
|
applyPositionOverrides,
|
|
59936
|
-
|
|
61823
|
+
atlasPalette,
|
|
61824
|
+
blueprintPalette,
|
|
59937
61825
|
buildExtendedChartOption,
|
|
59938
61826
|
buildNoteMessageMap,
|
|
59939
61827
|
buildRenderSequence,
|
|
@@ -59967,6 +61855,7 @@ export {
|
|
|
59967
61855
|
computeTimeTicks,
|
|
59968
61856
|
contrastText,
|
|
59969
61857
|
controlsGroupCapsuleWidth,
|
|
61858
|
+
createMapGeoQuery,
|
|
59970
61859
|
decodeDiagramUrl,
|
|
59971
61860
|
decodeViewState,
|
|
59972
61861
|
displayName,
|
|
@@ -60035,6 +61924,8 @@ export {
|
|
|
60035
61924
|
looksLikeState,
|
|
60036
61925
|
makeDgmoError,
|
|
60037
61926
|
mapBackgroundColor,
|
|
61927
|
+
mapContentAspect,
|
|
61928
|
+
mapExportDimensions,
|
|
60038
61929
|
mapNeutralLandColor,
|
|
60039
61930
|
matchesContiguously,
|
|
60040
61931
|
measurePertAnalysisBlock,
|
|
@@ -60170,9 +62061,11 @@ export {
|
|
|
60170
62061
|
shapeFill,
|
|
60171
62062
|
simulateCanonical,
|
|
60172
62063
|
simulateFast,
|
|
62064
|
+
slatePalette,
|
|
60173
62065
|
solarizedPalette,
|
|
60174
62066
|
suggestChartTypes,
|
|
60175
62067
|
themes,
|
|
62068
|
+
tidewaterPalette,
|
|
60176
62069
|
tint,
|
|
60177
62070
|
tokyoNightPalette,
|
|
60178
62071
|
transformLine,
|