@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.cjs
CHANGED
|
@@ -373,18 +373,18 @@ function computeQuadrantPointLabels(points, chartBounds, obstacles, pointRadius,
|
|
|
373
373
|
const results = [];
|
|
374
374
|
for (let i = 0; i < points.length; i++) {
|
|
375
375
|
const pt = points[i];
|
|
376
|
-
const
|
|
376
|
+
const labelWidth2 = pt.label.length * fontSize * CHAR_WIDTH_RATIO + 8;
|
|
377
377
|
let best = null;
|
|
378
378
|
const directions = [
|
|
379
379
|
{
|
|
380
380
|
// Above
|
|
381
381
|
gen: (offset) => {
|
|
382
|
-
const lx = pt.cx -
|
|
382
|
+
const lx = pt.cx - labelWidth2 / 2;
|
|
383
383
|
const ly = pt.cy - offset - labelHeight;
|
|
384
|
-
if (ly < chartBounds.top || lx < chartBounds.left || lx +
|
|
384
|
+
if (ly < chartBounds.top || lx < chartBounds.left || lx + labelWidth2 > chartBounds.right)
|
|
385
385
|
return null;
|
|
386
386
|
return {
|
|
387
|
-
rect: { x: lx, y: ly, w:
|
|
387
|
+
rect: { x: lx, y: ly, w: labelWidth2, h: labelHeight },
|
|
388
388
|
textX: pt.cx,
|
|
389
389
|
textY: ly + labelHeight / 2,
|
|
390
390
|
anchor: "middle"
|
|
@@ -394,12 +394,12 @@ function computeQuadrantPointLabels(points, chartBounds, obstacles, pointRadius,
|
|
|
394
394
|
{
|
|
395
395
|
// Below
|
|
396
396
|
gen: (offset) => {
|
|
397
|
-
const lx = pt.cx -
|
|
397
|
+
const lx = pt.cx - labelWidth2 / 2;
|
|
398
398
|
const ly = pt.cy + offset;
|
|
399
|
-
if (ly + labelHeight > chartBounds.bottom || lx < chartBounds.left || lx +
|
|
399
|
+
if (ly + labelHeight > chartBounds.bottom || lx < chartBounds.left || lx + labelWidth2 > chartBounds.right)
|
|
400
400
|
return null;
|
|
401
401
|
return {
|
|
402
|
-
rect: { x: lx, y: ly, w:
|
|
402
|
+
rect: { x: lx, y: ly, w: labelWidth2, h: labelHeight },
|
|
403
403
|
textX: pt.cx,
|
|
404
404
|
textY: ly + labelHeight / 2,
|
|
405
405
|
anchor: "middle"
|
|
@@ -411,10 +411,10 @@ function computeQuadrantPointLabels(points, chartBounds, obstacles, pointRadius,
|
|
|
411
411
|
gen: (offset) => {
|
|
412
412
|
const lx = pt.cx + offset;
|
|
413
413
|
const ly = pt.cy - labelHeight / 2;
|
|
414
|
-
if (lx +
|
|
414
|
+
if (lx + labelWidth2 > chartBounds.right || ly < chartBounds.top || ly + labelHeight > chartBounds.bottom)
|
|
415
415
|
return null;
|
|
416
416
|
return {
|
|
417
|
-
rect: { x: lx, y: ly, w:
|
|
417
|
+
rect: { x: lx, y: ly, w: labelWidth2, h: labelHeight },
|
|
418
418
|
textX: lx,
|
|
419
419
|
textY: pt.cy,
|
|
420
420
|
anchor: "start"
|
|
@@ -424,13 +424,13 @@ function computeQuadrantPointLabels(points, chartBounds, obstacles, pointRadius,
|
|
|
424
424
|
{
|
|
425
425
|
// Left
|
|
426
426
|
gen: (offset) => {
|
|
427
|
-
const lx = pt.cx - offset -
|
|
427
|
+
const lx = pt.cx - offset - labelWidth2;
|
|
428
428
|
const ly = pt.cy - labelHeight / 2;
|
|
429
429
|
if (lx < chartBounds.left || ly < chartBounds.top || ly + labelHeight > chartBounds.bottom)
|
|
430
430
|
return null;
|
|
431
431
|
return {
|
|
432
|
-
rect: { x: lx, y: ly, w:
|
|
433
|
-
textX: lx +
|
|
432
|
+
rect: { x: lx, y: ly, w: labelWidth2, h: labelHeight },
|
|
433
|
+
textX: lx + labelWidth2,
|
|
434
434
|
textY: pt.cy,
|
|
435
435
|
anchor: "end"
|
|
436
436
|
};
|
|
@@ -480,10 +480,10 @@ function computeQuadrantPointLabels(points, chartBounds, obstacles, pointRadius,
|
|
|
480
480
|
}
|
|
481
481
|
}
|
|
482
482
|
if (!best) {
|
|
483
|
-
const lx = pt.cx -
|
|
483
|
+
const lx = pt.cx - labelWidth2 / 2;
|
|
484
484
|
const ly = pt.cy - minGap - labelHeight;
|
|
485
485
|
best = {
|
|
486
|
-
rect: { x: lx, y: ly, w:
|
|
486
|
+
rect: { x: lx, y: ly, w: labelWidth2, h: labelHeight },
|
|
487
487
|
textX: pt.cx,
|
|
488
488
|
textY: ly + labelHeight / 2,
|
|
489
489
|
anchor: "middle",
|
|
@@ -860,6 +860,9 @@ var init_reserved_key_registry = __esm({
|
|
|
860
860
|
"value",
|
|
861
861
|
"label",
|
|
862
862
|
"style"
|
|
863
|
+
// `surface:` was removed in the 2026-06-02 defaults-on review — it is no longer
|
|
864
|
+
// a recognized metadata key (the route/edge surface feature was cut; §24B.7).
|
|
865
|
+
// A stray `surface: water` is no longer captured as a reserved key.
|
|
863
866
|
]);
|
|
864
867
|
ORG_REGISTRY = staticRegistry([
|
|
865
868
|
"color",
|
|
@@ -1922,77 +1925,266 @@ function getSegmentColors(palette, count) {
|
|
|
1922
1925
|
(_, i) => hslToHex(Math.round((startHue + i * step) % 360), avgS, avgL)
|
|
1923
1926
|
);
|
|
1924
1927
|
}
|
|
1928
|
+
function politicalTints(palette, count, isDark) {
|
|
1929
|
+
if (count <= 0) return [];
|
|
1930
|
+
const base = isDark ? palette.surface : palette.bg;
|
|
1931
|
+
const c = palette.colors;
|
|
1932
|
+
const swatches = [
|
|
1933
|
+
.../* @__PURE__ */ new Set([
|
|
1934
|
+
c.green,
|
|
1935
|
+
c.yellow,
|
|
1936
|
+
c.orange,
|
|
1937
|
+
c.purple,
|
|
1938
|
+
c.red,
|
|
1939
|
+
c.teal,
|
|
1940
|
+
c.cyan,
|
|
1941
|
+
c.blue
|
|
1942
|
+
])
|
|
1943
|
+
];
|
|
1944
|
+
const bands = isDark ? POLITICAL_TINT_BANDS.dark : POLITICAL_TINT_BANDS.light;
|
|
1945
|
+
const out = [];
|
|
1946
|
+
for (const pct of bands) {
|
|
1947
|
+
if (out.length >= count) break;
|
|
1948
|
+
for (const s of swatches) out.push(mix(s, base, pct));
|
|
1949
|
+
}
|
|
1950
|
+
return out.slice(0, count);
|
|
1951
|
+
}
|
|
1952
|
+
var POLITICAL_TINT_BANDS;
|
|
1925
1953
|
var init_color_utils = __esm({
|
|
1926
1954
|
"src/palettes/color-utils.ts"() {
|
|
1927
1955
|
"use strict";
|
|
1956
|
+
POLITICAL_TINT_BANDS = {
|
|
1957
|
+
light: [32, 48, 64, 80],
|
|
1958
|
+
dark: [44, 58, 72, 86]
|
|
1959
|
+
};
|
|
1928
1960
|
}
|
|
1929
1961
|
});
|
|
1930
1962
|
|
|
1931
|
-
// src/palettes/
|
|
1932
|
-
var
|
|
1933
|
-
var
|
|
1934
|
-
"src/palettes/
|
|
1963
|
+
// src/palettes/atlas.ts
|
|
1964
|
+
var atlasPalette;
|
|
1965
|
+
var init_atlas = __esm({
|
|
1966
|
+
"src/palettes/atlas.ts"() {
|
|
1935
1967
|
"use strict";
|
|
1936
1968
|
init_registry();
|
|
1937
|
-
|
|
1938
|
-
id: "
|
|
1939
|
-
name: "
|
|
1969
|
+
atlasPalette = {
|
|
1970
|
+
id: "atlas",
|
|
1971
|
+
name: "Atlas",
|
|
1940
1972
|
light: {
|
|
1941
|
-
bg: "#
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1973
|
+
bg: "#f3ead3",
|
|
1974
|
+
// warm manila / parchment
|
|
1975
|
+
surface: "#ece0c0",
|
|
1976
|
+
// deeper paper (cards, panels)
|
|
1977
|
+
overlay: "#e8dab8",
|
|
1978
|
+
// popovers, dropdowns
|
|
1979
|
+
border: "#bcaa86",
|
|
1980
|
+
// muted sepia rule line
|
|
1981
|
+
text: "#463a26",
|
|
1982
|
+
// aged sepia-brown ink
|
|
1983
|
+
textMuted: "#7a6a4f",
|
|
1984
|
+
// faded annotation ink
|
|
1985
|
+
textOnFillLight: "#f7f1de",
|
|
1986
|
+
// parchment (light text on dark fills)
|
|
1987
|
+
textOnFillDark: "#3a2e1c",
|
|
1988
|
+
// deep ink (dark text on light fills)
|
|
1989
|
+
primary: "#5b7a99",
|
|
1990
|
+
// pull-down map ocean (steel-blue)
|
|
1991
|
+
secondary: "#7e9a6f",
|
|
1992
|
+
// lowland sage / celadon
|
|
1993
|
+
accent: "#b07f7c",
|
|
1994
|
+
// dusty rose
|
|
1995
|
+
destructive: "#b25a45",
|
|
1996
|
+
// brick / terracotta
|
|
1953
1997
|
colors: {
|
|
1954
|
-
red: "#
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1998
|
+
red: "#bf6a52",
|
|
1999
|
+
// terracotta brick
|
|
2000
|
+
orange: "#cf9a5c",
|
|
2001
|
+
// map tan / ochre
|
|
2002
|
+
yellow: "#cdb35e",
|
|
2003
|
+
// straw / muted lemon
|
|
2004
|
+
green: "#7e9a6f",
|
|
2005
|
+
// sage / celadon lowland
|
|
2006
|
+
blue: "#5b7a99",
|
|
2007
|
+
// steel-blue ocean
|
|
2008
|
+
purple: "#9a7fa6",
|
|
2009
|
+
// dusty lilac / mauve
|
|
2010
|
+
teal: "#6fa094",
|
|
2011
|
+
// muted seafoam
|
|
2012
|
+
cyan: "#79a7b5",
|
|
2013
|
+
// shallow-water blue
|
|
2014
|
+
gray: "#8a7d68",
|
|
2015
|
+
// warm taupe
|
|
2016
|
+
black: "#463a26",
|
|
2017
|
+
// ink
|
|
2018
|
+
white: "#ece0c0"
|
|
2019
|
+
// paper
|
|
1965
2020
|
}
|
|
1966
2021
|
},
|
|
1967
2022
|
dark: {
|
|
1968
|
-
bg: "#
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
2023
|
+
bg: "#1e2a33",
|
|
2024
|
+
// deep map ocean (night globe)
|
|
2025
|
+
surface: "#27353f",
|
|
2026
|
+
// raised ocean
|
|
2027
|
+
overlay: "#2e3d48",
|
|
2028
|
+
// popovers, dropdowns
|
|
2029
|
+
border: "#3d4f5c",
|
|
2030
|
+
// depth-contour line
|
|
2031
|
+
text: "#e8dcc0",
|
|
2032
|
+
// parchment ink, inverted
|
|
2033
|
+
textMuted: "#a89a7d",
|
|
2034
|
+
// faded label
|
|
2035
|
+
textOnFillLight: "#f7f1de",
|
|
2036
|
+
// parchment
|
|
2037
|
+
textOnFillDark: "#1a242c",
|
|
2038
|
+
// deep ocean ink
|
|
2039
|
+
primary: "#7ba0bf",
|
|
2040
|
+
// brighter ocean
|
|
2041
|
+
secondary: "#9bb588",
|
|
2042
|
+
// sage, lifted
|
|
2043
|
+
accent: "#cf9a96",
|
|
2044
|
+
// dusty rose, lifted
|
|
2045
|
+
destructive: "#c9745c",
|
|
2046
|
+
// brick, lifted
|
|
2047
|
+
colors: {
|
|
2048
|
+
red: "#cf7a60",
|
|
2049
|
+
// terracotta
|
|
2050
|
+
orange: "#d9a96a",
|
|
2051
|
+
// tan / ochre
|
|
2052
|
+
yellow: "#d8c074",
|
|
2053
|
+
// straw
|
|
2054
|
+
green: "#9bb588",
|
|
2055
|
+
// sage lowland
|
|
2056
|
+
blue: "#7ba0bf",
|
|
2057
|
+
// ocean
|
|
2058
|
+
purple: "#b59ac0",
|
|
2059
|
+
// lilac / mauve
|
|
2060
|
+
teal: "#85b3a6",
|
|
2061
|
+
// seafoam
|
|
2062
|
+
cyan: "#92bccb",
|
|
2063
|
+
// shallow-water blue
|
|
2064
|
+
gray: "#9a8d76",
|
|
2065
|
+
// warm taupe
|
|
2066
|
+
black: "#27353f",
|
|
2067
|
+
// raised ocean
|
|
2068
|
+
white: "#e8dcc0"
|
|
2069
|
+
// parchment
|
|
2070
|
+
}
|
|
2071
|
+
}
|
|
2072
|
+
};
|
|
2073
|
+
registerPalette(atlasPalette);
|
|
2074
|
+
}
|
|
2075
|
+
});
|
|
2076
|
+
|
|
2077
|
+
// src/palettes/blueprint.ts
|
|
2078
|
+
var blueprintPalette;
|
|
2079
|
+
var init_blueprint = __esm({
|
|
2080
|
+
"src/palettes/blueprint.ts"() {
|
|
2081
|
+
"use strict";
|
|
2082
|
+
init_registry();
|
|
2083
|
+
blueprintPalette = {
|
|
2084
|
+
id: "blueprint",
|
|
2085
|
+
name: "Blueprint",
|
|
2086
|
+
light: {
|
|
2087
|
+
bg: "#f4f8fb",
|
|
2088
|
+
// pale drafting white (faint cyan)
|
|
2089
|
+
surface: "#e6eef4",
|
|
2090
|
+
// drafting panel
|
|
2091
|
+
overlay: "#dde9f1",
|
|
2092
|
+
// popovers, dropdowns
|
|
2093
|
+
border: "#aac3d6",
|
|
2094
|
+
// pale blue grid line
|
|
2095
|
+
text: "#123a5e",
|
|
2096
|
+
// blueprint navy ink
|
|
2097
|
+
textMuted: "#4f7390",
|
|
2098
|
+
// faint draft note
|
|
2099
|
+
textOnFillLight: "#f4f8fb",
|
|
2100
|
+
// drafting white
|
|
2101
|
+
textOnFillDark: "#0c2f4d",
|
|
2102
|
+
// deep blueprint navy
|
|
2103
|
+
primary: "#1f5e8c",
|
|
2104
|
+
// blueprint blue
|
|
2105
|
+
secondary: "#5b7d96",
|
|
2106
|
+
// steel
|
|
2107
|
+
accent: "#b08a3e",
|
|
2108
|
+
// draftsman's ochre highlight
|
|
2109
|
+
destructive: "#c0504d",
|
|
2110
|
+
// correction red
|
|
1980
2111
|
colors: {
|
|
1981
|
-
red: "#
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
2112
|
+
red: "#c25a4e",
|
|
2113
|
+
// correction red
|
|
2114
|
+
orange: "#c2823e",
|
|
2115
|
+
// ochre
|
|
2116
|
+
yellow: "#c2a843",
|
|
2117
|
+
// pencil gold
|
|
2118
|
+
green: "#4f8a6b",
|
|
2119
|
+
// drafting green
|
|
2120
|
+
blue: "#1f5e8c",
|
|
2121
|
+
// blueprint blue
|
|
2122
|
+
purple: "#6f5e96",
|
|
2123
|
+
// indigo pencil
|
|
2124
|
+
teal: "#3a8a8a",
|
|
2125
|
+
// teal
|
|
2126
|
+
cyan: "#3f8fb5",
|
|
2127
|
+
// cyan
|
|
2128
|
+
gray: "#7e8e98",
|
|
2129
|
+
// graphite
|
|
2130
|
+
black: "#123a5e",
|
|
2131
|
+
// navy ink
|
|
2132
|
+
white: "#e6eef4"
|
|
2133
|
+
// panel
|
|
2134
|
+
}
|
|
2135
|
+
},
|
|
2136
|
+
dark: {
|
|
2137
|
+
bg: "#103a5e",
|
|
2138
|
+
// deep blueprint blue (cyanotype ground)
|
|
2139
|
+
surface: "#16466e",
|
|
2140
|
+
// raised sheet
|
|
2141
|
+
overlay: "#1c5180",
|
|
2142
|
+
// popovers, dropdowns
|
|
2143
|
+
border: "#3a6f96",
|
|
2144
|
+
// grid line
|
|
2145
|
+
text: "#eaf2f8",
|
|
2146
|
+
// chalk white
|
|
2147
|
+
textMuted: "#9fc0d6",
|
|
2148
|
+
// faint chalk note
|
|
2149
|
+
textOnFillLight: "#eaf2f8",
|
|
2150
|
+
// chalk white
|
|
2151
|
+
textOnFillDark: "#0c2f4d",
|
|
2152
|
+
// deep blueprint navy
|
|
2153
|
+
primary: "#7fb8d8",
|
|
2154
|
+
// chalk cyan
|
|
2155
|
+
secondary: "#9fb8c8",
|
|
2156
|
+
// pale steel
|
|
2157
|
+
accent: "#d8c27a",
|
|
2158
|
+
// chalk amber
|
|
2159
|
+
destructive: "#e08a7a",
|
|
2160
|
+
// chalk correction red
|
|
2161
|
+
colors: {
|
|
2162
|
+
red: "#e0907e",
|
|
2163
|
+
// chalk red
|
|
2164
|
+
orange: "#e0ab78",
|
|
2165
|
+
// chalk amber
|
|
2166
|
+
yellow: "#e3d089",
|
|
2167
|
+
// chalk gold
|
|
2168
|
+
green: "#93c79e",
|
|
2169
|
+
// chalk green
|
|
2170
|
+
blue: "#8ec3e0",
|
|
2171
|
+
// chalk cyan-blue
|
|
2172
|
+
purple: "#b6a6d8",
|
|
2173
|
+
// chalk indigo
|
|
2174
|
+
teal: "#84c7c2",
|
|
2175
|
+
// chalk teal
|
|
2176
|
+
cyan: "#9fd6e0",
|
|
2177
|
+
// chalk cyan
|
|
2178
|
+
gray: "#aebecb",
|
|
2179
|
+
// chalk graphite
|
|
2180
|
+
black: "#16466e",
|
|
2181
|
+
// raised sheet
|
|
2182
|
+
white: "#eaf2f8"
|
|
2183
|
+
// chalk white
|
|
1992
2184
|
}
|
|
1993
2185
|
}
|
|
1994
2186
|
};
|
|
1995
|
-
registerPalette(
|
|
2187
|
+
registerPalette(blueprintPalette);
|
|
1996
2188
|
}
|
|
1997
2189
|
});
|
|
1998
2190
|
|
|
@@ -2489,6 +2681,120 @@ var init_rose_pine = __esm({
|
|
|
2489
2681
|
}
|
|
2490
2682
|
});
|
|
2491
2683
|
|
|
2684
|
+
// src/palettes/slate.ts
|
|
2685
|
+
var slatePalette;
|
|
2686
|
+
var init_slate = __esm({
|
|
2687
|
+
"src/palettes/slate.ts"() {
|
|
2688
|
+
"use strict";
|
|
2689
|
+
init_registry();
|
|
2690
|
+
slatePalette = {
|
|
2691
|
+
id: "slate",
|
|
2692
|
+
name: "Slate",
|
|
2693
|
+
light: {
|
|
2694
|
+
bg: "#ffffff",
|
|
2695
|
+
// clean slide white
|
|
2696
|
+
surface: "#f3f5f8",
|
|
2697
|
+
// light cool-gray panel
|
|
2698
|
+
overlay: "#eaeef3",
|
|
2699
|
+
// popovers, dropdowns
|
|
2700
|
+
border: "#d4dae1",
|
|
2701
|
+
// hairline rule
|
|
2702
|
+
text: "#1f2933",
|
|
2703
|
+
// near-black slate (softer than pure black)
|
|
2704
|
+
textMuted: "#5b6672",
|
|
2705
|
+
// secondary label
|
|
2706
|
+
textOnFillLight: "#ffffff",
|
|
2707
|
+
// light text on dark fills
|
|
2708
|
+
textOnFillDark: "#1f2933",
|
|
2709
|
+
// dark text on light fills
|
|
2710
|
+
primary: "#3b6ea5",
|
|
2711
|
+
// confident corporate blue
|
|
2712
|
+
secondary: "#5b6672",
|
|
2713
|
+
// slate gray
|
|
2714
|
+
accent: "#3a9188",
|
|
2715
|
+
// muted teal accent
|
|
2716
|
+
destructive: "#c0504d",
|
|
2717
|
+
// brick red
|
|
2718
|
+
colors: {
|
|
2719
|
+
red: "#c0504d",
|
|
2720
|
+
// brick
|
|
2721
|
+
orange: "#cc7a33",
|
|
2722
|
+
// muted amber
|
|
2723
|
+
yellow: "#c9a227",
|
|
2724
|
+
// gold (not neon)
|
|
2725
|
+
green: "#5b9357",
|
|
2726
|
+
// forest / sage
|
|
2727
|
+
blue: "#3b6ea5",
|
|
2728
|
+
// corporate blue
|
|
2729
|
+
purple: "#7d5ba6",
|
|
2730
|
+
// muted violet
|
|
2731
|
+
teal: "#3a9188",
|
|
2732
|
+
// teal
|
|
2733
|
+
cyan: "#4f96c4",
|
|
2734
|
+
// steel cyan
|
|
2735
|
+
gray: "#7e8a97",
|
|
2736
|
+
// cool gray
|
|
2737
|
+
black: "#1f2933",
|
|
2738
|
+
// slate ink
|
|
2739
|
+
white: "#f3f5f8"
|
|
2740
|
+
// panel
|
|
2741
|
+
}
|
|
2742
|
+
},
|
|
2743
|
+
dark: {
|
|
2744
|
+
bg: "#161b22",
|
|
2745
|
+
// deep slate (keynote dark)
|
|
2746
|
+
surface: "#202833",
|
|
2747
|
+
// raised panel
|
|
2748
|
+
overlay: "#29323e",
|
|
2749
|
+
// popovers, dropdowns
|
|
2750
|
+
border: "#38424f",
|
|
2751
|
+
// divider
|
|
2752
|
+
text: "#e6eaef",
|
|
2753
|
+
// off-white
|
|
2754
|
+
textMuted: "#9aa5b1",
|
|
2755
|
+
// secondary label
|
|
2756
|
+
textOnFillLight: "#ffffff",
|
|
2757
|
+
// light text on dark fills
|
|
2758
|
+
textOnFillDark: "#161b22",
|
|
2759
|
+
// dark text on light fills
|
|
2760
|
+
primary: "#5b9bd5",
|
|
2761
|
+
// lifted corporate blue
|
|
2762
|
+
secondary: "#8593a3",
|
|
2763
|
+
// slate gray, lifted
|
|
2764
|
+
accent: "#45b3a3",
|
|
2765
|
+
// teal, lifted
|
|
2766
|
+
destructive: "#e07b6e",
|
|
2767
|
+
// brick, lifted
|
|
2768
|
+
colors: {
|
|
2769
|
+
red: "#e07b6e",
|
|
2770
|
+
// brick
|
|
2771
|
+
orange: "#e0975a",
|
|
2772
|
+
// amber
|
|
2773
|
+
yellow: "#d9bd5a",
|
|
2774
|
+
// gold
|
|
2775
|
+
green: "#74b56e",
|
|
2776
|
+
// forest / sage
|
|
2777
|
+
blue: "#5b9bd5",
|
|
2778
|
+
// corporate blue
|
|
2779
|
+
purple: "#a585c9",
|
|
2780
|
+
// violet
|
|
2781
|
+
teal: "#45b3a3",
|
|
2782
|
+
// teal
|
|
2783
|
+
cyan: "#62b0d9",
|
|
2784
|
+
// steel cyan
|
|
2785
|
+
gray: "#95a1ae",
|
|
2786
|
+
// cool gray
|
|
2787
|
+
black: "#202833",
|
|
2788
|
+
// raised panel
|
|
2789
|
+
white: "#e6eaef"
|
|
2790
|
+
// off-white
|
|
2791
|
+
}
|
|
2792
|
+
}
|
|
2793
|
+
};
|
|
2794
|
+
registerPalette(slatePalette);
|
|
2795
|
+
}
|
|
2796
|
+
});
|
|
2797
|
+
|
|
2492
2798
|
// src/palettes/solarized.ts
|
|
2493
2799
|
var solarizedPalette;
|
|
2494
2800
|
var init_solarized = __esm({
|
|
@@ -2584,6 +2890,120 @@ var init_solarized = __esm({
|
|
|
2584
2890
|
}
|
|
2585
2891
|
});
|
|
2586
2892
|
|
|
2893
|
+
// src/palettes/tidewater.ts
|
|
2894
|
+
var tidewaterPalette;
|
|
2895
|
+
var init_tidewater = __esm({
|
|
2896
|
+
"src/palettes/tidewater.ts"() {
|
|
2897
|
+
"use strict";
|
|
2898
|
+
init_registry();
|
|
2899
|
+
tidewaterPalette = {
|
|
2900
|
+
id: "tidewater",
|
|
2901
|
+
name: "Tidewater",
|
|
2902
|
+
light: {
|
|
2903
|
+
bg: "#eceff0",
|
|
2904
|
+
// weathered sea-mist paper
|
|
2905
|
+
surface: "#e0e4e3",
|
|
2906
|
+
// worn deck panel
|
|
2907
|
+
overlay: "#dadfdf",
|
|
2908
|
+
// popovers, dropdowns
|
|
2909
|
+
border: "#a9b2b3",
|
|
2910
|
+
// muted slate rule
|
|
2911
|
+
text: "#18313f",
|
|
2912
|
+
// ship's-log navy ink
|
|
2913
|
+
textMuted: "#51636b",
|
|
2914
|
+
// faded log entry
|
|
2915
|
+
textOnFillLight: "#f3f5f3",
|
|
2916
|
+
// weathered white
|
|
2917
|
+
textOnFillDark: "#162c38",
|
|
2918
|
+
// deep navy
|
|
2919
|
+
primary: "#1f4e6b",
|
|
2920
|
+
// deep-sea navy
|
|
2921
|
+
secondary: "#b08a4f",
|
|
2922
|
+
// rope / manila tan
|
|
2923
|
+
accent: "#c69a3e",
|
|
2924
|
+
// brass
|
|
2925
|
+
destructive: "#c1433a",
|
|
2926
|
+
// signal-flag red
|
|
2927
|
+
colors: {
|
|
2928
|
+
red: "#c1433a",
|
|
2929
|
+
// signal-flag red
|
|
2930
|
+
orange: "#cc7a38",
|
|
2931
|
+
// weathered amber
|
|
2932
|
+
yellow: "#d6bf5a",
|
|
2933
|
+
// brass gold
|
|
2934
|
+
green: "#4f8a6b",
|
|
2935
|
+
// sea-glass green
|
|
2936
|
+
blue: "#1f4e6b",
|
|
2937
|
+
// deep-sea navy
|
|
2938
|
+
purple: "#6a5a8c",
|
|
2939
|
+
// twilight harbor
|
|
2940
|
+
teal: "#3d8c8c",
|
|
2941
|
+
// sea-glass teal
|
|
2942
|
+
cyan: "#4f9bb5",
|
|
2943
|
+
// shallow water
|
|
2944
|
+
gray: "#8a8d86",
|
|
2945
|
+
// driftwood gray
|
|
2946
|
+
black: "#18313f",
|
|
2947
|
+
// navy ink
|
|
2948
|
+
white: "#e0e4e3"
|
|
2949
|
+
// deck panel
|
|
2950
|
+
}
|
|
2951
|
+
},
|
|
2952
|
+
dark: {
|
|
2953
|
+
bg: "#0f2230",
|
|
2954
|
+
// night-harbor deep sea
|
|
2955
|
+
surface: "#16303f",
|
|
2956
|
+
// raised hull
|
|
2957
|
+
overlay: "#1d3a4a",
|
|
2958
|
+
// popovers, dropdowns
|
|
2959
|
+
border: "#2c4856",
|
|
2960
|
+
// rigging line
|
|
2961
|
+
text: "#e6ebe8",
|
|
2962
|
+
// weathered white
|
|
2963
|
+
textMuted: "#9aaab0",
|
|
2964
|
+
// faded label
|
|
2965
|
+
textOnFillLight: "#f3f5f3",
|
|
2966
|
+
// weathered white
|
|
2967
|
+
textOnFillDark: "#0f2230",
|
|
2968
|
+
// deep sea
|
|
2969
|
+
primary: "#4f9bc4",
|
|
2970
|
+
// lifted sea blue
|
|
2971
|
+
secondary: "#c9a46a",
|
|
2972
|
+
// rope tan, lifted
|
|
2973
|
+
accent: "#d9b25a",
|
|
2974
|
+
// brass, lifted
|
|
2975
|
+
destructive: "#e06a5e",
|
|
2976
|
+
// signal red, lifted
|
|
2977
|
+
colors: {
|
|
2978
|
+
red: "#e06a5e",
|
|
2979
|
+
// signal-flag red
|
|
2980
|
+
orange: "#df9a52",
|
|
2981
|
+
// amber
|
|
2982
|
+
yellow: "#e0c662",
|
|
2983
|
+
// brass gold
|
|
2984
|
+
green: "#6fb58c",
|
|
2985
|
+
// sea-glass green
|
|
2986
|
+
blue: "#4f9bc4",
|
|
2987
|
+
// sea blue
|
|
2988
|
+
purple: "#9486bf",
|
|
2989
|
+
// twilight harbor
|
|
2990
|
+
teal: "#5cb0ac",
|
|
2991
|
+
// sea-glass teal
|
|
2992
|
+
cyan: "#62b4cf",
|
|
2993
|
+
// shallow water
|
|
2994
|
+
gray: "#9aa39c",
|
|
2995
|
+
// driftwood gray
|
|
2996
|
+
black: "#16303f",
|
|
2997
|
+
// raised hull
|
|
2998
|
+
white: "#e6ebe8"
|
|
2999
|
+
// weathered white
|
|
3000
|
+
}
|
|
3001
|
+
}
|
|
3002
|
+
};
|
|
3003
|
+
registerPalette(tidewaterPalette);
|
|
3004
|
+
}
|
|
3005
|
+
});
|
|
3006
|
+
|
|
2587
3007
|
// src/palettes/tokyo-night.ts
|
|
2588
3008
|
var tokyoNightPalette;
|
|
2589
3009
|
var init_tokyo_night = __esm({
|
|
@@ -2859,7 +3279,8 @@ var init_monokai = __esm({
|
|
|
2859
3279
|
// src/palettes/index.ts
|
|
2860
3280
|
var palettes_exports = {};
|
|
2861
3281
|
__export(palettes_exports, {
|
|
2862
|
-
|
|
3282
|
+
atlasPalette: () => atlasPalette,
|
|
3283
|
+
blueprintPalette: () => blueprintPalette,
|
|
2863
3284
|
catppuccinPalette: () => catppuccinPalette,
|
|
2864
3285
|
contrastText: () => contrastText,
|
|
2865
3286
|
draculaPalette: () => draculaPalette,
|
|
@@ -2880,7 +3301,9 @@ __export(palettes_exports, {
|
|
|
2880
3301
|
rosePinePalette: () => rosePinePalette,
|
|
2881
3302
|
shade: () => shade,
|
|
2882
3303
|
shapeFill: () => shapeFill,
|
|
3304
|
+
slatePalette: () => slatePalette,
|
|
2883
3305
|
solarizedPalette: () => solarizedPalette,
|
|
3306
|
+
tidewaterPalette: () => tidewaterPalette,
|
|
2884
3307
|
tint: () => tint,
|
|
2885
3308
|
tokyoNightPalette: () => tokyoNightPalette
|
|
2886
3309
|
});
|
|
@@ -2890,17 +3313,21 @@ var init_palettes = __esm({
|
|
|
2890
3313
|
"use strict";
|
|
2891
3314
|
init_registry();
|
|
2892
3315
|
init_color_utils();
|
|
2893
|
-
|
|
3316
|
+
init_atlas();
|
|
3317
|
+
init_blueprint();
|
|
2894
3318
|
init_catppuccin();
|
|
2895
3319
|
init_gruvbox();
|
|
2896
3320
|
init_nord();
|
|
2897
3321
|
init_one_dark();
|
|
2898
3322
|
init_rose_pine();
|
|
3323
|
+
init_slate();
|
|
2899
3324
|
init_solarized();
|
|
3325
|
+
init_tidewater();
|
|
2900
3326
|
init_tokyo_night();
|
|
2901
3327
|
init_dracula();
|
|
2902
3328
|
init_monokai();
|
|
2903
|
-
|
|
3329
|
+
init_atlas();
|
|
3330
|
+
init_blueprint();
|
|
2904
3331
|
init_catppuccin();
|
|
2905
3332
|
init_dracula();
|
|
2906
3333
|
init_gruvbox();
|
|
@@ -2908,9 +3335,15 @@ var init_palettes = __esm({
|
|
|
2908
3335
|
init_nord();
|
|
2909
3336
|
init_one_dark();
|
|
2910
3337
|
init_rose_pine();
|
|
3338
|
+
init_slate();
|
|
2911
3339
|
init_solarized();
|
|
3340
|
+
init_tidewater();
|
|
2912
3341
|
init_tokyo_night();
|
|
2913
3342
|
palettes = {
|
|
3343
|
+
atlas: atlasPalette,
|
|
3344
|
+
blueprint: blueprintPalette,
|
|
3345
|
+
slate: slatePalette,
|
|
3346
|
+
tidewater: tidewaterPalette,
|
|
2914
3347
|
nord: nordPalette,
|
|
2915
3348
|
catppuccin: catppuccinPalette,
|
|
2916
3349
|
solarized: solarizedPalette,
|
|
@@ -2919,8 +3352,7 @@ var init_palettes = __esm({
|
|
|
2919
3352
|
oneDark: oneDarkPalette,
|
|
2920
3353
|
rosePine: rosePinePalette,
|
|
2921
3354
|
dracula: draculaPalette,
|
|
2922
|
-
monokai: monokaiPalette
|
|
2923
|
-
bold: boldPalette
|
|
3355
|
+
monokai: monokaiPalette
|
|
2924
3356
|
};
|
|
2925
3357
|
}
|
|
2926
3358
|
});
|
|
@@ -3430,6 +3862,9 @@ function controlsGroupCapsuleWidth(toggles) {
|
|
|
3430
3862
|
}
|
|
3431
3863
|
return w;
|
|
3432
3864
|
}
|
|
3865
|
+
function isAppHostedControls(config, isExport) {
|
|
3866
|
+
return !isExport && config.controlsHost === "app" && !!config.controlsGroup && config.controlsGroup.toggles.length > 0;
|
|
3867
|
+
}
|
|
3433
3868
|
function buildControlsGroupLayout(config, state) {
|
|
3434
3869
|
const cg = config.controlsGroup;
|
|
3435
3870
|
if (!cg || cg.toggles.length === 0) return void 0;
|
|
@@ -3483,6 +3918,7 @@ function buildControlsGroupLayout(config, state) {
|
|
|
3483
3918
|
function computeLegendLayout(config, state, containerWidth) {
|
|
3484
3919
|
const { groups, controls: configControls, mode } = config;
|
|
3485
3920
|
const isExport = mode === "export";
|
|
3921
|
+
const gated = isAppHostedControls(config, isExport);
|
|
3486
3922
|
const activeGroupName = state.activeGroup?.toLowerCase() ?? null;
|
|
3487
3923
|
if (isExport && !activeGroupName) {
|
|
3488
3924
|
return {
|
|
@@ -3493,7 +3929,7 @@ function computeLegendLayout(config, state, containerWidth) {
|
|
|
3493
3929
|
pills: []
|
|
3494
3930
|
};
|
|
3495
3931
|
}
|
|
3496
|
-
const controlsGroupLayout = isExport ? void 0 : buildControlsGroupLayout(config, state);
|
|
3932
|
+
const controlsGroupLayout = isExport || gated ? void 0 : buildControlsGroupLayout(config, state);
|
|
3497
3933
|
const visibleGroups = config.showEmptyGroups ? groups : groups.filter((g) => g.entries.length > 0 || !!g.gradient);
|
|
3498
3934
|
if (visibleGroups.length === 0 && (!configControls || configControls.length === 0) && !controlsGroupLayout) {
|
|
3499
3935
|
return {
|
|
@@ -8325,8 +8761,8 @@ function computeScatterLabelGraphics(points, chartBounds, fontSize, symbolSize,
|
|
|
8325
8761
|
const pt = points[i];
|
|
8326
8762
|
const ptSize = pt.size ?? symbolSize;
|
|
8327
8763
|
const minGap = ptSize / 2 + 4;
|
|
8328
|
-
const
|
|
8329
|
-
const labelX = pt.px -
|
|
8764
|
+
const labelWidth2 = pt.name.length * fontSize * 0.6 + 8;
|
|
8765
|
+
const labelX = pt.px - labelWidth2 / 2;
|
|
8330
8766
|
let bestLabelY = 0;
|
|
8331
8767
|
let bestOffset = Infinity;
|
|
8332
8768
|
let placed = false;
|
|
@@ -8338,7 +8774,7 @@ function computeScatterLabelGraphics(points, chartBounds, fontSize, symbolSize,
|
|
|
8338
8774
|
const candidate = {
|
|
8339
8775
|
x: labelX,
|
|
8340
8776
|
y: labelY,
|
|
8341
|
-
w:
|
|
8777
|
+
w: labelWidth2,
|
|
8342
8778
|
h: labelHeight
|
|
8343
8779
|
};
|
|
8344
8780
|
let collision = false;
|
|
@@ -8380,7 +8816,7 @@ function computeScatterLabelGraphics(points, chartBounds, fontSize, symbolSize,
|
|
|
8380
8816
|
const labelRect = {
|
|
8381
8817
|
x: labelX,
|
|
8382
8818
|
y: bestLabelY,
|
|
8383
|
-
w:
|
|
8819
|
+
w: labelWidth2,
|
|
8384
8820
|
h: labelHeight
|
|
8385
8821
|
};
|
|
8386
8822
|
placedLabels.push(labelRect);
|
|
@@ -8416,7 +8852,7 @@ function computeScatterLabelGraphics(points, chartBounds, fontSize, symbolSize,
|
|
|
8416
8852
|
shape: {
|
|
8417
8853
|
x: labelX - bgPad,
|
|
8418
8854
|
y: bestLabelY - bgPad,
|
|
8419
|
-
width:
|
|
8855
|
+
width: labelWidth2 + bgPad * 2,
|
|
8420
8856
|
height: labelHeight + bgPad * 2
|
|
8421
8857
|
},
|
|
8422
8858
|
style: { fill: bg },
|
|
@@ -15856,10 +16292,6 @@ function parseMap(content) {
|
|
|
15856
16292
|
handleTag(trimmed, lineNumber);
|
|
15857
16293
|
continue;
|
|
15858
16294
|
}
|
|
15859
|
-
if ((firstWord === "muted" || firstWord === "natural") && trimmed === firstWord) {
|
|
15860
|
-
handleDirective(firstWord, "", lineNumber);
|
|
15861
|
-
continue;
|
|
15862
|
-
}
|
|
15863
16295
|
if (DIRECTIVE_SET.has(firstWord) && !trimmed.slice(firstWord.length).trimStart().startsWith(":")) {
|
|
15864
16296
|
handleDirective(
|
|
15865
16297
|
firstWord,
|
|
@@ -15906,28 +16338,13 @@ function parseMap(content) {
|
|
|
15906
16338
|
pushWarning(line12, `Duplicate directive "${key}" \u2014 last value wins.`);
|
|
15907
16339
|
};
|
|
15908
16340
|
switch (key) {
|
|
15909
|
-
case "region":
|
|
15910
|
-
dup(d.region);
|
|
15911
|
-
d.region = value;
|
|
15912
|
-
break;
|
|
15913
|
-
case "projection":
|
|
15914
|
-
dup(d.projection);
|
|
15915
|
-
if (value && ![
|
|
15916
|
-
"equirectangular",
|
|
15917
|
-
"natural-earth",
|
|
15918
|
-
"albers-usa",
|
|
15919
|
-
"mercator"
|
|
15920
|
-
].includes(value))
|
|
15921
|
-
pushWarning(
|
|
15922
|
-
line12,
|
|
15923
|
-
`Unknown projection "${value}" (expected equirectangular | natural-earth | albers-usa | mercator).`
|
|
15924
|
-
);
|
|
15925
|
-
d.projection = value;
|
|
15926
|
-
break;
|
|
15927
|
-
case "region-metric":
|
|
16341
|
+
case "region-metric": {
|
|
15928
16342
|
dup(d.regionMetric);
|
|
15929
|
-
|
|
16343
|
+
const { label: rmLabel, colorName: rmColor } = peelTrailingColorName(value);
|
|
16344
|
+
d.regionMetric = rmLabel;
|
|
16345
|
+
if (rmColor) d.regionMetricColor = rmColor;
|
|
15930
16346
|
break;
|
|
16347
|
+
}
|
|
15931
16348
|
case "poi-metric":
|
|
15932
16349
|
dup(d.poiMetric);
|
|
15933
16350
|
d.poiMetric = value;
|
|
@@ -15936,85 +16353,43 @@ function parseMap(content) {
|
|
|
15936
16353
|
dup(d.flowMetric);
|
|
15937
16354
|
d.flowMetric = value;
|
|
15938
16355
|
break;
|
|
15939
|
-
case "
|
|
15940
|
-
dup(d.
|
|
15941
|
-
|
|
15942
|
-
const s = parseScale(value, line12);
|
|
15943
|
-
if (s) d.scale = s;
|
|
15944
|
-
}
|
|
15945
|
-
break;
|
|
15946
|
-
case "region-labels":
|
|
15947
|
-
dup(d.regionLabels);
|
|
15948
|
-
if (value && !["full", "abbrev", "off"].includes(value))
|
|
15949
|
-
pushWarning(
|
|
15950
|
-
line12,
|
|
15951
|
-
`Unknown region-labels "${value}" (expected full | abbrev | off).`
|
|
15952
|
-
);
|
|
15953
|
-
d.regionLabels = value;
|
|
15954
|
-
break;
|
|
15955
|
-
case "poi-labels":
|
|
15956
|
-
dup(d.poiLabels);
|
|
15957
|
-
if (value && !["off", "auto", "all"].includes(value))
|
|
15958
|
-
pushWarning(
|
|
15959
|
-
line12,
|
|
15960
|
-
`Unknown poi-labels "${value}" (expected off | auto | all).`
|
|
15961
|
-
);
|
|
15962
|
-
d.poiLabels = value;
|
|
15963
|
-
break;
|
|
15964
|
-
case "default-country":
|
|
15965
|
-
dup(d.defaultCountry);
|
|
15966
|
-
d.defaultCountry = value;
|
|
15967
|
-
break;
|
|
15968
|
-
case "default-state":
|
|
15969
|
-
dup(d.defaultState);
|
|
15970
|
-
d.defaultState = value;
|
|
16356
|
+
case "locale":
|
|
16357
|
+
dup(d.locale);
|
|
16358
|
+
d.locale = value;
|
|
15971
16359
|
break;
|
|
15972
16360
|
case "active-tag":
|
|
15973
16361
|
dup(d.activeTag);
|
|
15974
16362
|
d.activeTag = value;
|
|
15975
16363
|
break;
|
|
16364
|
+
case "caption":
|
|
16365
|
+
dup(d.caption);
|
|
16366
|
+
d.caption = value;
|
|
16367
|
+
break;
|
|
16368
|
+
// ── Cosmetic `no-*` opt-outs: bare flags, idempotent (mirror `no-legend`,
|
|
16369
|
+
// no dup warning); each defaults the feature ON when absent. ──
|
|
15976
16370
|
case "no-legend":
|
|
15977
16371
|
d.noLegend = true;
|
|
15978
16372
|
break;
|
|
15979
|
-
case "
|
|
15980
|
-
|
|
15981
|
-
if (d.basemapStyle !== void 0 && d.basemapStyle !== key)
|
|
15982
|
-
pushWarning(
|
|
15983
|
-
line12,
|
|
15984
|
-
`Conflicting basemap dress \u2014 "${d.basemapStyle}" then "${key}"; last wins.`
|
|
15985
|
-
);
|
|
15986
|
-
d.basemapStyle = key;
|
|
16373
|
+
case "no-coastline":
|
|
16374
|
+
d.noCoastline = true;
|
|
15987
16375
|
break;
|
|
15988
|
-
case "
|
|
15989
|
-
|
|
15990
|
-
d.subtitle = value;
|
|
16376
|
+
case "no-relief":
|
|
16377
|
+
d.noRelief = true;
|
|
15991
16378
|
break;
|
|
15992
|
-
case "
|
|
15993
|
-
|
|
15994
|
-
|
|
16379
|
+
case "no-context-labels":
|
|
16380
|
+
d.noContextLabels = true;
|
|
16381
|
+
break;
|
|
16382
|
+
case "no-region-labels":
|
|
16383
|
+
d.noRegionLabels = true;
|
|
16384
|
+
break;
|
|
16385
|
+
case "no-poi-labels":
|
|
16386
|
+
d.noPoiLabels = true;
|
|
16387
|
+
break;
|
|
16388
|
+
case "no-colorize":
|
|
16389
|
+
d.noColorize = true;
|
|
15995
16390
|
break;
|
|
15996
16391
|
}
|
|
15997
16392
|
}
|
|
15998
|
-
function parseScale(value, line12) {
|
|
15999
|
-
const toks = value.split(/\s+/).filter(Boolean);
|
|
16000
|
-
const min = Number(toks[0]);
|
|
16001
|
-
const max = Number(toks[1]);
|
|
16002
|
-
if (!Number.isFinite(min) || !Number.isFinite(max)) {
|
|
16003
|
-
pushError(line12, `scale requires numeric <min> <max> (got "${value}").`);
|
|
16004
|
-
return null;
|
|
16005
|
-
}
|
|
16006
|
-
const scale = { min, max };
|
|
16007
|
-
if (toks[2] === "center") {
|
|
16008
|
-
const c = Number(toks[3]);
|
|
16009
|
-
if (Number.isFinite(c)) scale.center = c;
|
|
16010
|
-
else
|
|
16011
|
-
pushError(
|
|
16012
|
-
line12,
|
|
16013
|
-
`scale center requires a number (got "${toks[3] ?? ""}").`
|
|
16014
|
-
);
|
|
16015
|
-
}
|
|
16016
|
-
return scale;
|
|
16017
|
-
}
|
|
16018
16393
|
function handleTag(trimmed, line12) {
|
|
16019
16394
|
const m = matchTagBlockHeading(trimmed);
|
|
16020
16395
|
if (!m) {
|
|
@@ -16088,6 +16463,7 @@ function parseMap(content) {
|
|
|
16088
16463
|
};
|
|
16089
16464
|
if (regionScope !== void 0) region.scope = regionScope;
|
|
16090
16465
|
if (valueNum !== void 0) region.value = valueNum;
|
|
16466
|
+
if (split.color) region.color = split.color;
|
|
16091
16467
|
regions.push(region);
|
|
16092
16468
|
}
|
|
16093
16469
|
function handlePoi(rest, line12, indent) {
|
|
@@ -16112,6 +16488,7 @@ function parseMap(content) {
|
|
|
16112
16488
|
const poi = { pos, tags, meta, lineNumber: line12 };
|
|
16113
16489
|
if (split.alias) poi.alias = split.alias;
|
|
16114
16490
|
if (label !== void 0) poi.label = label;
|
|
16491
|
+
if (split.color) poi.color = split.color;
|
|
16115
16492
|
pois.push(poi);
|
|
16116
16493
|
open.poi = { poi, indent };
|
|
16117
16494
|
}
|
|
@@ -16212,13 +16589,15 @@ function parseMap(content) {
|
|
|
16212
16589
|
pushError(line12, `Edge has an empty endpoint: "${trimmed}".`);
|
|
16213
16590
|
continue;
|
|
16214
16591
|
}
|
|
16215
|
-
const
|
|
16592
|
+
const isLast = k === links.length - 1;
|
|
16593
|
+
const meta = isLast ? lastSplit.meta : {};
|
|
16594
|
+
const style = links[k].style === "arc" ? "arc" : "straight";
|
|
16216
16595
|
edges.push({
|
|
16217
16596
|
from,
|
|
16218
16597
|
to,
|
|
16219
16598
|
...links[k].label !== void 0 && { label: links[k].label },
|
|
16220
16599
|
directed: links[k].directed,
|
|
16221
|
-
style
|
|
16600
|
+
style,
|
|
16222
16601
|
meta,
|
|
16223
16602
|
lineNumber: line12
|
|
16224
16603
|
});
|
|
@@ -16304,20 +16683,19 @@ var init_parser12 = __esm({
|
|
|
16304
16683
|
LEG_ARROW_RE = /^(-[^>]*?->|->|~[^>]*?~>|~>|--)\s+(.+)$/;
|
|
16305
16684
|
AT_RE = /(^|[\s,])at\s*:/i;
|
|
16306
16685
|
DIRECTIVE_SET = /* @__PURE__ */ new Set([
|
|
16307
|
-
"region",
|
|
16308
|
-
"projection",
|
|
16309
16686
|
"region-metric",
|
|
16310
16687
|
"poi-metric",
|
|
16311
16688
|
"flow-metric",
|
|
16312
|
-
"
|
|
16313
|
-
"region-labels",
|
|
16314
|
-
"poi-labels",
|
|
16315
|
-
"default-country",
|
|
16316
|
-
"default-state",
|
|
16689
|
+
"locale",
|
|
16317
16690
|
"active-tag",
|
|
16691
|
+
"caption",
|
|
16318
16692
|
"no-legend",
|
|
16319
|
-
"
|
|
16320
|
-
"
|
|
16693
|
+
"no-coastline",
|
|
16694
|
+
"no-relief",
|
|
16695
|
+
"no-context-labels",
|
|
16696
|
+
"no-region-labels",
|
|
16697
|
+
"no-poi-labels",
|
|
16698
|
+
"no-colorize"
|
|
16321
16699
|
]);
|
|
16322
16700
|
}
|
|
16323
16701
|
});
|
|
@@ -24328,8 +24706,8 @@ function renderKanban(container, parsed, palette, isDark, options) {
|
|
|
24328
24706
|
let metaY = separatorY + sCardSeparatorGap + sCardMetaFontSize;
|
|
24329
24707
|
for (const meta of tagMeta) {
|
|
24330
24708
|
cg.append("text").attr("x", cx + sCardPaddingX).attr("y", metaY).attr("font-size", sCardMetaFontSize).attr("fill", onCardText).text(`${meta.label}: `);
|
|
24331
|
-
const
|
|
24332
|
-
cg.append("text").attr("x", cx + sCardPaddingX +
|
|
24709
|
+
const labelWidth2 = (meta.label.length + 2) * sCardMetaFontSize * 0.6;
|
|
24710
|
+
cg.append("text").attr("x", cx + sCardPaddingX + labelWidth2).attr("y", metaY).attr("font-size", sCardMetaFontSize).attr("fill", onCardText).text(meta.value);
|
|
24333
24711
|
metaY += sCardMetaLineHeight;
|
|
24334
24712
|
}
|
|
24335
24713
|
for (const detail of card.details) {
|
|
@@ -24673,8 +25051,8 @@ function renderSwimlaneCard(parent, cardLayout, tagGroups, activeTagGroup, palet
|
|
|
24673
25051
|
let metaY = separatorY + sCardSeparatorGap + sCardMetaFontSize;
|
|
24674
25052
|
for (const meta of tagMeta) {
|
|
24675
25053
|
cg.append("text").attr("x", cx + sCardPaddingX).attr("y", metaY).attr("font-size", sCardMetaFontSize).attr("fill", palette.textMuted).text(`${meta.label}: `);
|
|
24676
|
-
const
|
|
24677
|
-
cg.append("text").attr("x", cx + sCardPaddingX +
|
|
25054
|
+
const labelWidth2 = (meta.label.length + 2) * sCardMetaFontSize * 0.6;
|
|
25055
|
+
cg.append("text").attr("x", cx + sCardPaddingX + labelWidth2).attr("y", metaY).attr("font-size", sCardMetaFontSize).attr("fill", onCardText).text(meta.value);
|
|
24678
25056
|
metaY += sCardMetaLineHeight;
|
|
24679
25057
|
}
|
|
24680
25058
|
for (const detail of card.details) {
|
|
@@ -25509,8 +25887,8 @@ function classifyEREntities(tables, relationships) {
|
|
|
25509
25887
|
}
|
|
25510
25888
|
}
|
|
25511
25889
|
const mmParticipants = /* @__PURE__ */ new Set();
|
|
25512
|
-
for (const [id,
|
|
25513
|
-
if (
|
|
25890
|
+
for (const [id, neighbors2] of tableStarNeighbors) {
|
|
25891
|
+
if (neighbors2.size >= 2) mmParticipants.add(id);
|
|
25514
25892
|
}
|
|
25515
25893
|
const indegreeValues = Object.values(indegreeMap);
|
|
25516
25894
|
const mean = indegreeValues.reduce((a, b) => a + b, 0) / indegreeValues.length;
|
|
@@ -26181,7 +26559,8 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26181
26559
|
controlsExpanded,
|
|
26182
26560
|
onToggleDescriptions,
|
|
26183
26561
|
onToggleControlsExpand,
|
|
26184
|
-
exportMode = false
|
|
26562
|
+
exportMode = false,
|
|
26563
|
+
controlsHost
|
|
26185
26564
|
} = options ?? {};
|
|
26186
26565
|
d3Selection6.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
26187
26566
|
const width = exportDims?.width ?? container.clientWidth;
|
|
@@ -26199,7 +26578,11 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26199
26578
|
const sGroupLabelZone = sctx.structural(GROUP_LABEL_ZONE);
|
|
26200
26579
|
const sTitleFontSize = sctx.text(TITLE_FONT_SIZE);
|
|
26201
26580
|
const sTitleY = sctx.structural(TITLE_Y);
|
|
26202
|
-
const
|
|
26581
|
+
const reserveHasDescriptions = parsed.nodes.some(
|
|
26582
|
+
(n) => n.description && n.description.length > 0
|
|
26583
|
+
);
|
|
26584
|
+
const willRenderLegend = parsed.tagGroups.length > 0 || reserveHasDescriptions && controlsHost !== "app";
|
|
26585
|
+
const sLegendHeight = willRenderLegend ? sctx.structural(
|
|
26203
26586
|
getMaxLegendReservedHeight(
|
|
26204
26587
|
{
|
|
26205
26588
|
groups: parsed.tagGroups,
|
|
@@ -26208,7 +26591,7 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26208
26591
|
},
|
|
26209
26592
|
width
|
|
26210
26593
|
)
|
|
26211
|
-
);
|
|
26594
|
+
) : 0;
|
|
26212
26595
|
const activeGroup = resolveActiveTagGroup(
|
|
26213
26596
|
parsed.tagGroups,
|
|
26214
26597
|
parsed.options["active-tag"],
|
|
@@ -26523,10 +26906,10 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26523
26906
|
const hasDescriptions = parsed.nodes.some(
|
|
26524
26907
|
(n) => n.description && n.description.length > 0
|
|
26525
26908
|
);
|
|
26526
|
-
const hasLegend = parsed.tagGroups.length > 0 || hasDescriptions;
|
|
26909
|
+
const hasLegend = parsed.tagGroups.length > 0 || hasDescriptions && controlsHost !== "app";
|
|
26527
26910
|
if (hasLegend) {
|
|
26528
26911
|
let controlsGroup;
|
|
26529
|
-
if (hasDescriptions && onToggleDescriptions) {
|
|
26912
|
+
if (hasDescriptions && (onToggleDescriptions || controlsHost === "app")) {
|
|
26530
26913
|
controlsGroup = {
|
|
26531
26914
|
toggles: [
|
|
26532
26915
|
{
|
|
@@ -26544,7 +26927,14 @@ function renderBoxesAndLines(container, parsed, layout, palette, isDark, options
|
|
|
26544
26927
|
groups: parsed.tagGroups,
|
|
26545
26928
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
26546
26929
|
mode: exportMode ? "export" : "preview",
|
|
26547
|
-
|
|
26930
|
+
// Keep inactive sibling tag groups visible as collapsed pills so the user
|
|
26931
|
+
// can click one to flip the active colouring dimension (preview only —
|
|
26932
|
+
// export shows just the active group). Without this, declaring a second
|
|
26933
|
+
// tag group (e.g. Team) leaves it invisible whenever another group is
|
|
26934
|
+
// active. The app's BoxesAndLinesPreview already wires pill clicks.
|
|
26935
|
+
showInactivePills: true,
|
|
26936
|
+
...controlsGroup !== void 0 && { controlsGroup },
|
|
26937
|
+
...controlsHost !== void 0 && { controlsHost }
|
|
26548
26938
|
};
|
|
26549
26939
|
const legendState = {
|
|
26550
26940
|
activeGroup,
|
|
@@ -27792,8 +28182,9 @@ function renderMindmap(container, parsed, layout, palette, isDark, onClickItem,
|
|
|
27792
28182
|
const containerHeight = exportDims?.height ?? (container.getBoundingClientRect().height || 600);
|
|
27793
28183
|
d3Selection7.select(container).selectAll("*").remove();
|
|
27794
28184
|
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);
|
|
28185
|
+
const appHosted = options?.controlsHost === "app";
|
|
27795
28186
|
const hasControls = !!options?.onToggleColorByDepth || !!options?.onToggleDescriptions;
|
|
27796
|
-
const hasLegend = parsed.tagGroups.length > 0 || hasControls;
|
|
28187
|
+
const hasLegend = parsed.tagGroups.length > 0 || hasControls && !appHosted;
|
|
27797
28188
|
const fixedLegend = !isExport && hasLegend;
|
|
27798
28189
|
const legendReserve = fixedLegend ? getMaxLegendReservedHeight(
|
|
27799
28190
|
{
|
|
@@ -27887,7 +28278,10 @@ function renderMindmap(container, parsed, layout, palette, isDark, onClickItem,
|
|
|
27887
28278
|
}),
|
|
27888
28279
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
27889
28280
|
mode: options?.exportMode ? "export" : "preview",
|
|
27890
|
-
...controlsToggles !== void 0 && { controlsGroup: controlsToggles }
|
|
28281
|
+
...controlsToggles !== void 0 && { controlsGroup: controlsToggles },
|
|
28282
|
+
...options?.controlsHost !== void 0 && {
|
|
28283
|
+
controlsHost: options.controlsHost
|
|
28284
|
+
}
|
|
27891
28285
|
};
|
|
27892
28286
|
const legendState = {
|
|
27893
28287
|
activeGroup: options?.colorByDepth ? null : activeTagGroup !== void 0 ? activeTagGroup : parsed.options["active-tag"] ?? null,
|
|
@@ -28331,8 +28725,8 @@ function computeFieldAlignX(children) {
|
|
|
28331
28725
|
for (const child of children) {
|
|
28332
28726
|
if (child.metadata["_labelField"] === "true" && child.children.length >= 2) {
|
|
28333
28727
|
const labelEl = child.children[0];
|
|
28334
|
-
const
|
|
28335
|
-
maxLabelWidth = Math.max(maxLabelWidth,
|
|
28728
|
+
const labelWidth2 = labelEl.label.length * CHAR_WIDTH5;
|
|
28729
|
+
maxLabelWidth = Math.max(maxLabelWidth, labelWidth2);
|
|
28336
28730
|
labelFieldCount++;
|
|
28337
28731
|
}
|
|
28338
28732
|
}
|
|
@@ -33296,7 +33690,7 @@ function hasRoles(node) {
|
|
|
33296
33690
|
function computeNodeWidth2(node, expanded, options) {
|
|
33297
33691
|
const badgeVal = node.computedConcurrentInvocations === 0 && node.computedInstances > 1 ? node.computedInstances : 0;
|
|
33298
33692
|
const badgeLen = badgeVal > 0 ? `${badgeVal}x`.length + 2 : 0;
|
|
33299
|
-
const
|
|
33693
|
+
const labelWidth2 = (node.label.length + badgeLen) * CHAR_WIDTH7 + PADDING_X3;
|
|
33300
33694
|
const allKeys = [];
|
|
33301
33695
|
if (node.computedRps > 0) allKeys.push("RPS");
|
|
33302
33696
|
if (expanded) {
|
|
@@ -33340,7 +33734,7 @@ function computeNodeWidth2(node, expanded, options) {
|
|
|
33340
33734
|
allKeys.push("overflow");
|
|
33341
33735
|
}
|
|
33342
33736
|
}
|
|
33343
|
-
if (allKeys.length === 0) return Math.max(MIN_NODE_WIDTH2,
|
|
33737
|
+
if (allKeys.length === 0) return Math.max(MIN_NODE_WIDTH2, labelWidth2);
|
|
33344
33738
|
const maxKeyLen = Math.max(...allKeys.map((k) => k.length));
|
|
33345
33739
|
let maxRowWidth = 0;
|
|
33346
33740
|
if (node.computedRps > 0) {
|
|
@@ -33428,7 +33822,7 @@ function computeNodeWidth2(node, expanded, options) {
|
|
|
33428
33822
|
truncated.length * META_CHAR_WIDTH3 + PADDING_X3
|
|
33429
33823
|
);
|
|
33430
33824
|
}
|
|
33431
|
-
return Math.max(MIN_NODE_WIDTH2,
|
|
33825
|
+
return Math.max(MIN_NODE_WIDTH2, labelWidth2, maxRowWidth + 20, descWidth);
|
|
33432
33826
|
}
|
|
33433
33827
|
function computeNodeHeight2(node, expanded, options) {
|
|
33434
33828
|
const propCount = countDisplayProps(node, expanded, options);
|
|
@@ -34977,8 +35371,9 @@ function computeInfraLegendGroups(nodes, tagGroups, palette, edges) {
|
|
|
34977
35371
|
}
|
|
34978
35372
|
return groups;
|
|
34979
35373
|
}
|
|
34980
|
-
function renderLegend3(rootSvg, legendGroups, totalWidth, legendY, palette, isDark, activeGroup, playback, exportMode = false) {
|
|
35374
|
+
function renderLegend3(rootSvg, legendGroups, totalWidth, legendY, palette, isDark, activeGroup, playback, exportMode = false, controlsHost) {
|
|
34981
35375
|
if (legendGroups.length === 0 && !playback) return;
|
|
35376
|
+
const appHostedPlayback = controlsHost === "app" && !!playback;
|
|
34982
35377
|
const legendG = rootSvg.append("g").attr("transform", `translate(0, ${legendY})`);
|
|
34983
35378
|
if (activeGroup) {
|
|
34984
35379
|
legendG.attr("data-legend-active", activeGroup.toLowerCase());
|
|
@@ -34987,14 +35382,29 @@ function renderLegend3(rootSvg, legendGroups, totalWidth, legendY, palette, isDa
|
|
|
34987
35382
|
name: g.name,
|
|
34988
35383
|
entries: g.entries.map((e) => ({ value: e.value, color: e.color }))
|
|
34989
35384
|
}));
|
|
34990
|
-
if (playback) {
|
|
35385
|
+
if (playback && !appHostedPlayback) {
|
|
34991
35386
|
allGroups.push({ name: "Playback", entries: [] });
|
|
34992
35387
|
}
|
|
34993
35388
|
const legendConfig = {
|
|
34994
35389
|
groups: allGroups,
|
|
34995
35390
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
34996
35391
|
mode: exportMode ? "export" : "preview",
|
|
34997
|
-
showEmptyGroups: true
|
|
35392
|
+
showEmptyGroups: true,
|
|
35393
|
+
...appHostedPlayback && {
|
|
35394
|
+
controlsHost: "app",
|
|
35395
|
+
controlsGroup: {
|
|
35396
|
+
toggles: [
|
|
35397
|
+
{
|
|
35398
|
+
id: "playback",
|
|
35399
|
+
type: "toggle",
|
|
35400
|
+
label: "Playback",
|
|
35401
|
+
active: true,
|
|
35402
|
+
onToggle: () => {
|
|
35403
|
+
}
|
|
35404
|
+
}
|
|
35405
|
+
]
|
|
35406
|
+
}
|
|
35407
|
+
}
|
|
34998
35408
|
};
|
|
34999
35409
|
const legendState = { activeGroup };
|
|
35000
35410
|
renderLegendD3(
|
|
@@ -35045,8 +35455,9 @@ function renderLegend3(rootSvg, legendGroups, totalWidth, legendY, palette, isDa
|
|
|
35045
35455
|
}
|
|
35046
35456
|
}
|
|
35047
35457
|
}
|
|
35048
|
-
function renderInfra(container, layout, palette, isDark, title, titleLineNumber, tagGroups, activeGroup, animate, playback, expandedNodeIds, exportMode, collapsedNodes) {
|
|
35458
|
+
function renderInfra(container, layout, palette, isDark, title, titleLineNumber, tagGroups, activeGroup, animate, playback, expandedNodeIds, exportMode, collapsedNodes, controlsHost) {
|
|
35049
35459
|
d3Selection11.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
35460
|
+
const appHostedPlayback = controlsHost === "app" && !!playback;
|
|
35050
35461
|
const ctx = ScaleContext.identity();
|
|
35051
35462
|
const sc = buildScaledConstants(ctx);
|
|
35052
35463
|
const legendGroups = computeInfraLegendGroups(
|
|
@@ -35055,7 +35466,7 @@ function renderInfra(container, layout, palette, isDark, title, titleLineNumber,
|
|
|
35055
35466
|
palette,
|
|
35056
35467
|
layout.edges
|
|
35057
35468
|
);
|
|
35058
|
-
const hasLegend = legendGroups.length > 0 || !!playback;
|
|
35469
|
+
const hasLegend = legendGroups.length > 0 || !!playback && !appHostedPlayback;
|
|
35059
35470
|
const fixedLegend = !exportMode && hasLegend;
|
|
35060
35471
|
const legendDynamicH = hasLegend ? getMaxLegendReservedHeight(
|
|
35061
35472
|
{
|
|
@@ -35199,7 +35610,8 @@ function renderInfra(container, layout, palette, isDark, title, titleLineNumber,
|
|
|
35199
35610
|
isDark,
|
|
35200
35611
|
activeGroup ?? null,
|
|
35201
35612
|
playback ?? void 0,
|
|
35202
|
-
exportMode
|
|
35613
|
+
exportMode,
|
|
35614
|
+
controlsHost
|
|
35203
35615
|
);
|
|
35204
35616
|
legendSvg.selectAll(".infra-legend-group").style("pointer-events", "auto");
|
|
35205
35617
|
} else {
|
|
@@ -35212,7 +35624,8 @@ function renderInfra(container, layout, palette, isDark, title, titleLineNumber,
|
|
|
35212
35624
|
isDark,
|
|
35213
35625
|
activeGroup ?? null,
|
|
35214
35626
|
playback ?? void 0,
|
|
35215
|
-
exportMode
|
|
35627
|
+
exportMode,
|
|
35628
|
+
controlsHost
|
|
35216
35629
|
);
|
|
35217
35630
|
}
|
|
35218
35631
|
}
|
|
@@ -43070,6 +43483,9 @@ function renderTechRadar(container, parsed, palette, isDark, onClickItem, export
|
|
|
43070
43483
|
onToggle: (active) => options.onToggleListing(active)
|
|
43071
43484
|
}
|
|
43072
43485
|
]
|
|
43486
|
+
},
|
|
43487
|
+
...options.controlsHost !== void 0 && {
|
|
43488
|
+
controlsHost: options.controlsHost
|
|
43073
43489
|
}
|
|
43074
43490
|
};
|
|
43075
43491
|
const legendState = {
|
|
@@ -44893,7 +45309,7 @@ function computeCycleLayout(parsed, options) {
|
|
|
44893
45309
|
const circleNodes = parsed.options["circle-nodes"] === "true";
|
|
44894
45310
|
const nodeDims = parsed.nodes.map((node) => {
|
|
44895
45311
|
const hasDesc = !hideDescriptions && node.description.length > 0;
|
|
44896
|
-
const
|
|
45312
|
+
const labelWidth2 = Math.max(
|
|
44897
45313
|
MIN_NODE_WIDTH4,
|
|
44898
45314
|
node.label.length * LABEL_CHAR_W + NODE_PAD_X * 2
|
|
44899
45315
|
);
|
|
@@ -44902,12 +45318,12 @@ function computeCycleLayout(parsed, options) {
|
|
|
44902
45318
|
}
|
|
44903
45319
|
if (!hasDesc) {
|
|
44904
45320
|
return {
|
|
44905
|
-
width: Math.min(MAX_NODE_WIDTH3,
|
|
45321
|
+
width: Math.min(MAX_NODE_WIDTH3, labelWidth2),
|
|
44906
45322
|
height: PLAIN_NODE_HEIGHT,
|
|
44907
45323
|
wrappedDesc: []
|
|
44908
45324
|
};
|
|
44909
45325
|
}
|
|
44910
|
-
return chooseDescribedRectDims(node.description,
|
|
45326
|
+
return chooseDescribedRectDims(node.description, labelWidth2);
|
|
44911
45327
|
});
|
|
44912
45328
|
if (circleNodes) {
|
|
44913
45329
|
const maxDiam = Math.max(...nodeDims.map((d) => d.width));
|
|
@@ -45103,10 +45519,10 @@ function computeCycleLayout(parsed, options) {
|
|
|
45103
45519
|
scale
|
|
45104
45520
|
};
|
|
45105
45521
|
}
|
|
45106
|
-
function chooseDescribedRectDims(description,
|
|
45522
|
+
function chooseDescribedRectDims(description, labelWidth2) {
|
|
45107
45523
|
const minW = Math.min(
|
|
45108
45524
|
MAX_NODE_WIDTH3,
|
|
45109
|
-
Math.max(MIN_NODE_WIDTH4,
|
|
45525
|
+
Math.max(MIN_NODE_WIDTH4, labelWidth2, DESC_MIN_WIDTH)
|
|
45110
45526
|
);
|
|
45111
45527
|
let best = null;
|
|
45112
45528
|
let bestScore = Infinity;
|
|
@@ -45534,7 +45950,8 @@ function renderCycle(container, parsed, palette, isDark, onClickItem, exportDims
|
|
|
45534
45950
|
const hideDescriptions = (renderOptions?.hideDescriptions ?? false) || parsed.options["no-descriptions"] === "true" || viewState?.hd === true;
|
|
45535
45951
|
const showDescriptions = !hideDescriptions;
|
|
45536
45952
|
const hasDescriptions = parsed.nodes.some((n) => n.description.length > 0) || parsed.edges.some((e) => e.description.length > 0);
|
|
45537
|
-
const
|
|
45953
|
+
const appHostedControls = renderOptions?.controlsHost === "app";
|
|
45954
|
+
const hasLegend = !appHostedControls && hasDescriptions && !!renderOptions?.onToggleDescriptions;
|
|
45538
45955
|
const showTitle = !!parsed.title && parsed.options["no-title"] !== "on";
|
|
45539
45956
|
const legendOffset = hasLegend ? sLegendHeight : 0;
|
|
45540
45957
|
const layoutHeight = height - (showTitle ? sTitleAreaHeight : 0) - legendOffset;
|
|
@@ -45571,7 +45988,10 @@ function renderCycle(container, parsed, palette, isDark, onClickItem, exportDims
|
|
|
45571
45988
|
groups: [],
|
|
45572
45989
|
position: { placement: "top-center", titleRelation: "below-title" },
|
|
45573
45990
|
mode: renderOptions?.exportMode ? "export" : "preview",
|
|
45574
|
-
controlsGroup
|
|
45991
|
+
controlsGroup,
|
|
45992
|
+
...renderOptions?.controlsHost !== void 0 && {
|
|
45993
|
+
controlsHost: renderOptions.controlsHost
|
|
45994
|
+
}
|
|
45575
45995
|
};
|
|
45576
45996
|
const legendState = {
|
|
45577
45997
|
activeGroup: null,
|
|
@@ -45842,6 +46262,107 @@ function featureIndex(topo) {
|
|
|
45842
46262
|
}
|
|
45843
46263
|
return idx;
|
|
45844
46264
|
}
|
|
46265
|
+
function buildAdjacency(topo) {
|
|
46266
|
+
const cached = adjacencyCache.get(topo);
|
|
46267
|
+
if (cached) return cached;
|
|
46268
|
+
const geometries = geomObject(topo).geometries;
|
|
46269
|
+
const nb = (0, import_topojson_client.neighbors)(geometries);
|
|
46270
|
+
const sets = /* @__PURE__ */ new Map();
|
|
46271
|
+
geometries.forEach((g, i) => {
|
|
46272
|
+
if (!g.type || g.type === "null") return;
|
|
46273
|
+
let set = sets.get(g.id);
|
|
46274
|
+
if (!set) {
|
|
46275
|
+
set = /* @__PURE__ */ new Set();
|
|
46276
|
+
sets.set(g.id, set);
|
|
46277
|
+
}
|
|
46278
|
+
for (const j of nb[i] ?? []) {
|
|
46279
|
+
const nid = geometries[j]?.id;
|
|
46280
|
+
if (nid && nid !== g.id) set.add(nid);
|
|
46281
|
+
}
|
|
46282
|
+
});
|
|
46283
|
+
const out = /* @__PURE__ */ new Map();
|
|
46284
|
+
for (const [iso, set] of sets) out.set(iso, [...set].sort());
|
|
46285
|
+
adjacencyCache.set(topo, out);
|
|
46286
|
+
return out;
|
|
46287
|
+
}
|
|
46288
|
+
function decodeFeatures(topo) {
|
|
46289
|
+
return geomObject(topo).geometries.map((g) => {
|
|
46290
|
+
const f = (0, import_topojson_client.feature)(topo, g);
|
|
46291
|
+
return {
|
|
46292
|
+
type: "Feature",
|
|
46293
|
+
id: g.id,
|
|
46294
|
+
properties: g.properties,
|
|
46295
|
+
geometry: f.geometry
|
|
46296
|
+
};
|
|
46297
|
+
});
|
|
46298
|
+
}
|
|
46299
|
+
function pointInRing(lon, lat, ring) {
|
|
46300
|
+
let inside = false;
|
|
46301
|
+
for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
|
|
46302
|
+
const xi = ring[i][0];
|
|
46303
|
+
const yi = ring[i][1];
|
|
46304
|
+
const xj = ring[j][0];
|
|
46305
|
+
const yj = ring[j][1];
|
|
46306
|
+
const intersect = yi > lat !== yj > lat && lon < (xj - xi) * (lat - yi) / (yj - yi) + xi;
|
|
46307
|
+
if (intersect) inside = !inside;
|
|
46308
|
+
}
|
|
46309
|
+
return inside;
|
|
46310
|
+
}
|
|
46311
|
+
function pointOnRingEdge(lon, lat, ring) {
|
|
46312
|
+
for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
|
|
46313
|
+
const xi = ring[i][0];
|
|
46314
|
+
const yi = ring[i][1];
|
|
46315
|
+
const xj = ring[j][0];
|
|
46316
|
+
const yj = ring[j][1];
|
|
46317
|
+
if (lon < Math.min(xi, xj) - EDGE_EPS || lon > Math.max(xi, xj) + EDGE_EPS)
|
|
46318
|
+
continue;
|
|
46319
|
+
if (lat < Math.min(yi, yj) - EDGE_EPS || lat > Math.max(yi, yj) + EDGE_EPS)
|
|
46320
|
+
continue;
|
|
46321
|
+
const cross = (xj - xi) * (lat - yi) - (yj - yi) * (lon - xi);
|
|
46322
|
+
if (Math.abs(cross) <= EDGE_EPS) return true;
|
|
46323
|
+
}
|
|
46324
|
+
return false;
|
|
46325
|
+
}
|
|
46326
|
+
function pointInGeometry(geometry, lon, lat) {
|
|
46327
|
+
const g = geometry;
|
|
46328
|
+
if (!g) return false;
|
|
46329
|
+
const polys = g.type === "Polygon" ? [g.coordinates] : g.type === "MultiPolygon" ? g.coordinates : [];
|
|
46330
|
+
for (const rings of polys) {
|
|
46331
|
+
if (!rings.length) continue;
|
|
46332
|
+
if (pointOnRingEdge(lon, lat, rings[0])) return true;
|
|
46333
|
+
if (!pointInRing(lon, lat, rings[0])) continue;
|
|
46334
|
+
let inHole = false;
|
|
46335
|
+
for (let h = 1; h < rings.length; h++) {
|
|
46336
|
+
if (pointInRing(lon, lat, rings[h]) && !pointOnRingEdge(lon, lat, rings[h])) {
|
|
46337
|
+
inHole = true;
|
|
46338
|
+
break;
|
|
46339
|
+
}
|
|
46340
|
+
}
|
|
46341
|
+
if (!inHole) return true;
|
|
46342
|
+
}
|
|
46343
|
+
return false;
|
|
46344
|
+
}
|
|
46345
|
+
function regionAt(lonLat, countries, states) {
|
|
46346
|
+
const lon = lonLat[0];
|
|
46347
|
+
const lat = lonLat[1];
|
|
46348
|
+
let country = null;
|
|
46349
|
+
for (const f of countries) {
|
|
46350
|
+
if (pointInGeometry(f.geometry, lon, lat)) {
|
|
46351
|
+
country = { iso: f.id, name: f.properties.name };
|
|
46352
|
+
break;
|
|
46353
|
+
}
|
|
46354
|
+
}
|
|
46355
|
+
let state = null;
|
|
46356
|
+
if (country?.iso === "US" && states) {
|
|
46357
|
+
for (const f of states) {
|
|
46358
|
+
if (pointInGeometry(f.geometry, lon, lat)) {
|
|
46359
|
+
state = { iso: f.id, name: f.properties.name };
|
|
46360
|
+
break;
|
|
46361
|
+
}
|
|
46362
|
+
}
|
|
46363
|
+
}
|
|
46364
|
+
return { country, state };
|
|
46365
|
+
}
|
|
45845
46366
|
function featureBbox(topo, geomId) {
|
|
45846
46367
|
const geom = geomObject(topo).geometries.find((g) => g.id === geomId);
|
|
45847
46368
|
if (!geom) return null;
|
|
@@ -45853,6 +46374,74 @@ function featureBbox(topo, geomId) {
|
|
|
45853
46374
|
[b[1][0], b[1][1]]
|
|
45854
46375
|
];
|
|
45855
46376
|
}
|
|
46377
|
+
function explodePolygons(gj) {
|
|
46378
|
+
const g = gj.geometry ?? gj;
|
|
46379
|
+
const t = g.type;
|
|
46380
|
+
const coords = g.coordinates;
|
|
46381
|
+
if (t === "Polygon") {
|
|
46382
|
+
return [
|
|
46383
|
+
{ type: "Feature", geometry: { type: "Polygon", coordinates: coords } }
|
|
46384
|
+
];
|
|
46385
|
+
}
|
|
46386
|
+
if (t === "MultiPolygon") {
|
|
46387
|
+
return coords.map((rings) => ({
|
|
46388
|
+
type: "Feature",
|
|
46389
|
+
geometry: { type: "Polygon", coordinates: rings }
|
|
46390
|
+
}));
|
|
46391
|
+
}
|
|
46392
|
+
return [];
|
|
46393
|
+
}
|
|
46394
|
+
function bboxGap(a, b) {
|
|
46395
|
+
const lonGap = Math.max(0, a[0][0] - b[1][0], b[0][0] - a[1][0]);
|
|
46396
|
+
const latGap = Math.max(0, a[0][1] - b[1][1], b[0][1] - a[1][1]);
|
|
46397
|
+
return Math.max(lonGap, latGap);
|
|
46398
|
+
}
|
|
46399
|
+
function featureBboxPrimary(topo, geomId) {
|
|
46400
|
+
const geom = geomObject(topo).geometries.find((g) => g.id === geomId);
|
|
46401
|
+
if (!geom) return null;
|
|
46402
|
+
const gj = (0, import_topojson_client.feature)(topo, geom);
|
|
46403
|
+
const parts = explodePolygons(gj);
|
|
46404
|
+
if (parts.length <= 1) return featureBbox(topo, geomId);
|
|
46405
|
+
const polys = parts.map((p) => {
|
|
46406
|
+
const b = (0, import_d3_geo.geoBounds)(p);
|
|
46407
|
+
if (!b || !Number.isFinite(b[0][0])) return null;
|
|
46408
|
+
const wraps = b[1][0] < b[0][0];
|
|
46409
|
+
const bbox = [
|
|
46410
|
+
[b[0][0], b[0][1]],
|
|
46411
|
+
[b[1][0], b[1][1]]
|
|
46412
|
+
];
|
|
46413
|
+
return { bbox, area: (0, import_d3_geo.geoArea)(p), wraps };
|
|
46414
|
+
}).filter(
|
|
46415
|
+
(p) => p !== null
|
|
46416
|
+
);
|
|
46417
|
+
if (polys.length <= 1 || polys.some((p) => p.wraps))
|
|
46418
|
+
return featureBbox(topo, geomId);
|
|
46419
|
+
const maxArea = Math.max(...polys.map((p) => p.area));
|
|
46420
|
+
const anchor = polys.find((p) => p.area === maxArea);
|
|
46421
|
+
const cluster = [
|
|
46422
|
+
[anchor.bbox[0][0], anchor.bbox[0][1]],
|
|
46423
|
+
[anchor.bbox[1][0], anchor.bbox[1][1]]
|
|
46424
|
+
];
|
|
46425
|
+
const remaining = polys.filter((p) => p !== anchor);
|
|
46426
|
+
let added = true;
|
|
46427
|
+
while (added) {
|
|
46428
|
+
added = false;
|
|
46429
|
+
for (let i = remaining.length - 1; i >= 0; i--) {
|
|
46430
|
+
const p = remaining[i];
|
|
46431
|
+
const near = bboxGap(p.bbox, cluster) <= DETACH_GAP_DEG;
|
|
46432
|
+
const large = p.area >= DETACH_AREA_FRAC * maxArea;
|
|
46433
|
+
if (near || large) {
|
|
46434
|
+
cluster[0][0] = Math.min(cluster[0][0], p.bbox[0][0]);
|
|
46435
|
+
cluster[0][1] = Math.min(cluster[0][1], p.bbox[0][1]);
|
|
46436
|
+
cluster[1][0] = Math.max(cluster[1][0], p.bbox[1][0]);
|
|
46437
|
+
cluster[1][1] = Math.max(cluster[1][1], p.bbox[1][1]);
|
|
46438
|
+
remaining.splice(i, 1);
|
|
46439
|
+
added = true;
|
|
46440
|
+
}
|
|
46441
|
+
}
|
|
46442
|
+
}
|
|
46443
|
+
return cluster;
|
|
46444
|
+
}
|
|
45856
46445
|
function unionExtent(boxes, points) {
|
|
45857
46446
|
const lats = [];
|
|
45858
46447
|
const lons = [];
|
|
@@ -45891,13 +46480,17 @@ function unionLongitudes(lons) {
|
|
|
45891
46480
|
}
|
|
45892
46481
|
return { west: pts[gapIdx], east: pts[gapIdx - 1] + 360 };
|
|
45893
46482
|
}
|
|
45894
|
-
var import_topojson_client, import_d3_geo, fold;
|
|
46483
|
+
var import_topojson_client, import_d3_geo, fold, adjacencyCache, EDGE_EPS, DETACH_GAP_DEG, DETACH_AREA_FRAC;
|
|
45895
46484
|
var init_geo = __esm({
|
|
45896
46485
|
"src/map/geo.ts"() {
|
|
45897
46486
|
"use strict";
|
|
45898
46487
|
import_topojson_client = require("topojson-client");
|
|
45899
46488
|
import_d3_geo = require("d3-geo");
|
|
45900
46489
|
fold = (s) => s.normalize("NFD").replace(/\p{Diacritic}/gu, "").toLowerCase().trim();
|
|
46490
|
+
adjacencyCache = /* @__PURE__ */ new WeakMap();
|
|
46491
|
+
EDGE_EPS = 1e-9;
|
|
46492
|
+
DETACH_GAP_DEG = 10;
|
|
46493
|
+
DETACH_AREA_FRAC = 0.25;
|
|
45901
46494
|
}
|
|
45902
46495
|
});
|
|
45903
46496
|
|
|
@@ -45915,6 +46508,12 @@ function looksUS(lat, lon) {
|
|
|
45915
46508
|
if (lat < 15 || lat > 72) return false;
|
|
45916
46509
|
return lon >= -180 && lon <= -64 || lon >= 172;
|
|
45917
46510
|
}
|
|
46511
|
+
function looksNorthAmericaNeighbor(lat, lon) {
|
|
46512
|
+
return lat >= 14 && lat <= 72 && lon >= -141 && lon <= -52;
|
|
46513
|
+
}
|
|
46514
|
+
function isWholeSphere(bb) {
|
|
46515
|
+
return bb[0][0] <= -179 && bb[1][0] >= 179 && bb[0][1] <= -89 && bb[1][1] >= 89;
|
|
46516
|
+
}
|
|
45918
46517
|
function resolveMap(parsed, data) {
|
|
45919
46518
|
const diagnostics = [...parsed.diagnostics];
|
|
45920
46519
|
const err = (line12, message, code) => {
|
|
@@ -45925,9 +46524,6 @@ function resolveMap(parsed, data) {
|
|
|
45925
46524
|
};
|
|
45926
46525
|
const result = {
|
|
45927
46526
|
title: parsed.title,
|
|
45928
|
-
...parsed.directives.subtitle !== void 0 && {
|
|
45929
|
-
subtitle: parsed.directives.subtitle
|
|
45930
|
-
},
|
|
45931
46527
|
...parsed.directives.caption !== void 0 && {
|
|
45932
46528
|
caption: parsed.directives.caption
|
|
45933
46529
|
},
|
|
@@ -45937,7 +46533,7 @@ function resolveMap(parsed, data) {
|
|
|
45937
46533
|
// renderer's job (step 4) — the resolver only carries `tags` + `tagGroups`
|
|
45938
46534
|
// through; it never resolves a tag value to a palette color (#10).
|
|
45939
46535
|
directives: { ...parsed.directives },
|
|
45940
|
-
basemaps: { world: "
|
|
46536
|
+
basemaps: { world: "detail", subdivisions: [] },
|
|
45941
46537
|
regions: [],
|
|
45942
46538
|
pois: [],
|
|
45943
46539
|
edges: [],
|
|
@@ -45946,7 +46542,8 @@ function resolveMap(parsed, data) {
|
|
|
45946
46542
|
[-180, -85],
|
|
45947
46543
|
[180, 85]
|
|
45948
46544
|
],
|
|
45949
|
-
projection: "
|
|
46545
|
+
projection: "equirectangular",
|
|
46546
|
+
poiFrameContainers: [],
|
|
45950
46547
|
diagnostics,
|
|
45951
46548
|
error: parsed.error
|
|
45952
46549
|
};
|
|
@@ -45956,7 +46553,10 @@ function resolveMap(parsed, data) {
|
|
|
45956
46553
|
...[...countryIndex.values()].map((v) => v.name),
|
|
45957
46554
|
...[...usStateIndex.values()].map((v) => v.name)
|
|
45958
46555
|
];
|
|
45959
|
-
const
|
|
46556
|
+
const localeRaw = parsed.directives.locale?.toUpperCase();
|
|
46557
|
+
const localeCountry = localeRaw ? localeRaw.split("-")[0] : void 0;
|
|
46558
|
+
const localeSubdivision = localeRaw && /^[A-Z]{2}-/.test(localeRaw) ? localeRaw : void 0;
|
|
46559
|
+
const usScoped = localeCountry === "US" || parsed.regions.some((r) => {
|
|
45960
46560
|
const f = fold(r.name);
|
|
45961
46561
|
return usStateIndex.has(f) && !countryIndex.has(f);
|
|
45962
46562
|
}) || parsed.regions.some(
|
|
@@ -46001,12 +46601,12 @@ function resolveMap(parsed, data) {
|
|
|
46001
46601
|
chosen = { ...inState, layer: "us-state" };
|
|
46002
46602
|
} else {
|
|
46003
46603
|
chosen = { ...inCountry, layer: "country" };
|
|
46604
|
+
warn(
|
|
46605
|
+
r.lineNumber,
|
|
46606
|
+
`"${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}").`,
|
|
46607
|
+
"W_MAP_REGION_AMBIGUOUS"
|
|
46608
|
+
);
|
|
46004
46609
|
}
|
|
46005
|
-
warn(
|
|
46006
|
-
r.lineNumber,
|
|
46007
|
-
`"${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}").`,
|
|
46008
|
-
"W_MAP_REGION_AMBIGUOUS"
|
|
46009
|
-
);
|
|
46010
46610
|
} else if (inState) {
|
|
46011
46611
|
chosen = { ...inState, layer: "us-state" };
|
|
46012
46612
|
} else if (inCountry) {
|
|
@@ -46030,6 +46630,7 @@ function resolveMap(parsed, data) {
|
|
|
46030
46630
|
name: chosen.name,
|
|
46031
46631
|
layer: chosen.layer,
|
|
46032
46632
|
...r.value !== void 0 && { value: r.value },
|
|
46633
|
+
...r.color !== void 0 && { color: r.color },
|
|
46033
46634
|
tags: r.tags,
|
|
46034
46635
|
meta: r.meta,
|
|
46035
46636
|
lineNumber: r.lineNumber
|
|
@@ -46106,7 +46707,7 @@ function resolveMap(parsed, data) {
|
|
|
46106
46707
|
if (!scope)
|
|
46107
46708
|
warn(
|
|
46108
46709
|
line12,
|
|
46109
|
-
`"${name}" is ambiguous \u2014 resolved to the most-populous match.`,
|
|
46710
|
+
`"${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.`,
|
|
46110
46711
|
"W_MAP_AMBIGUOUS_NAME"
|
|
46111
46712
|
);
|
|
46112
46713
|
}
|
|
@@ -46119,17 +46720,21 @@ function resolveMap(parsed, data) {
|
|
|
46119
46720
|
return fold(pos.name);
|
|
46120
46721
|
};
|
|
46121
46722
|
const poiCountries = [];
|
|
46122
|
-
let
|
|
46723
|
+
let anyUsPoi = false;
|
|
46724
|
+
let anyNonNaPoi = false;
|
|
46123
46725
|
const noteCountry = (iso) => {
|
|
46124
46726
|
if (iso) {
|
|
46125
46727
|
poiCountries.push(iso);
|
|
46126
|
-
if (iso
|
|
46728
|
+
if (iso === "US") anyUsPoi = true;
|
|
46729
|
+
if (iso !== "US" && iso !== "CA" && iso !== "MX") anyNonNaPoi = true;
|
|
46127
46730
|
}
|
|
46128
46731
|
};
|
|
46129
46732
|
const deferred = [];
|
|
46130
46733
|
for (const p of parsed.pois) {
|
|
46131
46734
|
if (p.pos.kind === "coords") {
|
|
46132
|
-
if (
|
|
46735
|
+
if (looksUS(p.pos.lat, p.pos.lon)) anyUsPoi = true;
|
|
46736
|
+
else if (!looksNorthAmericaNeighbor(p.pos.lat, p.pos.lon))
|
|
46737
|
+
anyNonNaPoi = true;
|
|
46133
46738
|
addResolvedPoi(p.pos.lat, p.pos.lon, p);
|
|
46134
46739
|
continue;
|
|
46135
46740
|
}
|
|
@@ -46147,14 +46752,15 @@ function resolveMap(parsed, data) {
|
|
|
46147
46752
|
deferred.push(p);
|
|
46148
46753
|
}
|
|
46149
46754
|
}
|
|
46150
|
-
const inferredCountry =
|
|
46755
|
+
const inferredCountry = localeCountry ?? mostCommonCountry(regions, poiCountries) ?? void 0;
|
|
46756
|
+
const inferredScope = localeSubdivision ?? inferredCountry;
|
|
46151
46757
|
for (const p of deferred) {
|
|
46152
46758
|
if (p.pos.kind !== "name") continue;
|
|
46153
46759
|
const got = lookupName(
|
|
46154
46760
|
p.pos.name,
|
|
46155
46761
|
p.pos.scope,
|
|
46156
46762
|
p.lineNumber,
|
|
46157
|
-
|
|
46763
|
+
inferredScope,
|
|
46158
46764
|
true
|
|
46159
46765
|
);
|
|
46160
46766
|
if (got.kind === "ok") {
|
|
@@ -46171,6 +46777,7 @@ function resolveMap(parsed, data) {
|
|
|
46171
46777
|
lat,
|
|
46172
46778
|
lon,
|
|
46173
46779
|
...p.label !== void 0 && { label: p.label },
|
|
46780
|
+
...p.color !== void 0 && { color: p.color },
|
|
46174
46781
|
tags: p.tags,
|
|
46175
46782
|
meta: p.meta,
|
|
46176
46783
|
lineNumber: p.lineNumber
|
|
@@ -46223,7 +46830,8 @@ function resolveMap(parsed, data) {
|
|
|
46223
46830
|
const meta = sizeValue !== void 0 ? { value: sizeValue } : {};
|
|
46224
46831
|
if (pos.kind === "coords") {
|
|
46225
46832
|
const id = alias ? fold(alias) : `@${pos.lat},${pos.lon}`;
|
|
46226
|
-
if (
|
|
46833
|
+
if (looksUS(pos.lat, pos.lon)) anyUsPoi = true;
|
|
46834
|
+
else if (!looksNorthAmericaNeighbor(pos.lat, pos.lon)) anyNonNaPoi = true;
|
|
46227
46835
|
if (!registry.has(id)) {
|
|
46228
46836
|
registerPoi(
|
|
46229
46837
|
id,
|
|
@@ -46246,7 +46854,7 @@ function resolveMap(parsed, data) {
|
|
|
46246
46854
|
if (registry.has(f)) return f;
|
|
46247
46855
|
const aliased = declaredByName.get(f);
|
|
46248
46856
|
if (aliased) return aliased;
|
|
46249
|
-
const got = lookupName(pos.name, pos.scope, line12,
|
|
46857
|
+
const got = lookupName(pos.name, pos.scope, line12, inferredScope, true);
|
|
46250
46858
|
if (got.kind !== "ok") return null;
|
|
46251
46859
|
noteCountry(got.iso);
|
|
46252
46860
|
registerPoi(
|
|
@@ -46303,9 +46911,12 @@ function resolveMap(parsed, data) {
|
|
|
46303
46911
|
}
|
|
46304
46912
|
routes.push({ stopIds, legs, lineNumber: rt.lineNumber });
|
|
46305
46913
|
}
|
|
46914
|
+
const hasUsContent = usSubdivisionReferenced || anyUsPoi || localeCountry === "US";
|
|
46915
|
+
const usOriented = !anyNonNaPoi && !regions.some(
|
|
46916
|
+
(r) => r.layer === "country" && !["US", "CA", "MX"].includes(r.iso)
|
|
46917
|
+
) && hasUsContent;
|
|
46306
46918
|
const subdivisions = [];
|
|
46307
|
-
if (usSubdivisionReferenced ||
|
|
46308
|
-
subdivisions.push("us-states");
|
|
46919
|
+
if (usSubdivisionReferenced || usOriented) subdivisions.push("us-states");
|
|
46309
46920
|
const regionBoxes = [];
|
|
46310
46921
|
for (const ref of referencedRegionIds) {
|
|
46311
46922
|
const bb = featureBbox(data.usStates, ref.id);
|
|
@@ -46313,7 +46924,7 @@ function resolveMap(parsed, data) {
|
|
|
46313
46924
|
}
|
|
46314
46925
|
for (const r of regions) {
|
|
46315
46926
|
if (r.layer === "country") {
|
|
46316
|
-
const bb =
|
|
46927
|
+
const bb = featureBboxPrimary(data.worldCoarse, r.iso);
|
|
46317
46928
|
if (bb) regionBoxes.push(bb);
|
|
46318
46929
|
}
|
|
46319
46930
|
}
|
|
@@ -46323,23 +46934,56 @@ function resolveMap(parsed, data) {
|
|
|
46323
46934
|
[-180, -85],
|
|
46324
46935
|
[180, 85]
|
|
46325
46936
|
];
|
|
46326
|
-
|
|
46937
|
+
const basePad = regions.length > 0 ? REGION_PAD_FRACTION : PAD_FRACTION;
|
|
46938
|
+
let extent2 = unioned ? pad(unioned, basePad) : DEFAULT_EXTENT;
|
|
46939
|
+
const isPoiOnly = pois.length > 0 && regions.length === 0;
|
|
46940
|
+
const containerRegionIds = [];
|
|
46941
|
+
if (isPoiOnly) {
|
|
46942
|
+
const countries = decodeFeatures(data.worldDetail);
|
|
46943
|
+
const states = decodeFeatures(data.usStates);
|
|
46944
|
+
const seen = /* @__PURE__ */ new Set();
|
|
46945
|
+
const containerBoxes = [];
|
|
46946
|
+
for (const p of pois) {
|
|
46947
|
+
const { country, state } = regionAt([p.lon, p.lat], countries, states);
|
|
46948
|
+
const id = state?.iso ?? country?.iso;
|
|
46949
|
+
if (!id || seen.has(id)) continue;
|
|
46950
|
+
seen.add(id);
|
|
46951
|
+
containerRegionIds.push(id);
|
|
46952
|
+
const bb = state ? featureBbox(data.usStates, id) : featureBboxPrimary(data.worldCoarse, id);
|
|
46953
|
+
if (bb && !isWholeSphere(bb)) containerBoxes.push(bb);
|
|
46954
|
+
}
|
|
46955
|
+
const containerUnion = unionExtent(containerBoxes, points);
|
|
46956
|
+
if (containerUnion) extent2 = pad(containerUnion, PAD_FRACTION);
|
|
46957
|
+
}
|
|
46958
|
+
if (isPoiOnly) {
|
|
46959
|
+
const cx = (extent2[0][0] + extent2[1][0]) / 2;
|
|
46960
|
+
const cy = (extent2[0][1] + extent2[1][1]) / 2;
|
|
46961
|
+
const lon = extent2[1][0] - extent2[0][0];
|
|
46962
|
+
const lat = extent2[1][1] - extent2[0][1];
|
|
46963
|
+
const longer = Math.max(lon, lat);
|
|
46964
|
+
if (longer > 0 && longer < POI_ZOOM_FLOOR_DEG) {
|
|
46965
|
+
const k = POI_ZOOM_FLOOR_DEG / longer;
|
|
46966
|
+
const halfLon = lon * k / 2;
|
|
46967
|
+
const halfLat = lat * k / 2;
|
|
46968
|
+
extent2 = [
|
|
46969
|
+
[cx - halfLon, cy - halfLat],
|
|
46970
|
+
[cx + halfLon, cy + halfLat]
|
|
46971
|
+
];
|
|
46972
|
+
}
|
|
46973
|
+
}
|
|
46327
46974
|
const lonSpan = extent2[1][0] - extent2[0][0];
|
|
46328
46975
|
const latSpan = extent2[1][1] - extent2[0][1];
|
|
46329
46976
|
const span = Math.max(lonSpan, latSpan);
|
|
46330
|
-
const
|
|
46977
|
+
const maxAbsLat = Math.max(Math.abs(extent2[0][1]), Math.abs(extent2[1][1]));
|
|
46331
46978
|
let projection;
|
|
46332
|
-
|
|
46333
|
-
|
|
46334
|
-
|
|
46335
|
-
} else if (usDominant) {
|
|
46979
|
+
if (isPoiOnly && usOriented && lonSpan < US_NATIONAL_LON_SPAN) {
|
|
46980
|
+
projection = "mercator";
|
|
46981
|
+
} else if (usOriented) {
|
|
46336
46982
|
projection = "albers-usa";
|
|
46337
|
-
} else if (span > WORLD_SPAN) {
|
|
46983
|
+
} else if (span > WORLD_SPAN || maxAbsLat > MERCATOR_MAX_LAT) {
|
|
46338
46984
|
projection = "equirectangular";
|
|
46339
|
-
} else if (span < MERCATOR_MAX_SPAN) {
|
|
46340
|
-
projection = "mercator";
|
|
46341
46985
|
} else {
|
|
46342
|
-
projection = "
|
|
46986
|
+
projection = "mercator";
|
|
46343
46987
|
}
|
|
46344
46988
|
if (lonSpan >= 180) {
|
|
46345
46989
|
extent2 = [
|
|
@@ -46352,11 +46996,20 @@ function resolveMap(parsed, data) {
|
|
|
46352
46996
|
result.edges = edges;
|
|
46353
46997
|
result.routes = routes;
|
|
46354
46998
|
result.basemaps = {
|
|
46355
|
-
|
|
46999
|
+
// Tier is intentionally pinned to detail (50m) at ALL scales. Diagrammo maps
|
|
47000
|
+
// are presentational (palette tints, relief hachures, POI hubs), not
|
|
47001
|
+
// survey-grade — recognizability > generalization: 110m coarse drops the
|
|
47002
|
+
// Italian boot to a stump at world scale. `WORLD_SPAN` lives on only for the
|
|
47003
|
+
// projection decision (the `usOriented`/`span > WORLD_SPAN` chain above); it
|
|
47004
|
+
// no longer gates basemap resolution.
|
|
47005
|
+
// `worldCoarse` is still loaded — it's the authoritative name/bbox index
|
|
47006
|
+
// (featureIndex, featureBboxPrimary), not dead code.
|
|
47007
|
+
world: "detail",
|
|
46356
47008
|
subdivisions
|
|
46357
47009
|
};
|
|
46358
47010
|
result.extent = extent2;
|
|
46359
47011
|
result.projection = projection;
|
|
47012
|
+
result.poiFrameContainers = containerRegionIds;
|
|
46360
47013
|
result.error = parsed.error ?? firstError(diagnostics);
|
|
46361
47014
|
return result;
|
|
46362
47015
|
}
|
|
@@ -46393,17 +47046,20 @@ function firstError(diags) {
|
|
|
46393
47046
|
const e = diags.find((d) => d.severity === "error");
|
|
46394
47047
|
return e ? formatDgmoError(e) : null;
|
|
46395
47048
|
}
|
|
46396
|
-
var WORLD_SPAN,
|
|
47049
|
+
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;
|
|
46397
47050
|
var init_resolver2 = __esm({
|
|
46398
47051
|
"src/map/resolver.ts"() {
|
|
46399
47052
|
"use strict";
|
|
46400
47053
|
init_diagnostics();
|
|
46401
47054
|
init_geo();
|
|
46402
47055
|
WORLD_SPAN = 90;
|
|
46403
|
-
|
|
47056
|
+
MERCATOR_MAX_LAT = 80;
|
|
46404
47057
|
PAD_FRACTION = 0.05;
|
|
47058
|
+
REGION_PAD_FRACTION = 0.12;
|
|
46405
47059
|
WORLD_LAT_SOUTH = -58;
|
|
46406
47060
|
WORLD_LAT_NORTH = 78;
|
|
47061
|
+
POI_ZOOM_FLOOR_DEG = 7;
|
|
47062
|
+
US_NATIONAL_LON_SPAN = 48;
|
|
46407
47063
|
REGION_ALIASES = {
|
|
46408
47064
|
// Common everyday names → the Natural-Earth display name actually shipped.
|
|
46409
47065
|
"united states": "united states of america",
|
|
@@ -46481,112 +47137,269 @@ var init_resolver2 = __esm({
|
|
|
46481
47137
|
}
|
|
46482
47138
|
});
|
|
46483
47139
|
|
|
46484
|
-
// src/map/
|
|
46485
|
-
|
|
46486
|
-
|
|
46487
|
-
|
|
47140
|
+
// src/map/colorize.ts
|
|
47141
|
+
function assignColors(isos, adjacency) {
|
|
47142
|
+
const sorted = [...isos].sort();
|
|
47143
|
+
const byIso = /* @__PURE__ */ new Map();
|
|
47144
|
+
let maxIndex = -1;
|
|
47145
|
+
for (const iso of sorted) {
|
|
47146
|
+
const taken = /* @__PURE__ */ new Set();
|
|
47147
|
+
for (const n of adjacency.get(iso) ?? []) {
|
|
47148
|
+
const c = byIso.get(n);
|
|
47149
|
+
if (c !== void 0) taken.add(c);
|
|
47150
|
+
}
|
|
47151
|
+
let h = 0;
|
|
47152
|
+
while (taken.has(h)) h++;
|
|
47153
|
+
byIso.set(iso, h);
|
|
47154
|
+
if (h > maxIndex) maxIndex = h;
|
|
47155
|
+
}
|
|
47156
|
+
return { byIso, huesNeeded: maxIndex + 1 };
|
|
47157
|
+
}
|
|
47158
|
+
var init_colorize = __esm({
|
|
47159
|
+
"src/map/colorize.ts"() {
|
|
47160
|
+
"use strict";
|
|
47161
|
+
}
|
|
46488
47162
|
});
|
|
46489
|
-
|
|
46490
|
-
|
|
46491
|
-
|
|
46492
|
-
|
|
46493
|
-
|
|
46494
|
-
|
|
46495
|
-
return
|
|
46496
|
-
}
|
|
46497
|
-
|
|
46498
|
-
|
|
46499
|
-
|
|
46500
|
-
|
|
46501
|
-
|
|
46502
|
-
|
|
46503
|
-
|
|
46504
|
-
|
|
46505
|
-
|
|
46506
|
-
|
|
47163
|
+
|
|
47164
|
+
// src/map/context-labels.ts
|
|
47165
|
+
function tierBand(maxSpanDeg) {
|
|
47166
|
+
if (maxSpanDeg >= 90) return "world";
|
|
47167
|
+
if (maxSpanDeg >= 20) return "continental";
|
|
47168
|
+
if (maxSpanDeg >= 5) return "regional";
|
|
47169
|
+
return "local";
|
|
47170
|
+
}
|
|
47171
|
+
function labelBudget(width, height, band) {
|
|
47172
|
+
const bandCap = {
|
|
47173
|
+
world: 6,
|
|
47174
|
+
continental: 5,
|
|
47175
|
+
regional: 4,
|
|
47176
|
+
local: 3
|
|
47177
|
+
};
|
|
47178
|
+
const area2 = Math.floor(Math.sqrt(Math.max(0, width * height)) / 150);
|
|
47179
|
+
return Math.max(0, Math.min(area2, bandCap[band]));
|
|
47180
|
+
}
|
|
47181
|
+
function waterEligible(tier, kind, band) {
|
|
47182
|
+
switch (band) {
|
|
47183
|
+
case "world":
|
|
47184
|
+
return tier <= 1 && (kind === "ocean" || kind === "sea");
|
|
47185
|
+
case "continental":
|
|
47186
|
+
return tier <= 2;
|
|
47187
|
+
case "regional":
|
|
47188
|
+
return tier <= 3;
|
|
47189
|
+
case "local":
|
|
47190
|
+
return tier <= 4;
|
|
47191
|
+
}
|
|
47192
|
+
}
|
|
47193
|
+
function insideViewport(p, width, height) {
|
|
47194
|
+
return !!p && Number.isFinite(p[0]) && Number.isFinite(p[1]) && p[0] >= 0 && p[0] <= width && p[1] >= 0 && p[1] <= height;
|
|
47195
|
+
}
|
|
47196
|
+
function labelWidth(text, letterSpacing) {
|
|
47197
|
+
const spacing = letterSpacing > 0 ? Math.max(0, text.length - 1) * letterSpacing : 0;
|
|
47198
|
+
return measureLegendText(text, FONT) + spacing + 2 * PADX;
|
|
47199
|
+
}
|
|
47200
|
+
function wrapLabel2(text, letterSpacing) {
|
|
47201
|
+
const words = text.split(/\s+/).filter(Boolean);
|
|
47202
|
+
if (words.length <= 1) return [text];
|
|
47203
|
+
const maxLines = words.length >= 4 ? 3 : 2;
|
|
47204
|
+
const n = words.length;
|
|
47205
|
+
let best = null;
|
|
47206
|
+
for (let mask = 0; mask < 1 << n - 1; mask++) {
|
|
47207
|
+
const lines = [];
|
|
47208
|
+
let cur = [words[0]];
|
|
47209
|
+
for (let i = 1; i < n; i++) {
|
|
47210
|
+
if (mask & 1 << i - 1) {
|
|
47211
|
+
lines.push(cur.join(" "));
|
|
47212
|
+
cur = [words[i]];
|
|
47213
|
+
} else cur.push(words[i]);
|
|
46507
47214
|
}
|
|
47215
|
+
lines.push(cur.join(" "));
|
|
47216
|
+
if (lines.length > maxLines) continue;
|
|
47217
|
+
const cost = Math.round(
|
|
47218
|
+
Math.max(...lines.map((l) => labelWidth(l, letterSpacing)))
|
|
47219
|
+
);
|
|
47220
|
+
const head = labelWidth(lines[0], letterSpacing);
|
|
47221
|
+
if (!best || cost < best.cost || cost === best.cost && lines.length < best.lines.length || cost === best.cost && lines.length === best.lines.length && head > best.head)
|
|
47222
|
+
best = { lines, cost, head };
|
|
46508
47223
|
}
|
|
46509
|
-
|
|
46510
|
-
`map data assets not found near ${baseDir} (looked in ${CANDIDATE_DIRS.join(", ")}). Run \`pnpm build:map-data\` and \`pnpm build\`.`
|
|
46511
|
-
);
|
|
47224
|
+
return best?.lines ?? [text];
|
|
46512
47225
|
}
|
|
46513
|
-
function
|
|
46514
|
-
const
|
|
46515
|
-
|
|
46516
|
-
|
|
46517
|
-
}
|
|
46518
|
-
return data;
|
|
47226
|
+
function rectAround(cx, cy, lines, letterSpacing) {
|
|
47227
|
+
const w = Math.max(...lines.map((l) => labelWidth(l, letterSpacing)));
|
|
47228
|
+
const h = (lines.length - 1) * LINE_HEIGHT + FONT + 2 * PADY;
|
|
47229
|
+
return { x: cx - w / 2, y: cy - h / 2, w, h };
|
|
46519
47230
|
}
|
|
46520
|
-
function
|
|
46521
|
-
|
|
46522
|
-
const url = import_meta.url;
|
|
46523
|
-
if (url) return nb.dirname(nb.fileURLToPath(url));
|
|
46524
|
-
} catch {
|
|
46525
|
-
}
|
|
46526
|
-
if (typeof __dirname !== "undefined") return __dirname;
|
|
46527
|
-
return process.cwd();
|
|
47231
|
+
function rectFits(r, width, height) {
|
|
47232
|
+
return r.x >= 0 && r.y >= 0 && r.x + r.w <= width && r.y + r.h <= height;
|
|
46528
47233
|
}
|
|
46529
|
-
function
|
|
46530
|
-
|
|
46531
|
-
|
|
46532
|
-
|
|
46533
|
-
|
|
46534
|
-
|
|
46535
|
-
|
|
46536
|
-
|
|
46537
|
-
|
|
46538
|
-
|
|
46539
|
-
|
|
46540
|
-
|
|
46541
|
-
|
|
46542
|
-
|
|
46543
|
-
|
|
46544
|
-
|
|
46545
|
-
|
|
46546
|
-
|
|
46547
|
-
|
|
46548
|
-
|
|
46549
|
-
|
|
46550
|
-
|
|
46551
|
-
|
|
46552
|
-
|
|
46553
|
-
|
|
46554
|
-
|
|
46555
|
-
|
|
46556
|
-
|
|
46557
|
-
|
|
46558
|
-
|
|
46559
|
-
|
|
46560
|
-
|
|
46561
|
-
|
|
47234
|
+
function overlapsPadded(a, b, pad2) {
|
|
47235
|
+
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;
|
|
47236
|
+
}
|
|
47237
|
+
function placeContextLabels(args) {
|
|
47238
|
+
const {
|
|
47239
|
+
projection,
|
|
47240
|
+
dLonSpan,
|
|
47241
|
+
dLatSpan,
|
|
47242
|
+
width,
|
|
47243
|
+
height,
|
|
47244
|
+
waterBodies,
|
|
47245
|
+
countries,
|
|
47246
|
+
palette,
|
|
47247
|
+
project,
|
|
47248
|
+
collides,
|
|
47249
|
+
overLand
|
|
47250
|
+
} = args;
|
|
47251
|
+
void projection;
|
|
47252
|
+
const band = tierBand(Math.max(dLonSpan, dLatSpan));
|
|
47253
|
+
const budget = labelBudget(width, height, band);
|
|
47254
|
+
if (budget <= 0) return [];
|
|
47255
|
+
const waterColor = mix(palette.colors.blue, palette.textMuted, 50);
|
|
47256
|
+
const countryColor = palette.textMuted;
|
|
47257
|
+
const haloColor = palette.bg;
|
|
47258
|
+
const candidates = [];
|
|
47259
|
+
const center = [width / 2, height / 2];
|
|
47260
|
+
for (const e of waterBodies?.entries ?? []) {
|
|
47261
|
+
const [lat, lon, name, tier, kind, alt] = e;
|
|
47262
|
+
if (!waterEligible(tier, kind, band)) continue;
|
|
47263
|
+
const wlines = wrapLabel2(name, WATER_LETTER_SPACING);
|
|
47264
|
+
const anchorsLngLat = [[lon, lat]];
|
|
47265
|
+
for (const a of alt ?? []) anchorsLngLat.push([a[1], a[0]]);
|
|
47266
|
+
let best = null;
|
|
47267
|
+
let bestD = Infinity;
|
|
47268
|
+
let nearestProj = null;
|
|
47269
|
+
let nearestProjD = Infinity;
|
|
47270
|
+
for (const [aLon, aLat] of anchorsLngLat) {
|
|
47271
|
+
const p = project(aLon, aLat);
|
|
47272
|
+
if (!p || !Number.isFinite(p[0]) || !Number.isFinite(p[1])) continue;
|
|
47273
|
+
const d = (p[0] - center[0]) ** 2 + (p[1] - center[1]) ** 2;
|
|
47274
|
+
if (d < nearestProjD) {
|
|
47275
|
+
nearestProjD = d;
|
|
47276
|
+
nearestProj = p;
|
|
47277
|
+
}
|
|
47278
|
+
if (!insideViewport(p, width, height)) continue;
|
|
47279
|
+
if (d < bestD) {
|
|
47280
|
+
bestD = d;
|
|
47281
|
+
best = p;
|
|
47282
|
+
}
|
|
47283
|
+
}
|
|
47284
|
+
if (!best && tier === 0 && nearestProj) {
|
|
47285
|
+
const overX = Math.max(0, -nearestProj[0], nearestProj[0] - width);
|
|
47286
|
+
const overY = Math.max(0, -nearestProj[1], nearestProj[1] - height);
|
|
47287
|
+
if (overX <= width * EDGE_CLAMP_OVERSHOOT && overY <= height * EDGE_CLAMP_OVERSHOOT) {
|
|
47288
|
+
const halfW = Math.max(...wlines.map((l) => labelWidth(l, WATER_LETTER_SPACING))) / 2;
|
|
47289
|
+
const halfH = ((wlines.length - 1) * LINE_HEIGHT + FONT + 2 * PADY) / 2;
|
|
47290
|
+
const m = EDGE_CLAMP_MARGIN;
|
|
47291
|
+
best = [
|
|
47292
|
+
Math.min(Math.max(nearestProj[0], halfW + m), width - halfW - m),
|
|
47293
|
+
Math.min(Math.max(nearestProj[1], halfH + m), height - halfH - m)
|
|
47294
|
+
];
|
|
47295
|
+
}
|
|
47296
|
+
}
|
|
47297
|
+
if (!best) continue;
|
|
47298
|
+
candidates.push({
|
|
47299
|
+
text: name,
|
|
47300
|
+
lines: wlines,
|
|
47301
|
+
cx: best[0],
|
|
47302
|
+
cy: best[1],
|
|
47303
|
+
italic: true,
|
|
47304
|
+
letterSpacing: WATER_LETTER_SPACING,
|
|
47305
|
+
color: waterColor,
|
|
47306
|
+
// Water before any country (×1000), then by tier, then kind, then name.
|
|
47307
|
+
sort: tier * 10 + KIND_ORDER[kind]
|
|
46562
47308
|
});
|
|
46563
|
-
}
|
|
46564
|
-
|
|
46565
|
-
|
|
46566
|
-
|
|
46567
|
-
|
|
47309
|
+
}
|
|
47310
|
+
const ranked = countries.map((c) => {
|
|
47311
|
+
const [x0, y0, x1, y1] = c.bbox;
|
|
47312
|
+
const w = x1 - x0;
|
|
47313
|
+
const h = y1 - y0;
|
|
47314
|
+
return { c, w, h, area: w * h };
|
|
47315
|
+
}).filter((r) => Number.isFinite(r.area) && r.area > 0).sort((a, b) => b.area - a.area);
|
|
47316
|
+
let ci = 0;
|
|
47317
|
+
for (const r of ranked) {
|
|
47318
|
+
const { c, w, h } = r;
|
|
47319
|
+
if (w > width * 0.66 || h > height * 0.66) continue;
|
|
47320
|
+
if (!insideViewport(c.anchor, width, height)) continue;
|
|
47321
|
+
const text = c.name;
|
|
47322
|
+
const tw = labelWidth(text, 0);
|
|
47323
|
+
if (tw > w || FONT + 2 * PADY > h) continue;
|
|
47324
|
+
candidates.push({
|
|
47325
|
+
text,
|
|
47326
|
+
lines: [text],
|
|
47327
|
+
cx: c.anchor[0],
|
|
47328
|
+
cy: c.anchor[1],
|
|
47329
|
+
italic: false,
|
|
47330
|
+
letterSpacing: 0,
|
|
47331
|
+
color: countryColor,
|
|
47332
|
+
// Always after every water body (+1e6); larger area = earlier.
|
|
47333
|
+
sort: 1e6 + ci++
|
|
47334
|
+
});
|
|
47335
|
+
}
|
|
47336
|
+
candidates.sort((a, b) => a.sort - b.sort);
|
|
47337
|
+
const placed = [];
|
|
47338
|
+
const placedRects = [];
|
|
47339
|
+
for (const cand of candidates) {
|
|
47340
|
+
if (placed.length >= budget) break;
|
|
47341
|
+
const rect = rectAround(cand.cx, cand.cy, cand.lines, cand.letterSpacing);
|
|
47342
|
+
if (!rectFits(rect, width, height)) continue;
|
|
47343
|
+
if (cand.italic && overLand) {
|
|
47344
|
+
const inset = 2;
|
|
47345
|
+
const top = cand.cy - (cand.lines.length - 1) / 2 * LINE_HEIGHT;
|
|
47346
|
+
const touchesLand = cand.lines.some((line12, li) => {
|
|
47347
|
+
const lw = labelWidth(line12, cand.letterSpacing);
|
|
47348
|
+
const x0 = cand.cx - lw / 2 + inset;
|
|
47349
|
+
const x1 = cand.cx + lw / 2 - inset;
|
|
47350
|
+
const xs = [x0, (x0 + cand.cx) / 2, cand.cx, (cand.cx + x1) / 2, x1];
|
|
47351
|
+
const base = top + li * LINE_HEIGHT;
|
|
47352
|
+
return [base, base - FONT * 0.4, base - FONT * 0.8].some(
|
|
47353
|
+
(y) => xs.some((x) => overLand(x, y))
|
|
47354
|
+
);
|
|
47355
|
+
});
|
|
47356
|
+
if (touchesLand) continue;
|
|
47357
|
+
}
|
|
47358
|
+
if (collides(rect)) continue;
|
|
47359
|
+
if (placedRects.some((r) => overlapsPadded(rect, r, CONTEXT_PAD))) continue;
|
|
47360
|
+
placedRects.push(rect);
|
|
47361
|
+
placed.push({
|
|
47362
|
+
x: cand.cx,
|
|
47363
|
+
y: cand.cy,
|
|
47364
|
+
text: cand.text,
|
|
47365
|
+
anchor: "middle",
|
|
47366
|
+
color: cand.color,
|
|
47367
|
+
// No halo: the bg-coloured outline reads as a ghost box behind the text
|
|
47368
|
+
// over the tinted water/land. Context labels are muted enough to sit
|
|
47369
|
+
// cleanly on the basemap without one.
|
|
47370
|
+
halo: false,
|
|
47371
|
+
haloColor,
|
|
47372
|
+
italic: cand.italic,
|
|
47373
|
+
letterSpacing: cand.letterSpacing,
|
|
47374
|
+
...cand.lines.length > 1 ? { lines: cand.lines } : {},
|
|
47375
|
+
lineNumber: 0
|
|
47376
|
+
});
|
|
47377
|
+
}
|
|
47378
|
+
return placed;
|
|
46568
47379
|
}
|
|
46569
|
-
var
|
|
46570
|
-
var
|
|
46571
|
-
"src/map/
|
|
47380
|
+
var FONT, LINE_HEIGHT, PADX, PADY, WATER_LETTER_SPACING, CONTEXT_PAD, EDGE_CLAMP_MARGIN, EDGE_CLAMP_OVERSHOOT, KIND_ORDER;
|
|
47381
|
+
var init_context_labels = __esm({
|
|
47382
|
+
"src/map/context-labels.ts"() {
|
|
46572
47383
|
"use strict";
|
|
46573
|
-
|
|
46574
|
-
|
|
46575
|
-
|
|
46576
|
-
|
|
46577
|
-
|
|
46578
|
-
|
|
46579
|
-
|
|
46580
|
-
|
|
46581
|
-
|
|
46582
|
-
|
|
47384
|
+
init_color_utils();
|
|
47385
|
+
init_legend_constants();
|
|
47386
|
+
FONT = 11;
|
|
47387
|
+
LINE_HEIGHT = FONT + 2;
|
|
47388
|
+
PADX = 4;
|
|
47389
|
+
PADY = 3;
|
|
47390
|
+
WATER_LETTER_SPACING = 1.5;
|
|
47391
|
+
CONTEXT_PAD = 4;
|
|
47392
|
+
EDGE_CLAMP_MARGIN = 8;
|
|
47393
|
+
EDGE_CLAMP_OVERSHOOT = 0.35;
|
|
47394
|
+
KIND_ORDER = {
|
|
47395
|
+
ocean: 0,
|
|
47396
|
+
sea: 1,
|
|
47397
|
+
gulf: 2,
|
|
47398
|
+
bay: 3,
|
|
47399
|
+
strait: 4,
|
|
47400
|
+
channel: 5,
|
|
47401
|
+
sound: 6
|
|
46583
47402
|
};
|
|
46584
|
-
CANDIDATE_DIRS = [
|
|
46585
|
-
"./data",
|
|
46586
|
-
"./map-data",
|
|
46587
|
-
"../map-data",
|
|
46588
|
-
"../src/map/data"
|
|
46589
|
-
];
|
|
46590
47403
|
}
|
|
46591
47404
|
});
|
|
46592
47405
|
|
|
@@ -46595,12 +47408,34 @@ function geomObject2(topo) {
|
|
|
46595
47408
|
const key = Object.keys(topo.objects)[0];
|
|
46596
47409
|
return topo.objects[key];
|
|
46597
47410
|
}
|
|
47411
|
+
function mergeFeatures(a, b) {
|
|
47412
|
+
const polysOf = (f) => {
|
|
47413
|
+
const g = f.geometry;
|
|
47414
|
+
if (!g) return null;
|
|
47415
|
+
if (g.type === "Polygon") return [g.coordinates];
|
|
47416
|
+
if (g.type === "MultiPolygon") return g.coordinates;
|
|
47417
|
+
return null;
|
|
47418
|
+
};
|
|
47419
|
+
const pa = polysOf(a);
|
|
47420
|
+
const pb = polysOf(b);
|
|
47421
|
+
if (!pa || !pb) return a;
|
|
47422
|
+
return {
|
|
47423
|
+
...a,
|
|
47424
|
+
geometry: { type: "MultiPolygon", coordinates: [...pa, ...pb] }
|
|
47425
|
+
};
|
|
47426
|
+
}
|
|
46598
47427
|
function decodeLayer(topo) {
|
|
47428
|
+
const cached = decodeCache.get(topo);
|
|
47429
|
+
if (cached) return cached;
|
|
46599
47430
|
const out = /* @__PURE__ */ new Map();
|
|
46600
47431
|
for (const g of geomObject2(topo).geometries) {
|
|
46601
47432
|
const f = (0, import_topojson_client2.feature)(topo, g);
|
|
46602
|
-
|
|
47433
|
+
if (!f.geometry) continue;
|
|
47434
|
+
const tagged = { ...f, id: g.id };
|
|
47435
|
+
const existing = out.get(g.id);
|
|
47436
|
+
out.set(g.id, existing ? mergeFeatures(existing, tagged) : tagged);
|
|
46603
47437
|
}
|
|
47438
|
+
decodeCache.set(topo, out);
|
|
46604
47439
|
return out;
|
|
46605
47440
|
}
|
|
46606
47441
|
function projectionFor(family) {
|
|
@@ -46609,38 +47444,35 @@ function projectionFor(family) {
|
|
|
46609
47444
|
return usConusProjection();
|
|
46610
47445
|
case "mercator":
|
|
46611
47446
|
return (0, import_d3_geo2.geoMercator)();
|
|
47447
|
+
case "equal-earth":
|
|
47448
|
+
return (0, import_d3_geo2.geoEqualEarth)();
|
|
47449
|
+
case "equirectangular":
|
|
47450
|
+
return (0, import_d3_geo2.geoEquirectangular)();
|
|
46612
47451
|
case "natural-earth":
|
|
46613
47452
|
return (0, import_d3_geo2.geoNaturalEarth1)();
|
|
46614
|
-
case "equirectangular":
|
|
46615
47453
|
default:
|
|
46616
47454
|
return (0, import_d3_geo2.geoEquirectangular)();
|
|
46617
47455
|
}
|
|
46618
47456
|
}
|
|
46619
|
-
function mapBackgroundColor(palette, isDark = false,
|
|
46620
|
-
|
|
46621
|
-
|
|
46622
|
-
|
|
46623
|
-
|
|
46624
|
-
|
|
46625
|
-
);
|
|
46626
|
-
return mix(palette.colors.blue, palette.bg, WATER_TINT);
|
|
47457
|
+
function mapBackgroundColor(palette, isDark = false, _dataActive = false) {
|
|
47458
|
+
return mix(
|
|
47459
|
+
palette.colors.blue,
|
|
47460
|
+
palette.bg,
|
|
47461
|
+
isDark ? WATER_TINT_DARK : WATER_TINT_LIGHT
|
|
47462
|
+
);
|
|
46627
47463
|
}
|
|
46628
|
-
function mapNeutralLandColor(palette, isDark,
|
|
46629
|
-
if (dataActive)
|
|
46630
|
-
return isDark ? mix(palette.colors.gray, palette.bg, MUTED_LAND_DARK) : palette.bg;
|
|
47464
|
+
function mapNeutralLandColor(palette, isDark, _dataActive = false) {
|
|
46631
47465
|
return mix(
|
|
46632
47466
|
palette.colors.green,
|
|
46633
47467
|
palette.bg,
|
|
46634
47468
|
isDark ? LAND_TINT_DARK : LAND_TINT_LIGHT
|
|
46635
47469
|
);
|
|
46636
47470
|
}
|
|
46637
|
-
function
|
|
46638
|
-
const { palette, isDark } = opts;
|
|
46639
|
-
const { width, height } = size;
|
|
47471
|
+
function buildMapProjection(resolved, data) {
|
|
46640
47472
|
const wantsUsStates = resolved.basemaps.subdivisions.includes("us-states");
|
|
46641
|
-
const usCrisp = resolved.projection === "albers-usa" && wantsUsStates && !!data.naLand;
|
|
47473
|
+
const usCrisp = (resolved.projection === "albers-usa" || resolved.projection === "mercator") && wantsUsStates && !!data.naLand;
|
|
46642
47474
|
const worldTopo = usCrisp ? data.worldDetail : resolved.basemaps.world === "detail" ? data.worldDetail : data.worldCoarse;
|
|
46643
|
-
const worldLayer = decodeLayer(worldTopo);
|
|
47475
|
+
const worldLayer = new Map(decodeLayer(worldTopo));
|
|
46644
47476
|
if (usCrisp && data.naLand) {
|
|
46645
47477
|
const [nbW, nbS, nbE, nbN] = [-140, 10, -52, 66];
|
|
46646
47478
|
const crisp = decodeLayer(data.naLand);
|
|
@@ -46649,17 +47481,110 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46649
47481
|
if (!base) continue;
|
|
46650
47482
|
const [[bw, bs], [be, bn]] = (0, import_d3_geo2.geoBounds)(base);
|
|
46651
47483
|
if (bw >= nbW && be <= nbE && bs >= nbS && bn <= nbN)
|
|
46652
|
-
worldLayer.set(iso, cf);
|
|
47484
|
+
worldLayer.set(iso, { ...cf, properties: base.properties });
|
|
46653
47485
|
}
|
|
46654
47486
|
}
|
|
46655
47487
|
const usLayer = wantsUsStates ? decodeLayer(data.usStates) : null;
|
|
47488
|
+
const extentOutline = () => {
|
|
47489
|
+
const [[w, s], [e, n]] = resolved.extent;
|
|
47490
|
+
const N = 16;
|
|
47491
|
+
const coords = [];
|
|
47492
|
+
for (let i = 0; i <= N; i++) {
|
|
47493
|
+
const t = i / N;
|
|
47494
|
+
const lon = w + (e - w) * t;
|
|
47495
|
+
const lat = s + (n - s) * t;
|
|
47496
|
+
coords.push([lon, s], [lon, n], [w, lat], [e, lat]);
|
|
47497
|
+
}
|
|
47498
|
+
return {
|
|
47499
|
+
type: "Feature",
|
|
47500
|
+
properties: {},
|
|
47501
|
+
geometry: { type: "MultiPoint", coordinates: coords }
|
|
47502
|
+
};
|
|
47503
|
+
};
|
|
47504
|
+
let fitFeatures;
|
|
47505
|
+
if (resolved.projection === "albers-usa" && usLayer) {
|
|
47506
|
+
fitFeatures = [...usLayer.entries()].filter(([iso]) => !US_NON_CONUS.has(iso)).map(([, f]) => f);
|
|
47507
|
+
const neighborPoints = resolved.pois.filter((p) => !inAlaska(p.lon, p.lat) && !inHawaii(p.lon, p.lat)).map((p) => [p.lon, p.lat]);
|
|
47508
|
+
if (neighborPoints.length > 0) {
|
|
47509
|
+
fitFeatures.push({
|
|
47510
|
+
type: "Feature",
|
|
47511
|
+
properties: {},
|
|
47512
|
+
geometry: { type: "MultiPoint", coordinates: neighborPoints }
|
|
47513
|
+
});
|
|
47514
|
+
}
|
|
47515
|
+
for (const r of resolved.regions) {
|
|
47516
|
+
if (r.layer === "country" && (r.iso === "CA" || r.iso === "MX")) {
|
|
47517
|
+
const cf = worldLayer.get(r.iso);
|
|
47518
|
+
if (cf) fitFeatures.push(cf);
|
|
47519
|
+
}
|
|
47520
|
+
}
|
|
47521
|
+
} else {
|
|
47522
|
+
fitFeatures = [extentOutline()];
|
|
47523
|
+
}
|
|
47524
|
+
const fitTarget = { type: "FeatureCollection", features: fitFeatures };
|
|
47525
|
+
const projection = projectionFor(resolved.projection);
|
|
47526
|
+
if (resolved.projection !== "albers-usa") {
|
|
47527
|
+
let centerLon = (resolved.extent[0][0] + resolved.extent[1][0]) / 2;
|
|
47528
|
+
if (centerLon > 180) centerLon -= 360;
|
|
47529
|
+
projection.rotate([-centerLon, 0]);
|
|
47530
|
+
}
|
|
47531
|
+
const fitGB = (0, import_d3_geo2.geoBounds)(fitTarget);
|
|
47532
|
+
const fitIsGlobal = fitGB[1][0] - fitGB[0][0] >= 270 || fitGB[1][1] - fitGB[0][1] >= 130;
|
|
47533
|
+
return {
|
|
47534
|
+
projection,
|
|
47535
|
+
fitTarget,
|
|
47536
|
+
fitIsGlobal,
|
|
47537
|
+
worldLayer,
|
|
47538
|
+
usLayer,
|
|
47539
|
+
usCrisp,
|
|
47540
|
+
wantsUsStates,
|
|
47541
|
+
worldTopo
|
|
47542
|
+
};
|
|
47543
|
+
}
|
|
47544
|
+
function parsePathRings(d) {
|
|
47545
|
+
const rings = [];
|
|
47546
|
+
let cur = [];
|
|
47547
|
+
const re = /([MLZ])([^MLZ]*)/g;
|
|
47548
|
+
let m;
|
|
47549
|
+
while (m = re.exec(d)) {
|
|
47550
|
+
if (m[1] === "Z") {
|
|
47551
|
+
if (cur.length) rings.push(cur);
|
|
47552
|
+
cur = [];
|
|
47553
|
+
continue;
|
|
47554
|
+
}
|
|
47555
|
+
if (m[1] === "M" && cur.length) {
|
|
47556
|
+
rings.push(cur);
|
|
47557
|
+
cur = [];
|
|
47558
|
+
}
|
|
47559
|
+
const nums = m[2].split(/[ ,]+/).map(Number);
|
|
47560
|
+
for (let i = 0; i + 1 < nums.length; i += 2) {
|
|
47561
|
+
const x = nums[i];
|
|
47562
|
+
const y = nums[i + 1];
|
|
47563
|
+
if (Number.isFinite(x) && Number.isFinite(y)) cur.push([x, y]);
|
|
47564
|
+
}
|
|
47565
|
+
}
|
|
47566
|
+
if (cur.length) rings.push(cur);
|
|
47567
|
+
return rings;
|
|
47568
|
+
}
|
|
47569
|
+
function layoutMap(resolved, data, size, opts) {
|
|
47570
|
+
const { palette, isDark } = opts;
|
|
47571
|
+
const { width, height } = size;
|
|
47572
|
+
const {
|
|
47573
|
+
projection,
|
|
47574
|
+
fitTarget,
|
|
47575
|
+
fitIsGlobal,
|
|
47576
|
+
worldLayer,
|
|
47577
|
+
usLayer,
|
|
47578
|
+
usCrisp,
|
|
47579
|
+
worldTopo
|
|
47580
|
+
} = buildMapProjection(resolved, data);
|
|
46656
47581
|
const usContext = usLayer !== null;
|
|
46657
47582
|
const regionStroke = isDark ? mix(palette.bg, palette.text, 78) : mix(palette.text, palette.bg, 78);
|
|
46658
47583
|
const values = resolved.regions.filter((r) => r.value !== void 0).map((r) => r.value);
|
|
46659
|
-
const
|
|
46660
|
-
const rampMin =
|
|
46661
|
-
const rampMax =
|
|
46662
|
-
const rampHue = palette.colors.red;
|
|
47584
|
+
const allNonNegative = values.length > 0 && values.every((v) => v >= 0);
|
|
47585
|
+
const rampMin = allNonNegative ? 0 : Math.min(...values);
|
|
47586
|
+
const rampMax = Math.max(...values);
|
|
47587
|
+
const rampHue = resolveColor(resolved.directives.regionMetricColor ?? "", palette) ?? palette.colors.red;
|
|
46663
47588
|
const hasRamp = values.length > 0;
|
|
46664
47589
|
const VALUE_NAME = hasRamp ? resolved.directives.regionMetric?.trim() || "Value" : null;
|
|
46665
47590
|
const matchColorGroup = (v) => {
|
|
@@ -46679,14 +47604,48 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46679
47604
|
activeGroup = VALUE_NAME ?? (resolved.tagGroups.length > 0 ? resolved.tagGroups[0].name : null);
|
|
46680
47605
|
}
|
|
46681
47606
|
const activeIsScore = VALUE_NAME !== null && activeGroup === VALUE_NAME;
|
|
46682
|
-
const mutedBasemap =
|
|
47607
|
+
const mutedBasemap = activeGroup !== null;
|
|
46683
47608
|
const neutralFill = mapNeutralLandColor(palette, isDark, mutedBasemap);
|
|
46684
47609
|
const water = mapBackgroundColor(palette, isDark, mutedBasemap);
|
|
47610
|
+
const lakeStroke = mix(regionStroke, water, 45);
|
|
46685
47611
|
const foreignFill = mix(
|
|
46686
47612
|
palette.colors.gray,
|
|
46687
47613
|
palette.bg,
|
|
46688
47614
|
mutedBasemap ? isDark ? MUTED_FOREIGN_DARK : MUTED_FOREIGN_LIGHT : isDark ? FOREIGN_TINT_DARK : FOREIGN_TINT_LIGHT
|
|
46689
47615
|
);
|
|
47616
|
+
const colorizeActive = resolved.directives.noColorize !== true && !hasRamp && resolved.tagGroups.length === 0;
|
|
47617
|
+
const colorByIso = /* @__PURE__ */ new Map();
|
|
47618
|
+
if (colorizeActive) {
|
|
47619
|
+
const adjacency = /* @__PURE__ */ new Map();
|
|
47620
|
+
const addEdges = (src) => {
|
|
47621
|
+
for (const [iso, ns] of src) {
|
|
47622
|
+
const cur = adjacency.get(iso);
|
|
47623
|
+
if (cur) cur.push(...ns);
|
|
47624
|
+
else adjacency.set(iso, [...ns]);
|
|
47625
|
+
}
|
|
47626
|
+
};
|
|
47627
|
+
addEdges(buildAdjacency(worldTopo));
|
|
47628
|
+
if (usLayer) {
|
|
47629
|
+
addEdges(buildAdjacency(data.usStates));
|
|
47630
|
+
for (const [country, states] of Object.entries(FOREIGN_BORDER)) {
|
|
47631
|
+
const cn = adjacency.get(country);
|
|
47632
|
+
if (!cn) continue;
|
|
47633
|
+
for (const st of states) {
|
|
47634
|
+
const sn = adjacency.get(st);
|
|
47635
|
+
if (!sn) continue;
|
|
47636
|
+
cn.push(st);
|
|
47637
|
+
sn.push(country);
|
|
47638
|
+
}
|
|
47639
|
+
}
|
|
47640
|
+
}
|
|
47641
|
+
const { byIso, huesNeeded } = assignColors(
|
|
47642
|
+
[...adjacency.keys()],
|
|
47643
|
+
adjacency
|
|
47644
|
+
);
|
|
47645
|
+
const tints = politicalTints(palette, huesNeeded, isDark);
|
|
47646
|
+
for (const [iso, idx] of byIso) colorByIso.set(iso, tints[idx]);
|
|
47647
|
+
}
|
|
47648
|
+
const colorizeStroke = (fill2) => mix(fill2, palette.text, 35);
|
|
46690
47649
|
const rampBase = isDark ? mix(palette.surface, palette.text, 28) : palette.bg;
|
|
46691
47650
|
const fillForValue = (s) => {
|
|
46692
47651
|
const t = rampMax > rampMin ? (s - rampMin) / (rampMax - rampMin) : 1;
|
|
@@ -46711,47 +47670,26 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46711
47670
|
isDark ? TAG_TINT_DARK : TAG_TINT_LIGHT
|
|
46712
47671
|
);
|
|
46713
47672
|
};
|
|
47673
|
+
const directFill = (name) => {
|
|
47674
|
+
const hex = name ? resolveColor(name, palette) : null;
|
|
47675
|
+
if (!hex) return null;
|
|
47676
|
+
return mix(hex, palette.bg, isDark ? TAG_TINT_DARK : TAG_TINT_LIGHT);
|
|
47677
|
+
};
|
|
46714
47678
|
const regionFill = (r) => {
|
|
47679
|
+
const direct = directFill(r.color);
|
|
47680
|
+
if (direct) return direct;
|
|
46715
47681
|
if (activeIsScore) {
|
|
46716
47682
|
return r.value !== void 0 ? fillForValue(r.value) : neutralFill;
|
|
46717
47683
|
}
|
|
47684
|
+
if (colorizeActive) return (r.iso && colorByIso.get(r.iso)) ?? neutralFill;
|
|
46718
47685
|
return tagFill(r.tags, activeGroup) ?? neutralFill;
|
|
46719
47686
|
};
|
|
46720
47687
|
const regionById = new Map(resolved.regions.map((r) => [r.iso, r]));
|
|
46721
|
-
const
|
|
46722
|
-
const [[w, s], [e, n]] = resolved.extent;
|
|
46723
|
-
const N = 16;
|
|
46724
|
-
const coords = [];
|
|
46725
|
-
for (let i = 0; i <= N; i++) {
|
|
46726
|
-
const t = i / N;
|
|
46727
|
-
const lon = w + (e - w) * t;
|
|
46728
|
-
const lat = s + (n - s) * t;
|
|
46729
|
-
coords.push([lon, s], [lon, n], [w, lat], [e, lat]);
|
|
46730
|
-
}
|
|
46731
|
-
return {
|
|
46732
|
-
type: "Feature",
|
|
46733
|
-
properties: {},
|
|
46734
|
-
geometry: { type: "MultiPoint", coordinates: coords }
|
|
46735
|
-
};
|
|
46736
|
-
};
|
|
46737
|
-
let fitFeatures;
|
|
46738
|
-
if (resolved.projection === "albers-usa" && usLayer) {
|
|
46739
|
-
fitFeatures = [...usLayer.entries()].filter(([iso]) => !US_NON_CONUS.has(iso)).map(([, f]) => f);
|
|
46740
|
-
} else {
|
|
46741
|
-
fitFeatures = [extentOutline()];
|
|
46742
|
-
}
|
|
46743
|
-
const fitTarget = { type: "FeatureCollection", features: fitFeatures };
|
|
46744
|
-
const projection = projectionFor(resolved.projection);
|
|
46745
|
-
if (resolved.projection !== "albers-usa") {
|
|
46746
|
-
let centerLon = (resolved.extent[0][0] + resolved.extent[1][0]) / 2;
|
|
46747
|
-
if (centerLon > 180) centerLon -= 360;
|
|
46748
|
-
projection.rotate([-centerLon, 0]);
|
|
46749
|
-
}
|
|
46750
|
-
const TITLE_GAP = 16;
|
|
47688
|
+
const TITLE_GAP2 = 16;
|
|
46751
47689
|
let topPad = FIT_PAD;
|
|
46752
47690
|
if (resolved.title && resolved.pois.length > 0) {
|
|
46753
47691
|
const bannerBottom = (resolved.subtitle ? TITLE_Y + TITLE_FONT_SIZE : TITLE_Y) + TITLE_FONT_SIZE / 2;
|
|
46754
|
-
topPad = Math.max(FIT_PAD, bannerBottom +
|
|
47692
|
+
topPad = Math.max(FIT_PAD, bannerBottom + TITLE_GAP2);
|
|
46755
47693
|
}
|
|
46756
47694
|
const fitBox = [
|
|
46757
47695
|
[FIT_PAD, topPad],
|
|
@@ -46761,11 +47699,10 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46761
47699
|
]
|
|
46762
47700
|
];
|
|
46763
47701
|
projection.fitExtent(fitBox, fitTarget);
|
|
46764
|
-
const fitGB = (0, import_d3_geo2.geoBounds)(fitTarget);
|
|
46765
|
-
const fitIsGlobal = fitGB[1][0] - fitGB[0][0] >= 270 || fitGB[1][1] - fitGB[0][1] >= 130;
|
|
46766
47702
|
let path;
|
|
46767
47703
|
let project;
|
|
46768
|
-
|
|
47704
|
+
let stretchParams = null;
|
|
47705
|
+
if (fitIsGlobal && !opts.preferContain) {
|
|
46769
47706
|
const cb = (0, import_d3_geo2.geoPath)(projection).bounds(fitTarget);
|
|
46770
47707
|
const bx0 = cb[0][0];
|
|
46771
47708
|
const by0 = cb[0][1];
|
|
@@ -46775,6 +47712,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46775
47712
|
const oy = fitBox[0][1];
|
|
46776
47713
|
const sx = cw > 0 ? (fitBox[1][0] - ox) / cw : 1;
|
|
46777
47714
|
const sy = ch > 0 ? (fitBox[1][1] - oy) / ch : 1;
|
|
47715
|
+
stretchParams = { sx, sy, ox, oy, bx0, by0 };
|
|
46778
47716
|
const stretch = (x, y) => [
|
|
46779
47717
|
ox + (x - bx0) * sx,
|
|
46780
47718
|
oy + (y - by0) * sy
|
|
@@ -46806,7 +47744,9 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46806
47744
|
const insets = [];
|
|
46807
47745
|
const insetRegions = [];
|
|
46808
47746
|
const insetLabelSeeds = [];
|
|
46809
|
-
|
|
47747
|
+
const akRef = resolved.regions.some((r) => r.iso === "US-AK") || resolved.pois.some((p) => inAlaska(p.lon, p.lat));
|
|
47748
|
+
const hiRef = resolved.regions.some((r) => r.iso === "US-HI") || resolved.pois.some((p) => inHawaii(p.lon, p.lat));
|
|
47749
|
+
if (resolved.projection === "albers-usa" && usLayer && (akRef || hiRef)) {
|
|
46810
47750
|
const PAD = 8;
|
|
46811
47751
|
const GAP = 12;
|
|
46812
47752
|
const yB = height - FIT_PAD;
|
|
@@ -46837,38 +47777,14 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46837
47777
|
}
|
|
46838
47778
|
return y;
|
|
46839
47779
|
};
|
|
46840
|
-
const
|
|
47780
|
+
const coastFloor = (x0, xr) => {
|
|
46841
47781
|
const n = 24;
|
|
46842
|
-
const pts = [];
|
|
46843
47782
|
let maxY = -Infinity;
|
|
46844
47783
|
for (let i = 0; i <= n; i++) {
|
|
46845
|
-
const
|
|
46846
|
-
|
|
46847
|
-
|
|
46848
|
-
|
|
46849
|
-
if (y > maxY) maxY = y;
|
|
46850
|
-
}
|
|
46851
|
-
}
|
|
46852
|
-
if (pts.length === 0) return () => yB - height * 0.42;
|
|
46853
|
-
let m = 0;
|
|
46854
|
-
if (pts.length >= 2) {
|
|
46855
|
-
let sx = 0, sy = 0, sxx = 0, sxy = 0;
|
|
46856
|
-
for (const [x, y] of pts) {
|
|
46857
|
-
sx += x;
|
|
46858
|
-
sy += y;
|
|
46859
|
-
sxx += x * x;
|
|
46860
|
-
sxy += x * y;
|
|
46861
|
-
}
|
|
46862
|
-
const den = pts.length * sxx - sx * sx;
|
|
46863
|
-
if (den !== 0) m = (pts.length * sxy - sx * sy) / den;
|
|
46864
|
-
}
|
|
46865
|
-
m = Math.max(-0.35, Math.min(0.35, m));
|
|
46866
|
-
let c = -Infinity;
|
|
46867
|
-
for (const [x, y] of pts) {
|
|
46868
|
-
const need = y - m * x + GAP;
|
|
46869
|
-
if (need > c) c = need;
|
|
46870
|
-
}
|
|
46871
|
-
return (x) => m * x + c;
|
|
47784
|
+
const y = at(x0 + (xr - x0) * i / n);
|
|
47785
|
+
if (y > maxY) maxY = y;
|
|
47786
|
+
}
|
|
47787
|
+
return maxY;
|
|
46872
47788
|
};
|
|
46873
47789
|
const placeInset = (iso, proj, boxX, iwReq) => {
|
|
46874
47790
|
const f = usLayer.get(iso);
|
|
@@ -46877,19 +47793,15 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46877
47793
|
const iw = Math.min(iwReq, width - FIT_PAD - x0 - 2 * PAD);
|
|
46878
47794
|
if (iw < 24) return boxX;
|
|
46879
47795
|
const xr = x0 + iw + 2 * PAD;
|
|
46880
|
-
const
|
|
46881
|
-
const
|
|
46882
|
-
const yR = top(xr);
|
|
47796
|
+
const floor = coastFloor(x0, xr);
|
|
47797
|
+
const topGuess = floor > -Infinity ? floor + GAP : yB - height * 0.42;
|
|
46883
47798
|
proj.fitWidth(iw, f);
|
|
46884
47799
|
const bb = (0, import_d3_geo2.geoPath)(proj).bounds(f);
|
|
46885
47800
|
const sh = Number.isFinite(bb[0][0]) ? bb[1][1] - bb[0][1] : iw;
|
|
46886
47801
|
const needH = sh + 2 * PAD;
|
|
46887
|
-
let topFit =
|
|
47802
|
+
let topFit = topGuess;
|
|
46888
47803
|
const bottom = Math.min(topFit + needH, yB);
|
|
46889
47804
|
if (bottom - topFit < needH) topFit = bottom - needH;
|
|
46890
|
-
const lift = topFit - Math.max(yL, yR);
|
|
46891
|
-
const topL = yL + lift;
|
|
46892
|
-
const topR = yR + lift;
|
|
46893
47805
|
proj.fitExtent(
|
|
46894
47806
|
[
|
|
46895
47807
|
[x0 + PAD, topFit + PAD],
|
|
@@ -46899,8 +47811,18 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46899
47811
|
);
|
|
46900
47812
|
const d = (0, import_d3_geo2.geoPath)(proj)(f) ?? "";
|
|
46901
47813
|
if (!d) return xr;
|
|
47814
|
+
let contextLand;
|
|
47815
|
+
if (iso === "US-AK") {
|
|
47816
|
+
const can = worldLayer.get("CA");
|
|
47817
|
+
const cd = can ? (0, import_d3_geo2.geoPath)(proj)(can) ?? "" : "";
|
|
47818
|
+
if (cd)
|
|
47819
|
+
contextLand = {
|
|
47820
|
+
d: cd,
|
|
47821
|
+
fill: colorizeActive ? colorByIso.get("CA") ?? foreignFill : foreignFill
|
|
47822
|
+
};
|
|
47823
|
+
}
|
|
46902
47824
|
const r = regionById.get(iso);
|
|
46903
|
-
let fill2 = neutralFill;
|
|
47825
|
+
let fill2 = colorizeActive ? colorByIso.get(iso) ?? neutralFill : neutralFill;
|
|
46904
47826
|
let lineNumber = -1;
|
|
46905
47827
|
if (r?.layer === "us-state") {
|
|
46906
47828
|
fill2 = regionFill(r);
|
|
@@ -46908,21 +47830,25 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46908
47830
|
}
|
|
46909
47831
|
insets.push({
|
|
46910
47832
|
x: x0,
|
|
46911
|
-
y:
|
|
47833
|
+
y: topFit,
|
|
46912
47834
|
w: xr - x0,
|
|
46913
|
-
h: bottom -
|
|
47835
|
+
h: bottom - topFit,
|
|
46914
47836
|
points: [
|
|
46915
|
-
[x0,
|
|
46916
|
-
[xr,
|
|
47837
|
+
[x0, topFit],
|
|
47838
|
+
[xr, topFit],
|
|
46917
47839
|
[xr, bottom],
|
|
46918
47840
|
[x0, bottom]
|
|
46919
|
-
]
|
|
47841
|
+
],
|
|
47842
|
+
// The FITTED inset projection (just fit to this box) — captured so the
|
|
47843
|
+
// geo-query can invert pixels inside the frame back to AK/HI coords.
|
|
47844
|
+
projection: proj,
|
|
47845
|
+
...contextLand && { contextLand }
|
|
46920
47846
|
});
|
|
46921
47847
|
insetRegions.push({
|
|
46922
47848
|
id: iso,
|
|
46923
47849
|
d,
|
|
46924
47850
|
fill: fill2,
|
|
46925
|
-
stroke: regionStroke,
|
|
47851
|
+
stroke: colorizeActive ? colorizeStroke(fill2) : regionStroke,
|
|
46926
47852
|
lineNumber,
|
|
46927
47853
|
layer: "us-state",
|
|
46928
47854
|
...r?.value !== void 0 && { value: r.value },
|
|
@@ -46935,13 +47861,16 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46935
47861
|
}
|
|
46936
47862
|
return xr;
|
|
46937
47863
|
};
|
|
46938
|
-
|
|
46939
|
-
|
|
46940
|
-
alaskaProjection(),
|
|
46941
|
-
|
|
46942
|
-
|
|
46943
|
-
|
|
46944
|
-
|
|
47864
|
+
let akRight = FIT_PAD;
|
|
47865
|
+
if (akRef)
|
|
47866
|
+
akRight = placeInset("US-AK", alaskaProjection(), FIT_PAD, width * 0.15);
|
|
47867
|
+
if (hiRef)
|
|
47868
|
+
placeInset(
|
|
47869
|
+
"US-HI",
|
|
47870
|
+
hawaiiProjection(),
|
|
47871
|
+
akRef ? akRight + 24 : FIT_PAD,
|
|
47872
|
+
width * 0.1
|
|
47873
|
+
);
|
|
46945
47874
|
}
|
|
46946
47875
|
const conusFit = resolved.projection === "albers-usa" && !!usLayer;
|
|
46947
47876
|
const classifyExtent = conusFit ? (0, import_d3_geo2.geoBounds)(fitTarget) : resolved.extent;
|
|
@@ -46957,15 +47886,24 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
46957
47886
|
};
|
|
46958
47887
|
const ringOverlapsView = (ring) => {
|
|
46959
47888
|
let loMin = Infinity, loMax = -Infinity, rawMin = Infinity, rawMax = -Infinity;
|
|
47889
|
+
const lons = [];
|
|
46960
47890
|
for (const [rawLon] of ring) {
|
|
46961
47891
|
const lon = normLon(rawLon);
|
|
47892
|
+
lons.push(lon);
|
|
46962
47893
|
if (lon < loMin) loMin = lon;
|
|
46963
47894
|
if (lon > loMax) loMax = lon;
|
|
46964
47895
|
if (rawLon < rawMin) rawMin = rawLon;
|
|
46965
47896
|
if (rawLon > rawMax) rawMax = rawLon;
|
|
46966
47897
|
}
|
|
46967
|
-
|
|
46968
|
-
|
|
47898
|
+
lons.sort((a, b) => a - b);
|
|
47899
|
+
let maxGap = 0;
|
|
47900
|
+
for (let i = 1; i < lons.length; i++)
|
|
47901
|
+
maxGap = Math.max(maxGap, lons[i] - lons[i - 1]);
|
|
47902
|
+
if (lons.length > 1)
|
|
47903
|
+
maxGap = Math.max(maxGap, lons[0] + 360 - lons[lons.length - 1]);
|
|
47904
|
+
const occupiedArc = 360 - maxGap;
|
|
47905
|
+
if (occupiedArc > 270) return false;
|
|
47906
|
+
if (rawMax - rawMin > 180 && occupiedArc < 90) return false;
|
|
46969
47907
|
let px0 = Infinity, py0 = Infinity, px1 = -Infinity, py1 = -Infinity, anyFinite = false;
|
|
46970
47908
|
for (const [lon, lat] of ring) {
|
|
46971
47909
|
const p = project(lon, lat);
|
|
@@ -47038,7 +47976,7 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47038
47976
|
const regions = [];
|
|
47039
47977
|
const pushRegionLayer = (layerFeatures, layerKind, shouldCull) => {
|
|
47040
47978
|
for (const [iso, f] of layerFeatures) {
|
|
47041
|
-
if (layerKind === "us-state" && usContext && INSET_STATES.has(iso))
|
|
47979
|
+
if (layerKind === "us-state" && usContext && resolved.projection === "albers-usa" && INSET_STATES.has(iso))
|
|
47042
47980
|
continue;
|
|
47043
47981
|
if (layerKind === "country" && usContext && iso === "US") continue;
|
|
47044
47982
|
if (layerKind === "country" && iso === "AQ" && !regionById.has("AQ"))
|
|
@@ -47050,7 +47988,8 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47050
47988
|
if (!d) continue;
|
|
47051
47989
|
const isThisLayer = r?.layer === layerKind;
|
|
47052
47990
|
const isForeign = layerKind === "country" && usContext && iso !== "US";
|
|
47053
|
-
|
|
47991
|
+
const baseFill = isForeign ? foreignFill : neutralFill;
|
|
47992
|
+
let fill2 = colorizeActive ? colorByIso.get(iso) ?? baseFill : baseFill;
|
|
47054
47993
|
let label;
|
|
47055
47994
|
let lineNumber = -1;
|
|
47056
47995
|
let layer = "base";
|
|
@@ -47059,12 +47998,14 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47059
47998
|
lineNumber = r.lineNumber;
|
|
47060
47999
|
layer = layerKind;
|
|
47061
48000
|
label = r.name;
|
|
48001
|
+
} else {
|
|
48002
|
+
label = f.properties?.name;
|
|
47062
48003
|
}
|
|
47063
48004
|
regions.push({
|
|
47064
48005
|
id: iso,
|
|
47065
48006
|
d,
|
|
47066
48007
|
fill: fill2,
|
|
47067
|
-
stroke: regionStroke,
|
|
48008
|
+
stroke: colorizeActive ? colorizeStroke(fill2) : regionStroke,
|
|
47068
48009
|
lineNumber,
|
|
47069
48010
|
layer,
|
|
47070
48011
|
...label !== void 0 && { label },
|
|
@@ -47086,13 +48027,88 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47086
48027
|
id: "lake",
|
|
47087
48028
|
d,
|
|
47088
48029
|
fill: water,
|
|
47089
|
-
stroke:
|
|
48030
|
+
stroke: lakeStroke,
|
|
47090
48031
|
lineNumber: -1,
|
|
47091
48032
|
layer: "base"
|
|
47092
48033
|
});
|
|
47093
48034
|
}
|
|
47094
48035
|
}
|
|
47095
|
-
const
|
|
48036
|
+
const pointInRings = (px, py, rings) => {
|
|
48037
|
+
let inside = false;
|
|
48038
|
+
for (const ring of rings) {
|
|
48039
|
+
for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
|
|
48040
|
+
const [xi, yi] = ring[i];
|
|
48041
|
+
const [xj, yj] = ring[j];
|
|
48042
|
+
if (yi > py !== yj > py && px < (xj - xi) * (py - yi) / (yj - yi) + xi)
|
|
48043
|
+
inside = !inside;
|
|
48044
|
+
}
|
|
48045
|
+
}
|
|
48046
|
+
return inside;
|
|
48047
|
+
};
|
|
48048
|
+
const fillHitTargets = [...regions, ...insetRegions].map((r) => ({
|
|
48049
|
+
fill: r.fill,
|
|
48050
|
+
rings: parsePathRings(r.d)
|
|
48051
|
+
}));
|
|
48052
|
+
const fillAt = (x, y) => {
|
|
48053
|
+
let hit = water;
|
|
48054
|
+
for (const t of fillHitTargets)
|
|
48055
|
+
if (pointInRings(x, y, t.rings)) hit = t.fill;
|
|
48056
|
+
return hit;
|
|
48057
|
+
};
|
|
48058
|
+
const labelOnFill = (fill2) => {
|
|
48059
|
+
const color = contrastRatio(fill2, palette.textOnFillDark) >= contrastRatio(fill2, palette.textOnFillLight) ? palette.textOnFillDark : palette.textOnFillLight;
|
|
48060
|
+
const haloColor = color === palette.textOnFillLight ? palette.textOnFillDark : palette.textOnFillLight;
|
|
48061
|
+
return {
|
|
48062
|
+
color,
|
|
48063
|
+
halo: contrastRatio(fill2, color) < REGION_LABEL_HALO_RATIO,
|
|
48064
|
+
haloColor
|
|
48065
|
+
};
|
|
48066
|
+
};
|
|
48067
|
+
const reliefAllowed = resolved.directives.noRelief !== true;
|
|
48068
|
+
const relief = [];
|
|
48069
|
+
let reliefHatch = null;
|
|
48070
|
+
if (reliefAllowed && data.mountainRanges) {
|
|
48071
|
+
for (const [, f] of decodeLayer(data.mountainRanges)) {
|
|
48072
|
+
const viewF = isGlobalView ? dropFrameFillers(f) : cullFeatureToView(f);
|
|
48073
|
+
if (!viewF) continue;
|
|
48074
|
+
const area2 = path.area(viewF);
|
|
48075
|
+
if (!Number.isFinite(area2) || area2 < RELIEF_MIN_AREA) continue;
|
|
48076
|
+
const box = path.bounds(viewF);
|
|
48077
|
+
if (box[1][0] - box[0][0] < RELIEF_MIN_DIM || box[1][1] - box[0][1] < RELIEF_MIN_DIM)
|
|
48078
|
+
continue;
|
|
48079
|
+
const d = path(viewF) ?? "";
|
|
48080
|
+
if (!d) continue;
|
|
48081
|
+
relief.push({ d });
|
|
48082
|
+
}
|
|
48083
|
+
if (relief.length) {
|
|
48084
|
+
const darkTone = isDark ? palette.bg : palette.text;
|
|
48085
|
+
const lightTone = isDark ? palette.text : palette.bg;
|
|
48086
|
+
const reliefLandRef = colorizeActive ? isDark ? palette.surface : palette.bg : neutralFill;
|
|
48087
|
+
const landLum = relativeLuminance(reliefLandRef);
|
|
48088
|
+
const tone = Math.abs(landLum - relativeLuminance(darkTone)) > 0.04 ? darkTone : lightTone;
|
|
48089
|
+
reliefHatch = {
|
|
48090
|
+
color: mix(tone, reliefLandRef, RELIEF_HATCH_STRENGTH),
|
|
48091
|
+
spacing: RELIEF_HATCH_SPACING,
|
|
48092
|
+
width: RELIEF_HATCH_WIDTH
|
|
48093
|
+
};
|
|
48094
|
+
}
|
|
48095
|
+
}
|
|
48096
|
+
let coastlineStyle = null;
|
|
48097
|
+
if (resolved.directives.noCoastline !== true) {
|
|
48098
|
+
const minDim = Math.min(width, height);
|
|
48099
|
+
coastlineStyle = {
|
|
48100
|
+
color: mix(regionStroke, water, COASTLINE_STROKE_MIX),
|
|
48101
|
+
// N equal-width rings: distance steps outward by COASTLINE_STEP; opacity
|
|
48102
|
+
// fades linearly from NEAR (innermost) to FAR (outermost).
|
|
48103
|
+
lines: Array.from({ length: COASTLINE_RING_COUNT }, (_, k) => ({
|
|
48104
|
+
d: (COASTLINE_D0 + k * COASTLINE_STEP) * minDim,
|
|
48105
|
+
thickness: COASTLINE_THICKNESS * minDim,
|
|
48106
|
+
opacity: COASTLINE_OPACITY_NEAR + (COASTLINE_OPACITY_FAR - COASTLINE_OPACITY_NEAR) * k / (COASTLINE_RING_COUNT - 1)
|
|
48107
|
+
})),
|
|
48108
|
+
minExtent: (isGlobalView ? COASTLINE_MIN_EXTENT_GLOBAL : COASTLINE_MIN_EXTENT) * minDim
|
|
48109
|
+
};
|
|
48110
|
+
}
|
|
48111
|
+
const riverColor = mix(palette.colors.blue, water, 32);
|
|
47096
48112
|
const rivers = [];
|
|
47097
48113
|
if (data.rivers) {
|
|
47098
48114
|
for (const [, f] of decodeLayer(data.rivers)) {
|
|
@@ -47113,6 +48129,9 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47113
48129
|
return R_MIN + Math.max(0, Math.min(1, t)) * (R_MAX - R_MIN);
|
|
47114
48130
|
};
|
|
47115
48131
|
const poiFill = (p) => {
|
|
48132
|
+
const directHex = p.color ? resolveColor(p.color, palette) : null;
|
|
48133
|
+
if (directHex)
|
|
48134
|
+
return { fill: directHex, stroke: mix(directHex, palette.text, 18) };
|
|
47116
48135
|
for (const group of resolved.tagGroups) {
|
|
47117
48136
|
const val = p.tags[group.name.toLowerCase()];
|
|
47118
48137
|
if (!val) continue;
|
|
@@ -47145,38 +48164,108 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47145
48164
|
const xy = project(p.lon, p.lat);
|
|
47146
48165
|
if (xy) projected.push({ p, xy });
|
|
47147
48166
|
}
|
|
47148
|
-
const
|
|
48167
|
+
const placePoi = (e, cx, cy, clusterId) => {
|
|
48168
|
+
const { fill: fill2, stroke: stroke2 } = poiFill(e.p);
|
|
48169
|
+
poiScreen.set(e.p.id, { cx, cy, r: radiusFor(e.p) });
|
|
48170
|
+
const num = routeNumberById.get(e.p.id);
|
|
48171
|
+
pois.push({
|
|
48172
|
+
id: e.p.id,
|
|
48173
|
+
cx,
|
|
48174
|
+
cy,
|
|
48175
|
+
r: radiusFor(e.p),
|
|
48176
|
+
fill: fill2,
|
|
48177
|
+
stroke: stroke2,
|
|
48178
|
+
lineNumber: e.p.lineNumber,
|
|
48179
|
+
implicit: !!e.p.implicit,
|
|
48180
|
+
isOrigin: originIds.has(e.p.id),
|
|
48181
|
+
...num !== void 0 && { routeNumber: num },
|
|
48182
|
+
...Object.keys(e.p.tags).length > 0 && { tags: e.p.tags },
|
|
48183
|
+
...clusterId !== void 0 && { clusterId }
|
|
48184
|
+
});
|
|
48185
|
+
};
|
|
48186
|
+
const clusters = [];
|
|
48187
|
+
const connected = /* @__PURE__ */ new Set();
|
|
48188
|
+
for (const e of resolved.edges) {
|
|
48189
|
+
connected.add(e.fromId);
|
|
48190
|
+
connected.add(e.toId);
|
|
48191
|
+
}
|
|
48192
|
+
for (const rt of resolved.routes) {
|
|
48193
|
+
rt.stopIds.forEach((id) => connected.add(id));
|
|
48194
|
+
}
|
|
48195
|
+
const radiusOf = (e) => radiusFor(e.p);
|
|
47149
48196
|
for (const e of projected) {
|
|
47150
|
-
|
|
47151
|
-
|
|
47152
|
-
|
|
47153
|
-
|
|
47154
|
-
|
|
47155
|
-
|
|
47156
|
-
|
|
47157
|
-
|
|
47158
|
-
|
|
47159
|
-
|
|
47160
|
-
|
|
47161
|
-
|
|
47162
|
-
|
|
47163
|
-
|
|
47164
|
-
|
|
47165
|
-
|
|
47166
|
-
|
|
47167
|
-
|
|
47168
|
-
|
|
47169
|
-
|
|
47170
|
-
|
|
47171
|
-
|
|
47172
|
-
|
|
47173
|
-
|
|
47174
|
-
|
|
47175
|
-
|
|
47176
|
-
|
|
47177
|
-
|
|
47178
|
-
|
|
47179
|
-
|
|
48197
|
+
if (connected.has(e.p.id)) placePoi(e, e.xy[0], e.xy[1]);
|
|
48198
|
+
}
|
|
48199
|
+
const groups = [];
|
|
48200
|
+
for (const e of projected) {
|
|
48201
|
+
if (connected.has(e.p.id)) continue;
|
|
48202
|
+
const r = radiusOf(e);
|
|
48203
|
+
const near = groups.find(
|
|
48204
|
+
(g) => g.some(
|
|
48205
|
+
(q) => Math.hypot(q.xy[0] - e.xy[0], q.xy[1] - e.xy[1]) < (r + radiusOf(q)) * STACK_OVERLAP
|
|
48206
|
+
)
|
|
48207
|
+
);
|
|
48208
|
+
if (near) near.push(e);
|
|
48209
|
+
else groups.push([e]);
|
|
48210
|
+
}
|
|
48211
|
+
for (const g of groups) {
|
|
48212
|
+
if (g.length === 1) {
|
|
48213
|
+
placePoi(g[0], g[0].xy[0], g[0].xy[1]);
|
|
48214
|
+
continue;
|
|
48215
|
+
}
|
|
48216
|
+
const clusterId = g[0].p.id;
|
|
48217
|
+
const cx0 = g.reduce((s, e) => s + e.xy[0], 0) / g.length;
|
|
48218
|
+
const cy0 = g.reduce((s, e) => s + e.xy[1], 0) / g.length;
|
|
48219
|
+
const maxR = Math.max(...g.map(radiusOf));
|
|
48220
|
+
const sep = 2 * maxR + STACK_RING_GAP;
|
|
48221
|
+
const ringR = Math.max(
|
|
48222
|
+
COLO_R,
|
|
48223
|
+
sep / (2 * Math.sin(Math.PI / Math.max(g.length, 2)))
|
|
48224
|
+
);
|
|
48225
|
+
const positions = g.map((e, i) => {
|
|
48226
|
+
if (g.length <= STACK_RING_MAX) {
|
|
48227
|
+
const ang2 = -Math.PI / 2 + i * 2 * Math.PI / g.length;
|
|
48228
|
+
return {
|
|
48229
|
+
e,
|
|
48230
|
+
mx: cx0 + Math.cos(ang2) * ringR,
|
|
48231
|
+
my: cy0 + Math.sin(ang2) * ringR
|
|
48232
|
+
};
|
|
48233
|
+
}
|
|
48234
|
+
const ang = i * GOLDEN_ANGLE;
|
|
48235
|
+
const rr = ringR * Math.sqrt((i + 1) / g.length);
|
|
48236
|
+
return { e, mx: cx0 + Math.cos(ang) * rr, my: cy0 + Math.sin(ang) * rr };
|
|
48237
|
+
});
|
|
48238
|
+
let minX = cx0 - maxR;
|
|
48239
|
+
let maxX = cx0 + maxR;
|
|
48240
|
+
let minY = cy0 - maxR;
|
|
48241
|
+
let maxY = cy0 + maxR;
|
|
48242
|
+
for (const { mx, my, e } of positions) {
|
|
48243
|
+
const r = radiusOf(e);
|
|
48244
|
+
minX = Math.min(minX, mx - r);
|
|
48245
|
+
maxX = Math.max(maxX, mx + r);
|
|
48246
|
+
minY = Math.min(minY, my - r);
|
|
48247
|
+
maxY = Math.max(maxY, my + r);
|
|
48248
|
+
}
|
|
48249
|
+
let dx = 0;
|
|
48250
|
+
let dy = 0;
|
|
48251
|
+
if (minX + dx < 2) dx = 2 - minX;
|
|
48252
|
+
if (maxX + dx > width - 2) dx = width - 2 - maxX;
|
|
48253
|
+
if (minY + dy < 2) dy = 2 - minY;
|
|
48254
|
+
if (maxY + dy > height - 2) dy = height - 2 - maxY;
|
|
48255
|
+
const legsOut = [];
|
|
48256
|
+
for (const { e, mx, my } of positions) {
|
|
48257
|
+
const fx = mx + dx;
|
|
48258
|
+
const fy = my + dy;
|
|
48259
|
+
placePoi(e, fx, fy, clusterId);
|
|
48260
|
+
legsOut.push({ x2: fx, y2: fy, color: poiFill(e.p).fill });
|
|
48261
|
+
}
|
|
48262
|
+
clusters.push({
|
|
48263
|
+
id: clusterId,
|
|
48264
|
+
cx: cx0 + dx,
|
|
48265
|
+
cy: cy0 + dy,
|
|
48266
|
+
count: g.length,
|
|
48267
|
+
hitR: ringR + maxR + 6,
|
|
48268
|
+
legs: legsOut
|
|
47180
48269
|
});
|
|
47181
48270
|
}
|
|
47182
48271
|
const legs = [];
|
|
@@ -47226,16 +48315,26 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47226
48315
|
if (!a || !b) continue;
|
|
47227
48316
|
const mx = (a.cx + b.cx) / 2;
|
|
47228
48317
|
const my = (a.cy + b.cy) / 2;
|
|
48318
|
+
const bow = {
|
|
48319
|
+
curved: leg.style === "arc",
|
|
48320
|
+
offset: 0,
|
|
48321
|
+
labelX: mx,
|
|
48322
|
+
labelY: my - 4
|
|
48323
|
+
};
|
|
48324
|
+
const routeLabelStyle = leg.label !== void 0 ? labelOnFill(fillAt(bow.labelX, bow.labelY)) : void 0;
|
|
47229
48325
|
legs.push({
|
|
47230
|
-
d: legPath(a, b,
|
|
48326
|
+
d: legPath(a, b, bow.curved, bow.offset),
|
|
47231
48327
|
width: routeWidthFor(Number(leg.value)),
|
|
47232
48328
|
color: mix(palette.text, palette.bg, 72),
|
|
47233
48329
|
arrow: true,
|
|
47234
48330
|
lineNumber: leg.lineNumber,
|
|
47235
48331
|
...leg.label !== void 0 && {
|
|
47236
48332
|
label: leg.label,
|
|
47237
|
-
labelX:
|
|
47238
|
-
labelY:
|
|
48333
|
+
labelX: bow.labelX,
|
|
48334
|
+
labelY: bow.labelY,
|
|
48335
|
+
labelColor: routeLabelStyle.color,
|
|
48336
|
+
labelHalo: routeLabelStyle.halo,
|
|
48337
|
+
labelHaloColor: routeLabelStyle.haloColor
|
|
47239
48338
|
}
|
|
47240
48339
|
});
|
|
47241
48340
|
}
|
|
@@ -47263,20 +48362,29 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47263
48362
|
const a = poiScreen.get(e.fromId);
|
|
47264
48363
|
const b = poiScreen.get(e.toId);
|
|
47265
48364
|
if (!a || !b) return;
|
|
47266
|
-
const
|
|
47267
|
-
const offset = n > 1 ? (i - (n - 1) / 2) * FAN_STEP : 0;
|
|
48365
|
+
const fanOffset = n > 1 ? (i - (n - 1) / 2) * FAN_STEP : 0;
|
|
47268
48366
|
const mx = (a.cx + b.cx) / 2;
|
|
47269
48367
|
const my = (a.cy + b.cy) / 2;
|
|
48368
|
+
const bow = {
|
|
48369
|
+
curved: e.style === "arc" || n > 1,
|
|
48370
|
+
offset: fanOffset,
|
|
48371
|
+
labelX: mx,
|
|
48372
|
+
labelY: my - 4
|
|
48373
|
+
};
|
|
48374
|
+
const edgeLabelStyle = e.label !== void 0 ? labelOnFill(fillAt(bow.labelX, bow.labelY)) : void 0;
|
|
47270
48375
|
legs.push({
|
|
47271
|
-
d: legPath(a, b, curved, offset),
|
|
48376
|
+
d: legPath(a, b, bow.curved, bow.offset),
|
|
47272
48377
|
width: widthFor(e),
|
|
47273
48378
|
color: mix(palette.text, palette.bg, 66),
|
|
47274
48379
|
arrow: e.directed,
|
|
47275
48380
|
lineNumber: e.lineNumber,
|
|
47276
48381
|
...e.label !== void 0 && {
|
|
47277
48382
|
label: e.label,
|
|
47278
|
-
labelX:
|
|
47279
|
-
labelY:
|
|
48383
|
+
labelX: bow.labelX,
|
|
48384
|
+
labelY: bow.labelY,
|
|
48385
|
+
labelColor: edgeLabelStyle.color,
|
|
48386
|
+
labelHalo: edgeLabelStyle.halo,
|
|
48387
|
+
labelHaloColor: edgeLabelStyle.haloColor
|
|
47280
48388
|
}
|
|
47281
48389
|
});
|
|
47282
48390
|
});
|
|
@@ -47318,25 +48426,25 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47318
48426
|
}
|
|
47319
48427
|
}
|
|
47320
48428
|
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));
|
|
47321
|
-
const
|
|
48429
|
+
const showRegionLabels = resolved.directives.noRegionLabels !== true;
|
|
48430
|
+
const isCompact = width < COMPACT_WIDTH_PX;
|
|
47322
48431
|
const LABEL_PADX = 6;
|
|
47323
48432
|
const LABEL_PADY = 3;
|
|
47324
|
-
const labelW = (text) => measureLegendText(text,
|
|
47325
|
-
const labelH =
|
|
48433
|
+
const labelW = (text) => measureLegendText(text, FONT2) + 2 * LABEL_PADX;
|
|
48434
|
+
const labelH = FONT2 + 2 * LABEL_PADY;
|
|
47326
48435
|
const pushRegionLabel = (x, y, text, fill2, lineNumber) => {
|
|
47327
|
-
const color =
|
|
47328
|
-
|
|
47329
|
-
|
|
47330
|
-
|
|
48436
|
+
const { color, haloColor } = labelOnFill(fill2);
|
|
48437
|
+
const halfW = measureLegendText(text, FONT2) / 2;
|
|
48438
|
+
const overflows = [y - FONT2 * 0.55, y - FONT2 * 0.1].some(
|
|
48439
|
+
(sy) => fillAt(x - halfW, sy) !== fill2 || fillAt(x + halfW, sy) !== fill2
|
|
47331
48440
|
);
|
|
47332
|
-
const haloColor = color === palette.textOnFillLight ? palette.textOnFillDark : palette.textOnFillLight;
|
|
47333
48441
|
labels.push({
|
|
47334
48442
|
x,
|
|
47335
48443
|
y,
|
|
47336
48444
|
text,
|
|
47337
48445
|
anchor: "middle",
|
|
47338
48446
|
color,
|
|
47339
|
-
halo:
|
|
48447
|
+
halo: overflows,
|
|
47340
48448
|
haloColor,
|
|
47341
48449
|
lineNumber
|
|
47342
48450
|
});
|
|
@@ -47345,21 +48453,50 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47345
48453
|
US: [-98.5, 39.5]
|
|
47346
48454
|
// CONUS geographic centre (near Lebanon, Kansas)
|
|
47347
48455
|
};
|
|
47348
|
-
|
|
47349
|
-
|
|
47350
|
-
|
|
47351
|
-
|
|
47352
|
-
|
|
48456
|
+
const REGION_LABEL_GAP = 2;
|
|
48457
|
+
const regionLabelRect = (cx, cy, text) => {
|
|
48458
|
+
const w = measureLegendText(text, FONT2) + 2 * REGION_LABEL_GAP;
|
|
48459
|
+
return { x: cx - w / 2, y: cy - FONT2 / 2, w, h: FONT2 };
|
|
48460
|
+
};
|
|
48461
|
+
if (showRegionLabels) {
|
|
48462
|
+
const frameContainers = new Set(resolved.poiFrameContainers);
|
|
48463
|
+
const entries = regions.map((r) => {
|
|
48464
|
+
const isContainer = frameContainers.has(r.id);
|
|
48465
|
+
if (r.layer === "base" && !isContainer || r.label === void 0)
|
|
48466
|
+
return null;
|
|
48467
|
+
const isUsState = r.layer === "us-state" || r.id.startsWith("US-");
|
|
48468
|
+
const f = isUsState ? usLayer?.get(r.id) : worldLayer.get(r.id);
|
|
48469
|
+
if (!f) return null;
|
|
47353
48470
|
const [[x0, y0], [x1, y1]] = path.bounds(f);
|
|
47354
|
-
const
|
|
47355
|
-
|
|
47356
|
-
const
|
|
48471
|
+
const boxW = x1 - x0;
|
|
48472
|
+
const boxH = y1 - y0;
|
|
48473
|
+
const abbrev = isUsState ? r.id.replace(/^US-/, "") : void 0;
|
|
48474
|
+
const candidates = abbrev !== void 0 ? isCompact ? [abbrev, r.label] : [r.label, abbrev] : [r.label];
|
|
48475
|
+
const anchor = !isUsState ? WORLD_LABEL_ANCHORS[r.id] : void 0;
|
|
47357
48476
|
const c = anchor ? project(anchor[0], anchor[1]) : path.centroid(f);
|
|
47358
|
-
if (!c || !Number.isFinite(c[0]))
|
|
48477
|
+
if (!c || !Number.isFinite(c[0])) return null;
|
|
48478
|
+
return { r, c, boxW, boxH, area: boxW * boxH, candidates };
|
|
48479
|
+
}).filter((e) => e !== null).sort((a, b) => b.area - a.area || a.r.lineNumber - b.r.lineNumber);
|
|
48480
|
+
const placedRegionRects = [];
|
|
48481
|
+
const POI_LABEL_PAD = 14;
|
|
48482
|
+
const poiObstacles = pois.map((p) => ({
|
|
48483
|
+
x: p.cx - p.r - POI_LABEL_PAD,
|
|
48484
|
+
y: p.cy - p.r - POI_LABEL_PAD,
|
|
48485
|
+
w: 2 * (p.r + POI_LABEL_PAD),
|
|
48486
|
+
h: 2 * (p.r + POI_LABEL_PAD)
|
|
48487
|
+
}));
|
|
48488
|
+
for (const { r, c, boxW, boxH, candidates } of entries) {
|
|
48489
|
+
const text = candidates.find((t) => {
|
|
48490
|
+
if (labelW(t) > boxW || labelH > boxH) return false;
|
|
48491
|
+
const rect = regionLabelRect(c[0], c[1], t);
|
|
48492
|
+
return !placedRegionRects.some((p) => rectsOverlap(rect, p)) && !poiObstacles.some((o) => rectsOverlap(rect, o));
|
|
48493
|
+
});
|
|
48494
|
+
if (text === void 0) continue;
|
|
48495
|
+
placedRegionRects.push(regionLabelRect(c[0], c[1], text));
|
|
47359
48496
|
pushRegionLabel(c[0], c[1], text, r.fill, r.lineNumber);
|
|
47360
48497
|
}
|
|
47361
48498
|
for (const seed of insetLabelSeeds) {
|
|
47362
|
-
const text =
|
|
48499
|
+
const text = isCompact ? seed.iso.replace(/^US-/, "") : seed.name;
|
|
47363
48500
|
const src = regionById.get(seed.iso);
|
|
47364
48501
|
pushRegionLabel(
|
|
47365
48502
|
seed.x,
|
|
@@ -47370,22 +48507,26 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47370
48507
|
);
|
|
47371
48508
|
}
|
|
47372
48509
|
}
|
|
47373
|
-
|
|
47374
|
-
|
|
47375
|
-
const ordered = [...pois].sort(
|
|
47376
|
-
(a, b) => a.lineNumber - b.lineNumber || (a.id < b.id ? -1 : 1)
|
|
47377
|
-
);
|
|
48510
|
+
if (resolved.directives.noPoiLabels !== true) {
|
|
48511
|
+
const ordered = [...pois].filter((p) => p.clusterId === void 0).sort((a, b) => a.lineNumber - b.lineNumber || (a.id < b.id ? -1 : 1));
|
|
47378
48512
|
const poiById = new Map(resolved.pois.map((q) => [q.id, q]));
|
|
47379
48513
|
const labelText = (p) => {
|
|
47380
48514
|
const src = poiById.get(p.id);
|
|
47381
48515
|
return src?.label ?? src?.name ?? p.id;
|
|
47382
48516
|
};
|
|
47383
|
-
const poiLabH =
|
|
48517
|
+
const poiLabH = FONT2 * 1.25;
|
|
47384
48518
|
const labelInfo = (p) => {
|
|
47385
48519
|
const text = labelText(p);
|
|
47386
|
-
return { text, w: measureLegendText(text,
|
|
48520
|
+
return { text, w: measureLegendText(text, FONT2) };
|
|
47387
48521
|
};
|
|
47388
48522
|
const GAP = 3;
|
|
48523
|
+
const clusterMembersById = /* @__PURE__ */ new Map();
|
|
48524
|
+
for (const p of pois) {
|
|
48525
|
+
if (p.clusterId === void 0) continue;
|
|
48526
|
+
const arr = clusterMembersById.get(p.clusterId);
|
|
48527
|
+
if (arr) arr.push(p);
|
|
48528
|
+
else clusterMembersById.set(p.clusterId, [p]);
|
|
48529
|
+
}
|
|
47389
48530
|
const inlineRect = (p, w, side) => {
|
|
47390
48531
|
switch (side) {
|
|
47391
48532
|
case "right":
|
|
@@ -47415,11 +48556,11 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47415
48556
|
const x = side === "right" ? rect.x : side === "left" ? rect.x + w : p.cx;
|
|
47416
48557
|
labels.push({
|
|
47417
48558
|
x,
|
|
47418
|
-
y: rect.y + poiLabH / 2 +
|
|
48559
|
+
y: rect.y + poiLabH / 2 + FONT2 / 3,
|
|
47419
48560
|
text,
|
|
47420
48561
|
anchor,
|
|
47421
48562
|
color: palette.text,
|
|
47422
|
-
halo:
|
|
48563
|
+
halo: false,
|
|
47423
48564
|
haloColor: palette.bg,
|
|
47424
48565
|
poiId: p.id,
|
|
47425
48566
|
lineNumber: p.lineNumber
|
|
@@ -47430,43 +48571,60 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47430
48571
|
return rect.x >= 0 && rect.x + rect.w <= width && rect.y >= 0 && rect.y + rect.h <= height && !collides(rect);
|
|
47431
48572
|
};
|
|
47432
48573
|
const GROUP_R = 30;
|
|
47433
|
-
const
|
|
48574
|
+
const groups2 = [];
|
|
47434
48575
|
for (const p of ordered) {
|
|
47435
|
-
const near =
|
|
48576
|
+
const near = groups2.find(
|
|
47436
48577
|
(g) => g.some((q) => Math.hypot(q.cx - p.cx, q.cy - p.cy) < GROUP_R)
|
|
47437
48578
|
);
|
|
47438
48579
|
if (near) near.push(p);
|
|
47439
|
-
else
|
|
48580
|
+
else groups2.push([p]);
|
|
47440
48581
|
}
|
|
47441
48582
|
const ROW_GAP2 = 3;
|
|
47442
48583
|
const step = poiLabH + ROW_GAP2;
|
|
47443
48584
|
const COL_GAP = 16;
|
|
47444
|
-
const
|
|
47445
|
-
|
|
48585
|
+
const makeItems = (group) => group.map((p) => ({ p, ...labelInfo(p) })).sort((a, b) => a.p.cy - b.p.cy || (a.text < b.text ? -1 : 1));
|
|
48586
|
+
const columnRows = (items, side) => {
|
|
47446
48587
|
const left = Math.min(...items.map((o) => o.p.cx - o.p.r));
|
|
47447
48588
|
const right = Math.max(...items.map((o) => o.p.cx + o.p.r));
|
|
47448
|
-
const cyMid = (Math.min(...items.map((o) => o.p.cy)) + Math.max(...items.map((o) => o.p.cy))) / 2;
|
|
47449
48589
|
const maxW = Math.max(...items.map((o) => o.w));
|
|
47450
|
-
const
|
|
47451
|
-
const colX = side === "right" ? right + COL_GAP : left - COL_GAP;
|
|
48590
|
+
const cyMid = (Math.min(...items.map((o) => o.p.cy)) + Math.max(...items.map((o) => o.p.cy))) / 2;
|
|
48591
|
+
const colX = side === "right" ? Math.min(right + COL_GAP, width - 2 - maxW) : Math.max(left - COL_GAP, 2 + maxW);
|
|
47452
48592
|
const totalH = items.length * step;
|
|
47453
48593
|
let startY = cyMid - totalH / 2;
|
|
47454
48594
|
startY = Math.max(2, Math.min(startY, height - totalH - 2));
|
|
47455
|
-
items.
|
|
48595
|
+
return items.map((o, i) => {
|
|
47456
48596
|
const rowCy = startY + i * step + step / 2;
|
|
47457
|
-
|
|
47458
|
-
|
|
47459
|
-
|
|
47460
|
-
|
|
47461
|
-
|
|
47462
|
-
|
|
48597
|
+
return {
|
|
48598
|
+
o,
|
|
48599
|
+
colX,
|
|
48600
|
+
rowCy,
|
|
48601
|
+
rect: {
|
|
48602
|
+
x: side === "right" ? colX : colX - o.w,
|
|
48603
|
+
y: rowCy - poiLabH / 2,
|
|
48604
|
+
w: o.w,
|
|
48605
|
+
h: poiLabH
|
|
48606
|
+
}
|
|
48607
|
+
};
|
|
48608
|
+
});
|
|
48609
|
+
};
|
|
48610
|
+
const wouldColumnBeClean = (items, side) => columnRows(items, side).every(
|
|
48611
|
+
({ rect }) => rect.x >= 0 && rect.x + rect.w <= width && rect.y >= 0 && rect.y + rect.h <= height && !collides(rect)
|
|
48612
|
+
);
|
|
48613
|
+
const defaultColumnSide = (items) => {
|
|
48614
|
+
const right = Math.max(...items.map((o) => o.p.cx + o.p.r));
|
|
48615
|
+
const maxW = Math.max(...items.map((o) => o.w));
|
|
48616
|
+
return right + COL_GAP + maxW <= width - 2 ? "right" : "left";
|
|
48617
|
+
};
|
|
48618
|
+
const commitColumn = (items, side, clusterId) => {
|
|
48619
|
+
for (const { o, colX, rowCy, rect } of columnRows(items, side)) {
|
|
48620
|
+
obstacles.push(rect);
|
|
47463
48621
|
labels.push({
|
|
47464
48622
|
x: colX,
|
|
47465
|
-
y: rowCy +
|
|
48623
|
+
y: rowCy + FONT2 / 3,
|
|
47466
48624
|
text: o.text,
|
|
47467
48625
|
anchor: side === "right" ? "start" : "end",
|
|
47468
48626
|
color: palette.text,
|
|
47469
|
-
halo:
|
|
48627
|
+
halo: false,
|
|
47470
48628
|
haloColor: palette.bg,
|
|
47471
48629
|
leader: {
|
|
47472
48630
|
x1: o.p.cx,
|
|
@@ -47476,24 +48634,141 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47476
48634
|
},
|
|
47477
48635
|
leaderColor: o.p.fill,
|
|
47478
48636
|
poiId: o.p.id,
|
|
47479
|
-
lineNumber: o.p.lineNumber
|
|
48637
|
+
lineNumber: o.p.lineNumber,
|
|
48638
|
+
...clusterId !== void 0 && { clusterMember: clusterId }
|
|
47480
48639
|
});
|
|
48640
|
+
}
|
|
48641
|
+
};
|
|
48642
|
+
const pushHidden = (p) => {
|
|
48643
|
+
const { text, w } = labelInfo(p);
|
|
48644
|
+
let x = p.cx + p.r + GAP;
|
|
48645
|
+
let anchor = "start";
|
|
48646
|
+
if (x + w > width) {
|
|
48647
|
+
x = p.cx - p.r - GAP - w;
|
|
48648
|
+
anchor = "end";
|
|
48649
|
+
}
|
|
48650
|
+
const y = Math.max(0, Math.min(p.cy - poiLabH / 2, height - poiLabH));
|
|
48651
|
+
labels.push({
|
|
48652
|
+
x: anchor === "start" ? x : x + w,
|
|
48653
|
+
y: y + poiLabH / 2 + FONT2 / 3,
|
|
48654
|
+
text,
|
|
48655
|
+
anchor,
|
|
48656
|
+
color: palette.text,
|
|
48657
|
+
halo: false,
|
|
48658
|
+
haloColor: palette.bg,
|
|
48659
|
+
poiId: p.id,
|
|
48660
|
+
hidden: true,
|
|
48661
|
+
lineNumber: p.lineNumber
|
|
47481
48662
|
});
|
|
47482
48663
|
};
|
|
47483
|
-
for (const
|
|
48664
|
+
for (const [clusterId, members] of clusterMembersById) {
|
|
48665
|
+
if (members.length === 0) continue;
|
|
48666
|
+
const items = makeItems(members);
|
|
48667
|
+
const side = wouldColumnBeClean(items, "right") ? "right" : wouldColumnBeClean(items, "left") ? "left" : defaultColumnSide(items);
|
|
48668
|
+
commitColumn(items, side, clusterId);
|
|
48669
|
+
}
|
|
48670
|
+
const maxExtent = MAX_CLUSTER_EXTENT_FACTOR * Math.min(width, height);
|
|
48671
|
+
const clusterPending = [];
|
|
48672
|
+
for (const g of groups2) {
|
|
48673
|
+
const items = makeItems(g);
|
|
47484
48674
|
if (g.length === 1) {
|
|
47485
|
-
const p =
|
|
47486
|
-
const { text, w } = labelInfo(p);
|
|
48675
|
+
const { p, text, w } = items[0];
|
|
47487
48676
|
const side = ["right", "left", "above", "below"].find(
|
|
47488
48677
|
(s) => inlineFits(p, w, s)
|
|
47489
48678
|
);
|
|
47490
|
-
if (side)
|
|
47491
|
-
|
|
47492
|
-
|
|
48679
|
+
if (side) pushInline(p, text, w, side);
|
|
48680
|
+
else commitColumn(items, defaultColumnSide(items));
|
|
48681
|
+
continue;
|
|
48682
|
+
}
|
|
48683
|
+
const left = Math.min(...items.map((o) => o.p.cx - o.p.r));
|
|
48684
|
+
const right = Math.max(...items.map((o) => o.p.cx + o.p.r));
|
|
48685
|
+
const minCy = Math.min(...items.map((o) => o.p.cy));
|
|
48686
|
+
const maxCy = Math.max(...items.map((o) => o.p.cy));
|
|
48687
|
+
const diag = Math.hypot(right - left, maxCy - minCy);
|
|
48688
|
+
if (diag > maxExtent || items.length > MAX_COLUMN_ROWS) {
|
|
48689
|
+
items.forEach((o) => pushHidden(o.p));
|
|
48690
|
+
} else {
|
|
48691
|
+
clusterPending.push(items);
|
|
48692
|
+
}
|
|
48693
|
+
}
|
|
48694
|
+
for (const items of clusterPending) {
|
|
48695
|
+
const side = ["right", "left"].find(
|
|
48696
|
+
(s) => wouldColumnBeClean(items, s)
|
|
48697
|
+
);
|
|
48698
|
+
if (side) commitColumn(items, side);
|
|
48699
|
+
else items.forEach((o) => pushHidden(o.p));
|
|
48700
|
+
}
|
|
48701
|
+
}
|
|
48702
|
+
if (resolved.directives.noContextLabels !== true) {
|
|
48703
|
+
for (const l of labels) {
|
|
48704
|
+
if (l.hidden) continue;
|
|
48705
|
+
const w = labelW(l.text);
|
|
48706
|
+
const x = l.anchor === "start" ? l.x : l.anchor === "end" ? l.x - w : l.x - w / 2;
|
|
48707
|
+
obstacles.push({ x, y: l.y - labelH / 2, w, h: labelH });
|
|
48708
|
+
}
|
|
48709
|
+
for (const box of insets)
|
|
48710
|
+
obstacles.push({ x: box.x, y: box.y, w: box.w, h: box.h });
|
|
48711
|
+
const countryCandidates = [];
|
|
48712
|
+
for (const f of worldLayer.values()) {
|
|
48713
|
+
const iso = typeof f.id === "string" ? f.id : String(f.id ?? "");
|
|
48714
|
+
if (!iso || regionById.has(iso)) continue;
|
|
48715
|
+
let hasReferencedSub = false;
|
|
48716
|
+
for (const k of regionById.keys())
|
|
48717
|
+
if (k.startsWith(iso + "-")) {
|
|
48718
|
+
hasReferencedSub = true;
|
|
48719
|
+
break;
|
|
47493
48720
|
}
|
|
48721
|
+
if (hasReferencedSub) continue;
|
|
48722
|
+
const b = path.bounds(f);
|
|
48723
|
+
const [x0, y0] = b[0];
|
|
48724
|
+
const [x1, y1] = b[1];
|
|
48725
|
+
if (!Number.isFinite(x0) || !Number.isFinite(x1)) continue;
|
|
48726
|
+
const anchorLngLat = WORLD_LABEL_ANCHORS[iso];
|
|
48727
|
+
const a = anchorLngLat ? project(anchorLngLat[0], anchorLngLat[1]) : path.centroid(f);
|
|
48728
|
+
countryCandidates.push({
|
|
48729
|
+
name: f.properties?.name ?? iso,
|
|
48730
|
+
bbox: [x0, y0, x1, y1],
|
|
48731
|
+
anchor: a && Number.isFinite(a[0]) ? [a[0], a[1]] : null
|
|
48732
|
+
});
|
|
48733
|
+
}
|
|
48734
|
+
const framedStateContainers = (resolved.poiFrameContainers ?? []).some(
|
|
48735
|
+
(id) => id.startsWith("US-")
|
|
48736
|
+
);
|
|
48737
|
+
if (usLayer && framedStateContainers) {
|
|
48738
|
+
const containerSet = new Set(resolved.poiFrameContainers);
|
|
48739
|
+
for (const [iso, f] of usLayer) {
|
|
48740
|
+
if (containerSet.has(iso) || regionById.has(iso)) continue;
|
|
48741
|
+
const viewF = cullFeatureToView(f);
|
|
48742
|
+
if (!viewF) continue;
|
|
48743
|
+
const b = path.bounds(viewF);
|
|
48744
|
+
const [x0, y0] = b[0];
|
|
48745
|
+
const [x1, y1] = b[1];
|
|
48746
|
+
if (!Number.isFinite(x0) || !Number.isFinite(x1)) continue;
|
|
48747
|
+
const a = path.centroid(viewF);
|
|
48748
|
+
countryCandidates.push({
|
|
48749
|
+
name: f.properties?.name ?? iso,
|
|
48750
|
+
bbox: [x0, y0, x1, y1],
|
|
48751
|
+
anchor: a && Number.isFinite(a[0]) ? [a[0], a[1]] : null
|
|
48752
|
+
});
|
|
47494
48753
|
}
|
|
47495
|
-
placeColumn(g);
|
|
47496
48754
|
}
|
|
48755
|
+
const contextLabels = placeContextLabels({
|
|
48756
|
+
projection: resolved.projection,
|
|
48757
|
+
dLonSpan,
|
|
48758
|
+
dLatSpan,
|
|
48759
|
+
width,
|
|
48760
|
+
height,
|
|
48761
|
+
waterBodies: data.waterBodies,
|
|
48762
|
+
countries: countryCandidates,
|
|
48763
|
+
palette,
|
|
48764
|
+
project,
|
|
48765
|
+
collides,
|
|
48766
|
+
// Water labels must stay over open water — `fillAt` returns the ocean
|
|
48767
|
+
// backdrop colour off-land and a region fill on-land (lakes/states count
|
|
48768
|
+
// as land here, which is the safe side for an ocean name).
|
|
48769
|
+
overLand: (x, y) => fillAt(x, y) !== water
|
|
48770
|
+
});
|
|
48771
|
+
labels.push(...contextLabels);
|
|
47497
48772
|
}
|
|
47498
48773
|
let legend = null;
|
|
47499
48774
|
if (!resolved.directives.noLegend) {
|
|
@@ -47528,24 +48803,35 @@ function layoutMap(resolved, data, size, opts) {
|
|
|
47528
48803
|
...resolved.caption !== void 0 && { caption: resolved.caption },
|
|
47529
48804
|
regions,
|
|
47530
48805
|
rivers,
|
|
48806
|
+
relief,
|
|
48807
|
+
reliefHatch,
|
|
48808
|
+
coastlineStyle,
|
|
47531
48809
|
legs,
|
|
47532
48810
|
pois,
|
|
48811
|
+
clusters,
|
|
47533
48812
|
labels,
|
|
47534
48813
|
legend,
|
|
47535
48814
|
insets,
|
|
47536
|
-
insetRegions
|
|
48815
|
+
insetRegions,
|
|
48816
|
+
projection,
|
|
48817
|
+
stretch: stretchParams,
|
|
48818
|
+
diagnostics: []
|
|
47537
48819
|
};
|
|
47538
48820
|
}
|
|
47539
|
-
var import_d3_geo2, import_topojson_client2, FIT_PAD, RAMP_FLOOR, R_DEFAULT, R_MIN, R_MAX, W_MIN, W_MAX,
|
|
48821
|
+
var import_d3_geo2, import_topojson_client2, FIT_PAD, RAMP_FLOOR, R_DEFAULT, R_MIN, R_MAX, W_MIN, W_MAX, FONT2, MAX_CLUSTER_EXTENT_FACTOR, MAX_COLUMN_ROWS, REGION_LABEL_HALO_RATIO, LAND_TINT_LIGHT, LAND_TINT_DARK, TAG_TINT_LIGHT, TAG_TINT_DARK, WATER_TINT_LIGHT, WATER_TINT_DARK, RIVER_WIDTH, COMPACT_WIDTH_PX, RELIEF_MIN_AREA, RELIEF_MIN_DIM, RELIEF_HATCH_SPACING, RELIEF_HATCH_WIDTH, RELIEF_HATCH_STRENGTH, COASTLINE_RING_COUNT, COASTLINE_D0, COASTLINE_STEP, COASTLINE_THICKNESS, COASTLINE_OPACITY_NEAR, COASTLINE_OPACITY_FAR, COASTLINE_MIN_EXTENT, COASTLINE_MIN_EXTENT_GLOBAL, COASTLINE_STROKE_MIX, FOREIGN_TINT_LIGHT, FOREIGN_TINT_DARK, MUTED_FOREIGN_LIGHT, MUTED_FOREIGN_DARK, COLO_R, GOLDEN_ANGLE, STACK_OVERLAP, STACK_RING_MAX, STACK_RING_GAP, FAN_STEP, ARC_CURVE_FRAC, decodeCache, usConusProjection, alaskaProjection, hawaiiProjection, INSET_STATES, inAlaska, inHawaii, FOREIGN_BORDER, US_NON_CONUS;
|
|
47540
48822
|
var init_layout15 = __esm({
|
|
47541
48823
|
"src/map/layout.ts"() {
|
|
47542
48824
|
"use strict";
|
|
47543
48825
|
import_d3_geo2 = require("d3-geo");
|
|
47544
48826
|
import_topojson_client2 = require("topojson-client");
|
|
47545
48827
|
init_color_utils();
|
|
48828
|
+
init_geo();
|
|
48829
|
+
init_colorize();
|
|
48830
|
+
init_colors();
|
|
47546
48831
|
init_label_layout();
|
|
47547
48832
|
init_legend_constants();
|
|
47548
48833
|
init_title_constants();
|
|
48834
|
+
init_context_labels();
|
|
47549
48835
|
FIT_PAD = 24;
|
|
47550
48836
|
RAMP_FLOOR = 15;
|
|
47551
48837
|
R_DEFAULT = 6;
|
|
@@ -47553,29 +48839,66 @@ var init_layout15 = __esm({
|
|
|
47553
48839
|
R_MAX = 22;
|
|
47554
48840
|
W_MIN = 1.25;
|
|
47555
48841
|
W_MAX = 8;
|
|
47556
|
-
|
|
47557
|
-
|
|
47558
|
-
|
|
47559
|
-
|
|
48842
|
+
FONT2 = 11;
|
|
48843
|
+
MAX_CLUSTER_EXTENT_FACTOR = 0.18;
|
|
48844
|
+
MAX_COLUMN_ROWS = 7;
|
|
48845
|
+
REGION_LABEL_HALO_RATIO = 4.5;
|
|
48846
|
+
LAND_TINT_LIGHT = 12;
|
|
48847
|
+
LAND_TINT_DARK = 24;
|
|
47560
48848
|
TAG_TINT_LIGHT = 60;
|
|
47561
48849
|
TAG_TINT_DARK = 68;
|
|
47562
|
-
|
|
48850
|
+
WATER_TINT_LIGHT = 24;
|
|
48851
|
+
WATER_TINT_DARK = 24;
|
|
47563
48852
|
RIVER_WIDTH = 1.3;
|
|
48853
|
+
COMPACT_WIDTH_PX = 480;
|
|
48854
|
+
RELIEF_MIN_AREA = 12;
|
|
48855
|
+
RELIEF_MIN_DIM = 2;
|
|
48856
|
+
RELIEF_HATCH_SPACING = 2;
|
|
48857
|
+
RELIEF_HATCH_WIDTH = 0.15;
|
|
48858
|
+
RELIEF_HATCH_STRENGTH = 32;
|
|
48859
|
+
COASTLINE_RING_COUNT = 5;
|
|
48860
|
+
COASTLINE_D0 = 16e-4;
|
|
48861
|
+
COASTLINE_STEP = 28e-4;
|
|
48862
|
+
COASTLINE_THICKNESS = 14e-4;
|
|
48863
|
+
COASTLINE_OPACITY_NEAR = 0.5;
|
|
48864
|
+
COASTLINE_OPACITY_FAR = 0.1;
|
|
48865
|
+
COASTLINE_MIN_EXTENT = 6e-4;
|
|
48866
|
+
COASTLINE_MIN_EXTENT_GLOBAL = 6e-4;
|
|
48867
|
+
COASTLINE_STROKE_MIX = 32;
|
|
47564
48868
|
FOREIGN_TINT_LIGHT = 30;
|
|
47565
48869
|
FOREIGN_TINT_DARK = 62;
|
|
47566
|
-
MUTED_WATER_LIGHT = 14;
|
|
47567
|
-
MUTED_WATER_DARK = 10;
|
|
47568
48870
|
MUTED_FOREIGN_LIGHT = 28;
|
|
47569
48871
|
MUTED_FOREIGN_DARK = 16;
|
|
47570
|
-
MUTED_LAND_DARK = 24;
|
|
47571
48872
|
COLO_R = 9;
|
|
47572
48873
|
GOLDEN_ANGLE = 2.399963229728653;
|
|
48874
|
+
STACK_OVERLAP = 1;
|
|
48875
|
+
STACK_RING_MAX = 8;
|
|
48876
|
+
STACK_RING_GAP = 4;
|
|
47573
48877
|
FAN_STEP = 16;
|
|
47574
48878
|
ARC_CURVE_FRAC = 0.18;
|
|
48879
|
+
decodeCache = /* @__PURE__ */ new WeakMap();
|
|
47575
48880
|
usConusProjection = () => (0, import_d3_geo2.geoConicEqualArea)().parallels([29.5, 45.5]).rotate([96, 0]);
|
|
47576
48881
|
alaskaProjection = () => (0, import_d3_geo2.geoConicEqualArea)().rotate([154, 0]).center([-2, 58.5]).parallels([55, 65]);
|
|
47577
48882
|
hawaiiProjection = () => (0, import_d3_geo2.geoMercator)();
|
|
47578
48883
|
INSET_STATES = /* @__PURE__ */ new Set(["US-AK", "US-HI"]);
|
|
48884
|
+
inAlaska = (lon, lat) => lat >= 51 && (lon <= -129 || lon >= 172);
|
|
48885
|
+
inHawaii = (lon, lat) => lat >= 18 && lat <= 23 && lon >= -161 && lon <= -154;
|
|
48886
|
+
FOREIGN_BORDER = {
|
|
48887
|
+
CA: [
|
|
48888
|
+
"US-AK",
|
|
48889
|
+
"US-WA",
|
|
48890
|
+
"US-ID",
|
|
48891
|
+
"US-MT",
|
|
48892
|
+
"US-ND",
|
|
48893
|
+
"US-MN",
|
|
48894
|
+
"US-MI",
|
|
48895
|
+
"US-NY",
|
|
48896
|
+
"US-VT",
|
|
48897
|
+
"US-NH",
|
|
48898
|
+
"US-ME"
|
|
48899
|
+
],
|
|
48900
|
+
MX: ["US-CA", "US-AZ", "US-NM", "US-TX"]
|
|
48901
|
+
};
|
|
47579
48902
|
US_NON_CONUS = /* @__PURE__ */ new Set([
|
|
47580
48903
|
"US-AK",
|
|
47581
48904
|
"US-HI",
|
|
@@ -47594,6 +48917,58 @@ __export(renderer_exports16, {
|
|
|
47594
48917
|
renderMap: () => renderMap,
|
|
47595
48918
|
renderMapForExport: () => renderMapForExport
|
|
47596
48919
|
});
|
|
48920
|
+
function pointInRing2(px, py, ring) {
|
|
48921
|
+
let inside = false;
|
|
48922
|
+
for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
|
|
48923
|
+
const [xi, yi] = ring[i];
|
|
48924
|
+
const [xj, yj] = ring[j];
|
|
48925
|
+
if (yi > py !== yj > py && px < (xj - xi) * (py - yi) / (yj - yi) + xi)
|
|
48926
|
+
inside = !inside;
|
|
48927
|
+
}
|
|
48928
|
+
return inside;
|
|
48929
|
+
}
|
|
48930
|
+
function ringToPath(ring) {
|
|
48931
|
+
let d = "";
|
|
48932
|
+
for (let i = 0; i < ring.length; i++)
|
|
48933
|
+
d += (i ? "L" : "M") + ring[i][0] + "," + ring[i][1];
|
|
48934
|
+
return d + "Z";
|
|
48935
|
+
}
|
|
48936
|
+
function coastlineOuterRings(regions, minExtent) {
|
|
48937
|
+
const paths = [];
|
|
48938
|
+
for (const r of regions) {
|
|
48939
|
+
const rings = parsePathRings(r.d);
|
|
48940
|
+
for (let i = 0; i < rings.length; i++) {
|
|
48941
|
+
const ring = rings[i];
|
|
48942
|
+
if (ring.length < 3) continue;
|
|
48943
|
+
let minX = Infinity;
|
|
48944
|
+
let minY = Infinity;
|
|
48945
|
+
let maxX = -Infinity;
|
|
48946
|
+
let maxY = -Infinity;
|
|
48947
|
+
for (const [x, y] of ring) {
|
|
48948
|
+
if (x < minX) minX = x;
|
|
48949
|
+
if (x > maxX) maxX = x;
|
|
48950
|
+
if (y < minY) minY = y;
|
|
48951
|
+
if (y > maxY) maxY = y;
|
|
48952
|
+
}
|
|
48953
|
+
if (Math.max(maxX - minX, maxY - minY) < minExtent) continue;
|
|
48954
|
+
const [fx, fy] = ring[0];
|
|
48955
|
+
let depth = 0;
|
|
48956
|
+
for (let j = 0; j < rings.length; j++)
|
|
48957
|
+
if (j !== i && pointInRing2(fx, fy, rings[j])) depth++;
|
|
48958
|
+
if (depth % 2 === 1) continue;
|
|
48959
|
+
paths.push(ringToPath(ring));
|
|
48960
|
+
}
|
|
48961
|
+
}
|
|
48962
|
+
return paths;
|
|
48963
|
+
}
|
|
48964
|
+
function appendWaterLines(g, outerRings, style, flatWater) {
|
|
48965
|
+
const d = outerRings.join(" ");
|
|
48966
|
+
const linesOuterFirst = [...style.lines].sort((a, b) => b.d - a.d);
|
|
48967
|
+
for (const line12 of linesOuterFirst) {
|
|
48968
|
+
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");
|
|
48969
|
+
g.append("path").attr("d", d).attr("stroke", flatWater).attr("stroke-width", 2 * line12.d).attr("stroke-linejoin", "round").attr("stroke-linecap", "round");
|
|
48970
|
+
}
|
|
48971
|
+
}
|
|
47597
48972
|
function renderMap(container, resolved, data, palette, isDark, onClickItem, exportDims, activeGroupOverride) {
|
|
47598
48973
|
d3Selection18.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
47599
48974
|
const width = exportDims?.width ?? container.clientWidth;
|
|
@@ -47606,6 +48981,11 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47606
48981
|
{
|
|
47607
48982
|
palette,
|
|
47608
48983
|
isDark,
|
|
48984
|
+
// Export-only: forward the contain-fit request from mapExportDimensions so a
|
|
48985
|
+
// clamped/floored (off-aspect) export canvas letterboxes instead of
|
|
48986
|
+
// stretch-distorting. The in-app preview pane passes no exportDims → unset →
|
|
48987
|
+
// keeps the global stretch-fill.
|
|
48988
|
+
preferContain: exportDims?.preferContain ?? false,
|
|
47609
48989
|
...activeGroupOverride !== void 0 && {
|
|
47610
48990
|
activeGroup: activeGroupOverride
|
|
47611
48991
|
}
|
|
@@ -47619,6 +48999,7 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47619
48999
|
const gRegions = svg.append("g").attr("class", "dgmo-map-regions");
|
|
47620
49000
|
const drawRegion = (g, r, strokeWidth) => {
|
|
47621
49001
|
const p = g.append("path").attr("d", r.d).attr("fill", r.fill).attr("stroke", r.stroke).attr("stroke-width", strokeWidth);
|
|
49002
|
+
if (r.label) p.attr("data-region-name", r.label);
|
|
47622
49003
|
if (r.layer !== "base") {
|
|
47623
49004
|
p.classed("dgmo-map-region", true).attr("data-region", r.id);
|
|
47624
49005
|
if (r.value !== void 0) p.attr("data-value", r.value);
|
|
@@ -47639,6 +49020,52 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47639
49020
|
}
|
|
47640
49021
|
};
|
|
47641
49022
|
for (const r of layout.regions) drawRegion(gRegions, r, 0.5);
|
|
49023
|
+
if (layout.relief.length && layout.reliefHatch) {
|
|
49024
|
+
const h = layout.reliefHatch;
|
|
49025
|
+
const rangeClipId = "dgmo-relief-clip";
|
|
49026
|
+
const landClipId = "dgmo-relief-land";
|
|
49027
|
+
const rangeClip = defs.append("clipPath").attr("id", rangeClipId);
|
|
49028
|
+
for (const s of layout.relief) rangeClip.append("path").attr("d", s.d);
|
|
49029
|
+
const landClip = defs.append("clipPath").attr("id", landClipId);
|
|
49030
|
+
for (const r of layout.regions)
|
|
49031
|
+
if (r.id !== "lake") landClip.append("path").attr("d", r.d);
|
|
49032
|
+
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");
|
|
49033
|
+
for (let y = h.spacing; y < height; y += h.spacing) {
|
|
49034
|
+
gRelief.append("line").attr("x1", 0).attr("y1", y).attr("x2", width).attr("y2", y);
|
|
49035
|
+
}
|
|
49036
|
+
}
|
|
49037
|
+
if (layout.coastlineStyle) {
|
|
49038
|
+
const cs = layout.coastlineStyle;
|
|
49039
|
+
const maskId = "dgmo-map-water-mask";
|
|
49040
|
+
const mask = defs.append("mask").attr("id", maskId).attr("maskUnits", "userSpaceOnUse").attr("x", 0).attr("y", 0).attr("width", width).attr("height", height);
|
|
49041
|
+
mask.append("rect").attr("x", 0).attr("y", 0).attr("width", width).attr("height", height).attr("fill", "white");
|
|
49042
|
+
const landD = layout.regions.filter((r) => r.id !== "lake").map((r) => r.d).join(" ");
|
|
49043
|
+
const lakeD = layout.regions.filter((r) => r.id === "lake").map((r) => r.d).join(" ");
|
|
49044
|
+
if (landD) mask.append("path").attr("d", landD).attr("fill", "black");
|
|
49045
|
+
if (lakeD) mask.append("path").attr("d", lakeD).attr("fill", "white");
|
|
49046
|
+
if (layout.insets.length) {
|
|
49047
|
+
const reach = Math.max(0, ...cs.lines.map((l) => l.d + l.thickness));
|
|
49048
|
+
for (const box of layout.insets) {
|
|
49049
|
+
const d = box.points.map((p, i) => `${i ? "L" : "M"}${p[0]},${p[1]}`).join("") + "Z";
|
|
49050
|
+
mask.append("path").attr("d", d).attr("fill", "black").attr("stroke", "black").attr("stroke-width", 2 * reach).attr("stroke-linejoin", "round");
|
|
49051
|
+
}
|
|
49052
|
+
}
|
|
49053
|
+
const gWater = svg.append("g").attr("class", "dgmo-map-water-lines").attr("fill", "none").attr("mask", `url(#${maskId})`);
|
|
49054
|
+
appendWaterLines(
|
|
49055
|
+
gWater,
|
|
49056
|
+
coastlineOuterRings(layout.regions, cs.minExtent),
|
|
49057
|
+
cs,
|
|
49058
|
+
layout.background
|
|
49059
|
+
);
|
|
49060
|
+
const byStroke = /* @__PURE__ */ new Map();
|
|
49061
|
+
for (const r of layout.regions) {
|
|
49062
|
+
const arr = byStroke.get(r.stroke);
|
|
49063
|
+
if (arr) arr.push(r.d);
|
|
49064
|
+
else byStroke.set(r.stroke, [r.d]);
|
|
49065
|
+
}
|
|
49066
|
+
for (const [stroke2, ds] of byStroke)
|
|
49067
|
+
gWater.append("path").attr("d", ds.join(" ")).attr("stroke", stroke2).attr("stroke-width", 0.5).attr("stroke-linejoin", "round");
|
|
49068
|
+
}
|
|
47642
49069
|
if (layout.rivers.length) {
|
|
47643
49070
|
const gRivers = svg.append("g").attr("class", "dgmo-map-rivers").attr("fill", "none");
|
|
47644
49071
|
for (const r of layout.rivers) {
|
|
@@ -47647,15 +49074,61 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47647
49074
|
}
|
|
47648
49075
|
if (layout.insets.length) {
|
|
47649
49076
|
const insetG = svg.append("g").attr("class", "dgmo-map-insets");
|
|
47650
|
-
|
|
49077
|
+
layout.insets.forEach((box, bi) => {
|
|
47651
49078
|
const d = box.points.map((p, i) => `${i ? "L" : "M"}${p[0]},${p[1]}`).join("") + "Z";
|
|
47652
49079
|
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");
|
|
47653
|
-
|
|
49080
|
+
if (box.contextLand) {
|
|
49081
|
+
const clipId = `dgmo-map-inset-clip-${bi}`;
|
|
49082
|
+
defs.append("clipPath").attr("id", clipId).append("path").attr("d", d);
|
|
49083
|
+
insetG.append("path").attr("d", box.contextLand.d).attr("fill", box.contextLand.fill).attr("clip-path", `url(#${clipId})`);
|
|
49084
|
+
}
|
|
49085
|
+
});
|
|
47654
49086
|
for (const r of layout.insetRegions) drawRegion(insetG, r, 0.5);
|
|
47655
|
-
|
|
49087
|
+
if (layout.coastlineStyle) {
|
|
49088
|
+
const cs = layout.coastlineStyle;
|
|
49089
|
+
const maskId = "dgmo-map-inset-water-mask";
|
|
49090
|
+
const mask = defs.append("mask").attr("id", maskId).attr("maskUnits", "userSpaceOnUse").attr("x", 0).attr("y", 0).attr("width", width).attr("height", height);
|
|
49091
|
+
for (const box of layout.insets) {
|
|
49092
|
+
const d = box.points.map((p, i) => `${i ? "L" : "M"}${p[0]},${p[1]}`).join("") + "Z";
|
|
49093
|
+
mask.append("path").attr("d", d).attr("fill", "white");
|
|
49094
|
+
}
|
|
49095
|
+
layout.insets.forEach((box, bi) => {
|
|
49096
|
+
if (box.contextLand)
|
|
49097
|
+
mask.append("path").attr("d", box.contextLand.d).attr("fill", "black").attr("clip-path", `url(#dgmo-map-inset-clip-${bi})`);
|
|
49098
|
+
});
|
|
49099
|
+
for (const r of layout.insetRegions)
|
|
49100
|
+
if (r.id !== "lake")
|
|
49101
|
+
mask.append("path").attr("d", r.d).attr("fill", "black");
|
|
49102
|
+
for (const r of layout.insetRegions)
|
|
49103
|
+
if (r.id === "lake")
|
|
49104
|
+
mask.append("path").attr("d", r.d).attr("fill", "white");
|
|
49105
|
+
const clipId = "dgmo-map-inset-water-clip";
|
|
49106
|
+
const clip = defs.append("clipPath").attr("id", clipId);
|
|
49107
|
+
for (const box of layout.insets) {
|
|
49108
|
+
const d = box.points.map((p, i) => `${i ? "L" : "M"}${p[0]},${p[1]}`).join("") + "Z";
|
|
49109
|
+
clip.append("path").attr("d", d);
|
|
49110
|
+
}
|
|
49111
|
+
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})`);
|
|
49112
|
+
appendWaterLines(
|
|
49113
|
+
gInsetWater,
|
|
49114
|
+
coastlineOuterRings(layout.insetRegions, cs.minExtent),
|
|
49115
|
+
cs,
|
|
49116
|
+
layout.background
|
|
49117
|
+
);
|
|
49118
|
+
for (const r of layout.insetRegions)
|
|
49119
|
+
gInsetWater.append("path").attr("d", r.d).attr("stroke", r.stroke).attr("stroke-width", 0.5).attr("stroke-linejoin", "round");
|
|
49120
|
+
}
|
|
49121
|
+
}
|
|
49122
|
+
const wireSync = (sel, lineNumber) => {
|
|
49123
|
+
if (lineNumber < 1) return;
|
|
49124
|
+
sel.attr("data-line-number", lineNumber);
|
|
49125
|
+
if (onClickItem)
|
|
49126
|
+
sel.style("cursor", "pointer").on("click", () => onClickItem(lineNumber));
|
|
49127
|
+
};
|
|
47656
49128
|
const gLegs = svg.append("g").attr("class", "dgmo-map-legs").attr("fill", "none");
|
|
47657
49129
|
layout.legs.forEach((leg, i) => {
|
|
47658
49130
|
const p = gLegs.append("path").attr("d", leg.d).attr("stroke", leg.color).attr("stroke-width", leg.width).attr("stroke-linecap", "round");
|
|
49131
|
+
wireSync(p, leg.lineNumber);
|
|
47659
49132
|
if (leg.arrow) {
|
|
47660
49133
|
const id = `dgmo-map-arrow-${i}`;
|
|
47661
49134
|
const s = arrowSize(leg.width);
|
|
@@ -47663,25 +49136,38 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47663
49136
|
p.attr("marker-end", `url(#${id})`);
|
|
47664
49137
|
}
|
|
47665
49138
|
if (leg.label !== void 0 && leg.labelX !== void 0) {
|
|
47666
|
-
emitText(
|
|
49139
|
+
const lt = emitText(
|
|
47667
49140
|
gLegs,
|
|
47668
49141
|
leg.labelX,
|
|
47669
49142
|
leg.labelY ?? 0,
|
|
47670
49143
|
leg.label,
|
|
47671
49144
|
"middle",
|
|
47672
|
-
palette.textMuted,
|
|
47673
|
-
haloColor,
|
|
47674
|
-
true,
|
|
49145
|
+
leg.labelColor ?? palette.textMuted,
|
|
49146
|
+
leg.labelHaloColor ?? haloColor,
|
|
49147
|
+
leg.labelHalo ?? true,
|
|
47675
49148
|
LABEL_FONT - 1
|
|
47676
49149
|
);
|
|
49150
|
+
wireSync(lt, leg.lineNumber);
|
|
47677
49151
|
}
|
|
47678
49152
|
});
|
|
49153
|
+
const gSpider = svg.append("g").attr("class", "dgmo-map-spider");
|
|
49154
|
+
for (const cl of layout.clusters) {
|
|
49155
|
+
if (!exportDims) {
|
|
49156
|
+
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");
|
|
49157
|
+
}
|
|
49158
|
+
for (const leg of cl.legs) {
|
|
49159
|
+
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");
|
|
49160
|
+
}
|
|
49161
|
+
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");
|
|
49162
|
+
}
|
|
47679
49163
|
const gPois = svg.append("g").attr("class", "dgmo-map-pois");
|
|
47680
49164
|
for (const poi of layout.pois) {
|
|
47681
49165
|
if (poi.isOrigin) {
|
|
47682
49166
|
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);
|
|
47683
49167
|
}
|
|
47684
49168
|
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);
|
|
49169
|
+
if (poi.clusterId !== void 0)
|
|
49170
|
+
c.attr("data-cluster-member", poi.clusterId);
|
|
47685
49171
|
if (poi.tags) {
|
|
47686
49172
|
for (const [group, value] of Object.entries(poi.tags)) {
|
|
47687
49173
|
c.attr(`data-tag-${group.toLowerCase()}`, value.toLowerCase());
|
|
@@ -47709,12 +49195,32 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47709
49195
|
}
|
|
47710
49196
|
const gLabels = svg.append("g").attr("class", "dgmo-map-labels");
|
|
47711
49197
|
for (const lab of layout.labels) {
|
|
49198
|
+
if (lab.hidden) {
|
|
49199
|
+
if (exportDims) continue;
|
|
49200
|
+
emitText(
|
|
49201
|
+
gLabels,
|
|
49202
|
+
lab.x,
|
|
49203
|
+
lab.y,
|
|
49204
|
+
lab.text,
|
|
49205
|
+
lab.anchor,
|
|
49206
|
+
lab.color,
|
|
49207
|
+
lab.haloColor,
|
|
49208
|
+
lab.halo,
|
|
49209
|
+
LABEL_FONT,
|
|
49210
|
+
lab.italic,
|
|
49211
|
+
lab.letterSpacing
|
|
49212
|
+
).attr("data-poi", lab.poiId ?? null).attr("data-poi-hidden", "").style("opacity", 0).style("pointer-events", "none");
|
|
49213
|
+
continue;
|
|
49214
|
+
}
|
|
47712
49215
|
if (lab.leader) {
|
|
47713
49216
|
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(
|
|
47714
49217
|
"stroke",
|
|
47715
49218
|
lab.leaderColor ?? mix(palette.textMuted, palette.bg, 60)
|
|
47716
49219
|
).attr("stroke-width", lab.leaderColor ? 1 : 0.75);
|
|
47717
49220
|
if (lab.poiId !== void 0) line12.attr("data-poi", lab.poiId);
|
|
49221
|
+
if (lab.clusterMember !== void 0)
|
|
49222
|
+
line12.attr("data-cluster-member", lab.clusterMember);
|
|
49223
|
+
wireSync(line12, lab.lineNumber);
|
|
47718
49224
|
}
|
|
47719
49225
|
const t = emitText(
|
|
47720
49226
|
gLabels,
|
|
@@ -47725,11 +49231,38 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47725
49231
|
lab.color,
|
|
47726
49232
|
lab.haloColor,
|
|
47727
49233
|
lab.halo,
|
|
47728
|
-
LABEL_FONT
|
|
49234
|
+
LABEL_FONT,
|
|
49235
|
+
lab.italic,
|
|
49236
|
+
lab.letterSpacing,
|
|
49237
|
+
lab.lines
|
|
47729
49238
|
);
|
|
47730
49239
|
if (lab.poiId !== void 0) {
|
|
47731
49240
|
t.attr("data-poi", lab.poiId).style("cursor", "default");
|
|
47732
49241
|
}
|
|
49242
|
+
if (lab.clusterMember !== void 0) {
|
|
49243
|
+
t.attr("data-cluster-member", lab.clusterMember);
|
|
49244
|
+
}
|
|
49245
|
+
wireSync(t, lab.lineNumber);
|
|
49246
|
+
}
|
|
49247
|
+
if (!exportDims && layout.clusters.length) {
|
|
49248
|
+
const gBadge = svg.append("g").attr("class", "dgmo-map-cluster-badges");
|
|
49249
|
+
for (const cl of layout.clusters) {
|
|
49250
|
+
const g = gBadge.append("g").attr("data-cluster", cl.id).style("opacity", 0).style("pointer-events", "none");
|
|
49251
|
+
const R = 9;
|
|
49252
|
+
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);
|
|
49253
|
+
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);
|
|
49254
|
+
emitText(
|
|
49255
|
+
g,
|
|
49256
|
+
cl.cx,
|
|
49257
|
+
cl.cy + 3,
|
|
49258
|
+
String(cl.count),
|
|
49259
|
+
"middle",
|
|
49260
|
+
palette.text,
|
|
49261
|
+
palette.bg,
|
|
49262
|
+
false,
|
|
49263
|
+
LABEL_FONT
|
|
49264
|
+
);
|
|
49265
|
+
}
|
|
47733
49266
|
}
|
|
47734
49267
|
if (layout.legend) {
|
|
47735
49268
|
const legendY = (layout.title ? TITLE_Y + TITLE_FONT_SIZE : 0) + (layout.subtitle ? TITLE_FONT_SIZE : 0) + 8;
|
|
@@ -47763,10 +49296,10 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47763
49296
|
}
|
|
47764
49297
|
}
|
|
47765
49298
|
if (layout.title) {
|
|
47766
|
-
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);
|
|
49299
|
+
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);
|
|
47767
49300
|
}
|
|
47768
49301
|
if (layout.subtitle) {
|
|
47769
|
-
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);
|
|
49302
|
+
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);
|
|
47770
49303
|
}
|
|
47771
49304
|
if (layout.caption) {
|
|
47772
49305
|
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);
|
|
@@ -47775,10 +49308,21 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
|
|
|
47775
49308
|
function renderMapForExport(container, resolved, data, palette, isDark, exportDims) {
|
|
47776
49309
|
renderMap(container, resolved, data, palette, isDark, void 0, exportDims);
|
|
47777
49310
|
}
|
|
47778
|
-
function emitText(g, x, y, text, anchor, color, halo, withHalo, fontSize) {
|
|
47779
|
-
const t = g.append("text").attr("x", x).attr("y", y).attr("text-anchor", anchor).attr("font-size", fontSize).attr("fill", color)
|
|
49311
|
+
function emitText(g, x, y, text, anchor, color, halo, withHalo, fontSize, italic, letterSpacing, lines) {
|
|
49312
|
+
const t = g.append("text").attr("x", x).attr("y", y).attr("text-anchor", anchor).attr("font-size", fontSize).attr("fill", color);
|
|
49313
|
+
if (lines && lines.length > 1) {
|
|
49314
|
+
const lineHeight = fontSize + 2;
|
|
49315
|
+
const startDy = -((lines.length - 1) / 2) * lineHeight;
|
|
49316
|
+
lines.forEach((ln, i) => {
|
|
49317
|
+
t.append("tspan").attr("x", x).attr("dy", i === 0 ? startDy : lineHeight).text(ln);
|
|
49318
|
+
});
|
|
49319
|
+
} else {
|
|
49320
|
+
t.text(text);
|
|
49321
|
+
}
|
|
49322
|
+
if (italic) t.attr("font-style", "italic");
|
|
49323
|
+
if (letterSpacing) t.attr("letter-spacing", letterSpacing);
|
|
47780
49324
|
if (withHalo) {
|
|
47781
|
-
t.attr("paint-order", "stroke fill").attr("stroke", halo).attr("stroke-width",
|
|
49325
|
+
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);
|
|
47782
49326
|
}
|
|
47783
49327
|
return t;
|
|
47784
49328
|
}
|
|
@@ -47796,6 +49340,179 @@ var init_renderer16 = __esm({
|
|
|
47796
49340
|
}
|
|
47797
49341
|
});
|
|
47798
49342
|
|
|
49343
|
+
// src/map/dimensions.ts
|
|
49344
|
+
var dimensions_exports = {};
|
|
49345
|
+
__export(dimensions_exports, {
|
|
49346
|
+
mapContentAspect: () => mapContentAspect,
|
|
49347
|
+
mapExportDimensions: () => mapExportDimensions
|
|
49348
|
+
});
|
|
49349
|
+
function mapContentAspect(resolved, data, ref = REF) {
|
|
49350
|
+
const { projection, fitTarget } = buildMapProjection(resolved, data);
|
|
49351
|
+
projection.fitSize([ref, ref], fitTarget);
|
|
49352
|
+
const b = (0, import_d3_geo3.geoPath)(projection).bounds(fitTarget);
|
|
49353
|
+
const w = b[1][0] - b[0][0];
|
|
49354
|
+
const h = b[1][1] - b[0][1];
|
|
49355
|
+
const aspect = w / h;
|
|
49356
|
+
return Number.isFinite(aspect) && aspect > 0 ? aspect : FALLBACK_ASPECT;
|
|
49357
|
+
}
|
|
49358
|
+
function mapExportDimensions(resolved, data, baseWidth = 1200) {
|
|
49359
|
+
const raw = mapContentAspect(resolved, data);
|
|
49360
|
+
const clamped = Math.max(ASPECT_MIN, Math.min(ASPECT_MAX, raw));
|
|
49361
|
+
const width = baseWidth;
|
|
49362
|
+
let height = Math.round(width / clamped);
|
|
49363
|
+
let chromeReserve = 0;
|
|
49364
|
+
if (resolved.title && resolved.pois.length > 0) {
|
|
49365
|
+
const bannerBottom = (resolved.subtitle ? TITLE_Y + TITLE_FONT_SIZE : TITLE_Y) + TITLE_FONT_SIZE / 2;
|
|
49366
|
+
chromeReserve += Math.max(FIT_PAD2, bannerBottom + TITLE_GAP) - FIT_PAD2;
|
|
49367
|
+
}
|
|
49368
|
+
let floored = false;
|
|
49369
|
+
if (height - chromeReserve < MIN_MAP_BAND) {
|
|
49370
|
+
height = Math.round(chromeReserve + MIN_MAP_BAND);
|
|
49371
|
+
floored = true;
|
|
49372
|
+
}
|
|
49373
|
+
const preferContain = clamped !== raw || floored;
|
|
49374
|
+
return { width, height, preferContain };
|
|
49375
|
+
}
|
|
49376
|
+
var import_d3_geo3, FIT_PAD2, TITLE_GAP, ASPECT_MAX, ASPECT_MIN, MIN_MAP_BAND, FALLBACK_ASPECT, REF;
|
|
49377
|
+
var init_dimensions = __esm({
|
|
49378
|
+
"src/map/dimensions.ts"() {
|
|
49379
|
+
"use strict";
|
|
49380
|
+
import_d3_geo3 = require("d3-geo");
|
|
49381
|
+
init_title_constants();
|
|
49382
|
+
init_layout15();
|
|
49383
|
+
FIT_PAD2 = 24;
|
|
49384
|
+
TITLE_GAP = 16;
|
|
49385
|
+
ASPECT_MAX = 3;
|
|
49386
|
+
ASPECT_MIN = 0.9;
|
|
49387
|
+
MIN_MAP_BAND = 200;
|
|
49388
|
+
FALLBACK_ASPECT = 1.5;
|
|
49389
|
+
REF = 1e3;
|
|
49390
|
+
}
|
|
49391
|
+
});
|
|
49392
|
+
|
|
49393
|
+
// src/map/load-data.ts
|
|
49394
|
+
var load_data_exports = {};
|
|
49395
|
+
__export(load_data_exports, {
|
|
49396
|
+
loadMapData: () => loadMapData
|
|
49397
|
+
});
|
|
49398
|
+
async function loadNodeBuiltins() {
|
|
49399
|
+
const [{ readFile }, { fileURLToPath }, { dirname: dirname2, resolve }] = await Promise.all([
|
|
49400
|
+
import("fs/promises"),
|
|
49401
|
+
import("url"),
|
|
49402
|
+
import("path")
|
|
49403
|
+
]);
|
|
49404
|
+
return { readFile, fileURLToPath, dirname: dirname2, resolve };
|
|
49405
|
+
}
|
|
49406
|
+
async function readJson(nb, dir, name) {
|
|
49407
|
+
return JSON.parse(await nb.readFile(nb.resolve(dir, name), "utf8"));
|
|
49408
|
+
}
|
|
49409
|
+
async function firstExistingDir(nb, baseDir) {
|
|
49410
|
+
for (const rel of CANDIDATE_DIRS) {
|
|
49411
|
+
const dir = nb.resolve(baseDir, rel);
|
|
49412
|
+
try {
|
|
49413
|
+
await nb.readFile(nb.resolve(dir, FILES.gazetteer), "utf8");
|
|
49414
|
+
return dir;
|
|
49415
|
+
} catch {
|
|
49416
|
+
}
|
|
49417
|
+
}
|
|
49418
|
+
throw new Error(
|
|
49419
|
+
`map data assets not found near ${baseDir} (looked in ${CANDIDATE_DIRS.join(", ")}). Run \`pnpm build:map-data\` and \`pnpm build\`.`
|
|
49420
|
+
);
|
|
49421
|
+
}
|
|
49422
|
+
function validate(data) {
|
|
49423
|
+
const topoOk = (t) => !!t && t.type === "Topology" && !!t.objects;
|
|
49424
|
+
if (!topoOk(data.worldCoarse) || !topoOk(data.worldDetail) || !topoOk(data.usStates) || !data.gazetteer || !Array.isArray(data.gazetteer.cities) || !data.gazetteer.byName) {
|
|
49425
|
+
throw new Error("map data assets are malformed (failed shape validation)");
|
|
49426
|
+
}
|
|
49427
|
+
return data;
|
|
49428
|
+
}
|
|
49429
|
+
function moduleBaseDir(nb) {
|
|
49430
|
+
try {
|
|
49431
|
+
const url = import_meta.url;
|
|
49432
|
+
if (url) return nb.dirname(nb.fileURLToPath(url));
|
|
49433
|
+
} catch {
|
|
49434
|
+
}
|
|
49435
|
+
if (typeof __dirname !== "undefined") return __dirname;
|
|
49436
|
+
return process.cwd();
|
|
49437
|
+
}
|
|
49438
|
+
function loadMapData() {
|
|
49439
|
+
cache ??= (async () => {
|
|
49440
|
+
const nb = await loadNodeBuiltins();
|
|
49441
|
+
const dir = await firstExistingDir(nb, moduleBaseDir(nb));
|
|
49442
|
+
const [
|
|
49443
|
+
worldCoarse,
|
|
49444
|
+
worldDetail,
|
|
49445
|
+
usStates,
|
|
49446
|
+
lakes,
|
|
49447
|
+
rivers,
|
|
49448
|
+
mountainRanges,
|
|
49449
|
+
naLand,
|
|
49450
|
+
naLakes,
|
|
49451
|
+
waterBodies,
|
|
49452
|
+
gazetteer
|
|
49453
|
+
] = await Promise.all([
|
|
49454
|
+
// worldCoarse (110m) is LOAD-BEARING but NOT a render source: the world
|
|
49455
|
+
// basemap renders from worldDetail (50m) at all scales (resolver pins
|
|
49456
|
+
// basemaps.world = 'detail'). Coarse stays as the authoritative region
|
|
49457
|
+
// name index + dominant-landmass bbox source in resolver.ts. Do not drop it.
|
|
49458
|
+
readJson(nb, dir, FILES.worldCoarse),
|
|
49459
|
+
readJson(nb, dir, FILES.worldDetail),
|
|
49460
|
+
readJson(nb, dir, FILES.usStates),
|
|
49461
|
+
// Lakes/rivers/mountain/NA/water assets are optional — older bundles may predate them.
|
|
49462
|
+
readJson(nb, dir, FILES.lakes).catch(() => void 0),
|
|
49463
|
+
readJson(nb, dir, FILES.rivers).catch(() => void 0),
|
|
49464
|
+
readJson(nb, dir, FILES.mountainRanges).catch(
|
|
49465
|
+
() => void 0
|
|
49466
|
+
),
|
|
49467
|
+
readJson(nb, dir, FILES.naLand).catch(() => void 0),
|
|
49468
|
+
readJson(nb, dir, FILES.naLakes).catch(() => void 0),
|
|
49469
|
+
readJson(nb, dir, FILES.waterBodies).catch(() => void 0),
|
|
49470
|
+
readJson(nb, dir, FILES.gazetteer)
|
|
49471
|
+
]);
|
|
49472
|
+
return validate({
|
|
49473
|
+
worldCoarse,
|
|
49474
|
+
worldDetail,
|
|
49475
|
+
usStates,
|
|
49476
|
+
gazetteer,
|
|
49477
|
+
...lakes && { lakes },
|
|
49478
|
+
...rivers && { rivers },
|
|
49479
|
+
...mountainRanges && { mountainRanges },
|
|
49480
|
+
...naLand && { naLand },
|
|
49481
|
+
...naLakes && { naLakes },
|
|
49482
|
+
...waterBodies && { waterBodies }
|
|
49483
|
+
});
|
|
49484
|
+
})().catch((e) => {
|
|
49485
|
+
cache = void 0;
|
|
49486
|
+
throw e;
|
|
49487
|
+
});
|
|
49488
|
+
return cache;
|
|
49489
|
+
}
|
|
49490
|
+
var import_meta, FILES, CANDIDATE_DIRS, cache;
|
|
49491
|
+
var init_load_data = __esm({
|
|
49492
|
+
"src/map/load-data.ts"() {
|
|
49493
|
+
"use strict";
|
|
49494
|
+
import_meta = {};
|
|
49495
|
+
FILES = {
|
|
49496
|
+
worldCoarse: "world-coarse.json",
|
|
49497
|
+
worldDetail: "world-detail.json",
|
|
49498
|
+
usStates: "us-states.json",
|
|
49499
|
+
lakes: "lakes.json",
|
|
49500
|
+
rivers: "rivers.json",
|
|
49501
|
+
mountainRanges: "mountain-ranges.json",
|
|
49502
|
+
naLand: "na-land.json",
|
|
49503
|
+
naLakes: "na-lakes.json",
|
|
49504
|
+
waterBodies: "water-bodies.json",
|
|
49505
|
+
gazetteer: "gazetteer.json"
|
|
49506
|
+
};
|
|
49507
|
+
CANDIDATE_DIRS = [
|
|
49508
|
+
"./data",
|
|
49509
|
+
"./map-data",
|
|
49510
|
+
"../map-data",
|
|
49511
|
+
"../src/map/data"
|
|
49512
|
+
];
|
|
49513
|
+
}
|
|
49514
|
+
});
|
|
49515
|
+
|
|
47799
49516
|
// src/pyramid/renderer.ts
|
|
47800
49517
|
var renderer_exports17 = {};
|
|
47801
49518
|
__export(renderer_exports17, {
|
|
@@ -49797,8 +51514,8 @@ function renderSequenceDiagram(container, parsed, palette, isDark, _onNavigateTo
|
|
|
49797
51514
|
const lines = splitParticipantLabel(p.label, LABEL_MAX_CHARS);
|
|
49798
51515
|
if (lines.length === 0) continue;
|
|
49799
51516
|
const widest = Math.max(...lines.map((l) => l.length));
|
|
49800
|
-
const
|
|
49801
|
-
uniformBoxWidth = Math.max(uniformBoxWidth,
|
|
51517
|
+
const labelWidth2 = widest * LABEL_CHAR_WIDTH + 10;
|
|
51518
|
+
uniformBoxWidth = Math.max(uniformBoxWidth, labelWidth2);
|
|
49802
51519
|
}
|
|
49803
51520
|
uniformBoxWidth = Math.min(MAX_BOX_WIDTH, uniformBoxWidth);
|
|
49804
51521
|
const effectiveGap = Math.max(PARTICIPANT_GAP, uniformBoxWidth + 30);
|
|
@@ -52493,15 +54210,15 @@ function renderArcDiagram(container, parsed, palette, _isDark, onClickItem, expo
|
|
|
52493
54210
|
textColor,
|
|
52494
54211
|
onClickItem
|
|
52495
54212
|
);
|
|
52496
|
-
const
|
|
52497
|
-
for (const node of nodes)
|
|
54213
|
+
const neighbors2 = /* @__PURE__ */ new Map();
|
|
54214
|
+
for (const node of nodes) neighbors2.set(node, /* @__PURE__ */ new Set());
|
|
52498
54215
|
for (const link of links) {
|
|
52499
|
-
|
|
52500
|
-
|
|
54216
|
+
neighbors2.get(link.source).add(link.target);
|
|
54217
|
+
neighbors2.get(link.target).add(link.source);
|
|
52501
54218
|
}
|
|
52502
54219
|
const FADE_OPACITY3 = 0.1;
|
|
52503
54220
|
function handleMouseEnter(hovered) {
|
|
52504
|
-
const connected =
|
|
54221
|
+
const connected = neighbors2.get(hovered);
|
|
52505
54222
|
g.selectAll(".arc-link").each(function() {
|
|
52506
54223
|
const el = d3Selection23.select(this);
|
|
52507
54224
|
const src = el.attr("data-source");
|
|
@@ -54492,7 +56209,7 @@ function renderVenn(container, parsed, palette, _isDark, onClickItem, exportDims
|
|
|
54492
56209
|
8,
|
|
54493
56210
|
Math.floor(OVERLAP_WRAP_TARGET_W / OVERLAP_CH_W)
|
|
54494
56211
|
);
|
|
54495
|
-
function
|
|
56212
|
+
function wrapLabel3(text, maxChars) {
|
|
54496
56213
|
const words = text.split(/\s+/).filter(Boolean);
|
|
54497
56214
|
const lines = [];
|
|
54498
56215
|
let cur = "";
|
|
@@ -54538,7 +56255,7 @@ function renderVenn(container, parsed, palette, _isDark, onClickItem, exportDims
|
|
|
54538
56255
|
if (!ov.label) continue;
|
|
54539
56256
|
const idxs = ov.sets.map((s) => vennSets.findIndex((vs) => vs.name === s));
|
|
54540
56257
|
if (idxs.some((idx) => idx < 0)) continue;
|
|
54541
|
-
const lines =
|
|
56258
|
+
const lines = wrapLabel3(ov.label, MAX_WRAP_CHARS);
|
|
54542
56259
|
wrappedOverlapLabels.set(ov, lines);
|
|
54543
56260
|
const dir = predictOverlapDirRaw(idxs);
|
|
54544
56261
|
const longest = lines.reduce((m, l) => Math.max(m, l.length), 0);
|
|
@@ -55975,25 +57692,29 @@ async function renderForExport(content, theme, palette, viewState, options) {
|
|
|
55975
57692
|
if (detectedType === "map") {
|
|
55976
57693
|
const { parseMap: parseMap2 } = await Promise.resolve().then(() => (init_parser12(), parser_exports11));
|
|
55977
57694
|
const { resolveMap: resolveMap2 } = await Promise.resolve().then(() => (init_resolver2(), resolver_exports));
|
|
55978
|
-
const { loadMapData: loadMapData2 } = await Promise.resolve().then(() => (init_load_data(), load_data_exports));
|
|
55979
57695
|
const { renderMapForExport: renderMapForExport2 } = await Promise.resolve().then(() => (init_renderer16(), renderer_exports16));
|
|
57696
|
+
const { mapExportDimensions: mapExportDimensions2 } = await Promise.resolve().then(() => (init_dimensions(), dimensions_exports));
|
|
55980
57697
|
const effectivePalette2 = await resolveExportPalette(theme, palette);
|
|
55981
57698
|
const mapParsed = parseMap2(content);
|
|
55982
|
-
let mapData;
|
|
55983
|
-
|
|
55984
|
-
|
|
55985
|
-
|
|
55986
|
-
|
|
57699
|
+
let mapData = options?.mapData;
|
|
57700
|
+
if (!mapData) {
|
|
57701
|
+
const { loadMapData: loadMapData2 } = await Promise.resolve().then(() => (init_load_data(), load_data_exports));
|
|
57702
|
+
try {
|
|
57703
|
+
mapData = await loadMapData2();
|
|
57704
|
+
} catch {
|
|
57705
|
+
return "";
|
|
57706
|
+
}
|
|
55987
57707
|
}
|
|
55988
57708
|
const mapResolved = resolveMap2(mapParsed, mapData);
|
|
55989
|
-
const
|
|
57709
|
+
const dims2 = mapExportDimensions2(mapResolved, mapData, EXPORT_WIDTH);
|
|
57710
|
+
const container2 = createExportContainer(dims2.width, dims2.height);
|
|
55990
57711
|
renderMapForExport2(
|
|
55991
57712
|
container2,
|
|
55992
57713
|
mapResolved,
|
|
55993
57714
|
mapData,
|
|
55994
57715
|
effectivePalette2,
|
|
55995
57716
|
theme === "dark",
|
|
55996
|
-
|
|
57717
|
+
dims2
|
|
55997
57718
|
);
|
|
55998
57719
|
return finalizeSvgExport(container2, theme, effectivePalette2);
|
|
55999
57720
|
}
|
|
@@ -56800,7 +58521,8 @@ __export(advanced_exports, {
|
|
|
56800
58521
|
applyCollapseProjection: () => applyCollapseProjection,
|
|
56801
58522
|
applyGroupOrdering: () => applyGroupOrdering,
|
|
56802
58523
|
applyPositionOverrides: () => applyPositionOverrides,
|
|
56803
|
-
|
|
58524
|
+
atlasPalette: () => atlasPalette,
|
|
58525
|
+
blueprintPalette: () => blueprintPalette,
|
|
56804
58526
|
buildExtendedChartOption: () => buildExtendedChartOption,
|
|
56805
58527
|
buildNoteMessageMap: () => buildNoteMessageMap,
|
|
56806
58528
|
buildRenderSequence: () => buildRenderSequence,
|
|
@@ -56834,6 +58556,7 @@ __export(advanced_exports, {
|
|
|
56834
58556
|
computeTimeTicks: () => computeTimeTicks,
|
|
56835
58557
|
contrastText: () => contrastText,
|
|
56836
58558
|
controlsGroupCapsuleWidth: () => controlsGroupCapsuleWidth,
|
|
58559
|
+
createMapGeoQuery: () => createMapGeoQuery,
|
|
56837
58560
|
decodeDiagramUrl: () => decodeDiagramUrl,
|
|
56838
58561
|
decodeViewState: () => decodeViewState,
|
|
56839
58562
|
displayName: () => displayName,
|
|
@@ -56902,6 +58625,8 @@ __export(advanced_exports, {
|
|
|
56902
58625
|
looksLikeState: () => looksLikeState,
|
|
56903
58626
|
makeDgmoError: () => makeDgmoError,
|
|
56904
58627
|
mapBackgroundColor: () => mapBackgroundColor,
|
|
58628
|
+
mapContentAspect: () => mapContentAspect,
|
|
58629
|
+
mapExportDimensions: () => mapExportDimensions,
|
|
56905
58630
|
mapNeutralLandColor: () => mapNeutralLandColor,
|
|
56906
58631
|
matchesContiguously: () => matchesContiguously,
|
|
56907
58632
|
measurePertAnalysisBlock: () => measurePertAnalysisBlock,
|
|
@@ -57037,9 +58762,11 @@ __export(advanced_exports, {
|
|
|
57037
58762
|
shapeFill: () => shapeFill,
|
|
57038
58763
|
simulateCanonical: () => simulateCanonical,
|
|
57039
58764
|
simulateFast: () => simulateFast,
|
|
58765
|
+
slatePalette: () => slatePalette,
|
|
57040
58766
|
solarizedPalette: () => solarizedPalette,
|
|
57041
58767
|
suggestChartTypes: () => suggestChartTypes,
|
|
57042
58768
|
themes: () => themes,
|
|
58769
|
+
tidewaterPalette: () => tidewaterPalette,
|
|
57043
58770
|
tint: () => tint,
|
|
57044
58771
|
tokyoNightPalette: () => tokyoNightPalette,
|
|
57045
58772
|
transformLine: () => transformLine,
|
|
@@ -57123,7 +58850,8 @@ async function render(content, options) {
|
|
|
57123
58850
|
...options?.c4Container !== void 0 && {
|
|
57124
58851
|
c4Container: options.c4Container
|
|
57125
58852
|
},
|
|
57126
|
-
...options?.tagGroup !== void 0 && { tagGroup: options.tagGroup }
|
|
58853
|
+
...options?.tagGroup !== void 0 && { tagGroup: options.tagGroup },
|
|
58854
|
+
...options?.mapData !== void 0 && { mapData: options.mapData }
|
|
57127
58855
|
});
|
|
57128
58856
|
if (chartType === "map") {
|
|
57129
58857
|
try {
|
|
@@ -57134,7 +58862,7 @@ async function render(content, options) {
|
|
|
57134
58862
|
Promise.resolve().then(() => (init_load_data(), load_data_exports))
|
|
57135
58863
|
]
|
|
57136
58864
|
);
|
|
57137
|
-
const data = await loadMapData2();
|
|
58865
|
+
const data = options?.mapData ?? await loadMapData2();
|
|
57138
58866
|
diagnostics = [...resolveMap2(parseMap2(content), data).diagnostics];
|
|
57139
58867
|
} catch {
|
|
57140
58868
|
}
|
|
@@ -57373,8 +59101,8 @@ function detectCycles(parsed) {
|
|
|
57373
59101
|
const parent = /* @__PURE__ */ new Map();
|
|
57374
59102
|
function dfs(nodeId3) {
|
|
57375
59103
|
color.set(nodeId3, 1);
|
|
57376
|
-
const
|
|
57377
|
-
for (const next of
|
|
59104
|
+
const neighbors2 = adj.get(nodeId3) ?? [];
|
|
59105
|
+
for (const next of neighbors2) {
|
|
57378
59106
|
const c = color.get(next) ?? 0;
|
|
57379
59107
|
if (c === 1) {
|
|
57380
59108
|
const lineKey = `${nodeId3}->${next}`;
|
|
@@ -57559,6 +59287,163 @@ init_resolver2();
|
|
|
57559
59287
|
init_load_data();
|
|
57560
59288
|
init_layout15();
|
|
57561
59289
|
init_renderer16();
|
|
59290
|
+
init_dimensions();
|
|
59291
|
+
|
|
59292
|
+
// src/map/geo-query.ts
|
|
59293
|
+
init_parser12();
|
|
59294
|
+
init_resolver2();
|
|
59295
|
+
init_layout15();
|
|
59296
|
+
init_geo();
|
|
59297
|
+
|
|
59298
|
+
// src/map/invert.ts
|
|
59299
|
+
function inInsetFrame(inset, px, py) {
|
|
59300
|
+
return px >= inset.x && px <= inset.x + inset.w && py >= inset.y && py <= inset.y + inset.h;
|
|
59301
|
+
}
|
|
59302
|
+
function unstretch(layout, px, py) {
|
|
59303
|
+
const s = layout.stretch;
|
|
59304
|
+
return [
|
|
59305
|
+
s.bx0 + (s.sx !== 0 ? (px - s.ox) / s.sx : 0),
|
|
59306
|
+
s.by0 + (s.sy !== 0 ? (py - s.oy) / s.sy : 0)
|
|
59307
|
+
];
|
|
59308
|
+
}
|
|
59309
|
+
function applyStretch(layout, x, y) {
|
|
59310
|
+
const s = layout.stretch;
|
|
59311
|
+
return [s.ox + (x - s.bx0) * s.sx, s.oy + (y - s.by0) * s.sy];
|
|
59312
|
+
}
|
|
59313
|
+
function pixelToLonLat(layout, px, py) {
|
|
59314
|
+
for (const inset of layout.insets) {
|
|
59315
|
+
if (inInsetFrame(inset, px, py)) {
|
|
59316
|
+
const ll2 = inset.projection.invert?.([px, py]);
|
|
59317
|
+
return ll2 && Number.isFinite(ll2[0]) && Number.isFinite(ll2[1]) ? [ll2[0], ll2[1]] : null;
|
|
59318
|
+
}
|
|
59319
|
+
}
|
|
59320
|
+
const [x, y] = layout.stretch ? unstretch(layout, px, py) : [px, py];
|
|
59321
|
+
const ll = layout.projection.invert?.([x, y]);
|
|
59322
|
+
return ll && Number.isFinite(ll[0]) && Number.isFinite(ll[1]) ? [ll[0], ll[1]] : null;
|
|
59323
|
+
}
|
|
59324
|
+
function lonLatToPixel(layout, lonLat) {
|
|
59325
|
+
const pt = [lonLat[0], lonLat[1]];
|
|
59326
|
+
const main = layout.projection(pt);
|
|
59327
|
+
const mainPx = main && Number.isFinite(main[0]) && Number.isFinite(main[1]) ? layout.stretch ? applyStretch(layout, main[0], main[1]) : [main[0], main[1]] : null;
|
|
59328
|
+
const onCanvas = !!mainPx && mainPx[0] >= 0 && mainPx[0] <= layout.width && mainPx[1] >= 0 && mainPx[1] <= layout.height;
|
|
59329
|
+
if (onCanvas) return mainPx;
|
|
59330
|
+
for (const inset of layout.insets) {
|
|
59331
|
+
const p = inset.projection(pt);
|
|
59332
|
+
if (p && Number.isFinite(p[0]) && Number.isFinite(p[1]) && inInsetFrame(inset, p[0], p[1]))
|
|
59333
|
+
return [p[0], p[1]];
|
|
59334
|
+
}
|
|
59335
|
+
return mainPx;
|
|
59336
|
+
}
|
|
59337
|
+
|
|
59338
|
+
// src/map/geo-query.ts
|
|
59339
|
+
var EARTH_R_KM = 6371;
|
|
59340
|
+
var DEG = Math.PI / 180;
|
|
59341
|
+
function haversineKm(lat1, lon1, lat2, lon2) {
|
|
59342
|
+
const dLat = (lat2 - lat1) * DEG;
|
|
59343
|
+
const dLon = (lon2 - lon1) * DEG;
|
|
59344
|
+
const a = Math.sin(dLat / 2) ** 2 + Math.cos(lat1 * DEG) * Math.cos(lat2 * DEG) * Math.sin(dLon / 2) ** 2;
|
|
59345
|
+
return 2 * EARTH_R_KM * Math.asin(Math.min(1, Math.sqrt(a)));
|
|
59346
|
+
}
|
|
59347
|
+
var POP_PULL_KM = 12;
|
|
59348
|
+
function nearestCity(lonLat, gazetteer) {
|
|
59349
|
+
const [lon, lat] = lonLat;
|
|
59350
|
+
let best = null;
|
|
59351
|
+
const cities = gazetteer.cities;
|
|
59352
|
+
for (let i = 0; i < cities.length; i++) {
|
|
59353
|
+
const c2 = cities[i];
|
|
59354
|
+
const dist = haversineKm(lat, lon, c2[0], c2[1]);
|
|
59355
|
+
const score = dist - POP_PULL_KM * Math.log10((c2[3] || 0) + 1);
|
|
59356
|
+
if (!best || score < best.score) best = { score, idx: i, dist };
|
|
59357
|
+
}
|
|
59358
|
+
if (!best) return null;
|
|
59359
|
+
const c = cities[best.idx];
|
|
59360
|
+
return {
|
|
59361
|
+
name: c[4],
|
|
59362
|
+
iso: c[2],
|
|
59363
|
+
...c[5] !== void 0 && { sub: c[5] },
|
|
59364
|
+
distanceKm: best.dist,
|
|
59365
|
+
lat: c[0],
|
|
59366
|
+
lon: c[1]
|
|
59367
|
+
};
|
|
59368
|
+
}
|
|
59369
|
+
function roundCoord(n) {
|
|
59370
|
+
return Number(n.toFixed(2));
|
|
59371
|
+
}
|
|
59372
|
+
function buildTokens(lonLat, region, city) {
|
|
59373
|
+
const coordPoiLine = `poi ${roundCoord(lonLat[1])} ${roundCoord(lonLat[0])}`;
|
|
59374
|
+
let stateTok = null;
|
|
59375
|
+
if (region.state) {
|
|
59376
|
+
const { iso, name } = region.state;
|
|
59377
|
+
stateTok = { primary: `${name} ${iso}`, alternates: [iso, name] };
|
|
59378
|
+
}
|
|
59379
|
+
let countryTok = null;
|
|
59380
|
+
if (region.country) {
|
|
59381
|
+
const { iso, name } = region.country;
|
|
59382
|
+
countryTok = { primary: name, alternates: [iso] };
|
|
59383
|
+
}
|
|
59384
|
+
let cityTok = null;
|
|
59385
|
+
if (city) {
|
|
59386
|
+
const scope = city.sub ?? (city.iso || "");
|
|
59387
|
+
cityTok = scope ? { token: `poi ${city.name} ${scope}`, ambiguous: false } : { token: `poi ${city.name}`, ambiguous: true };
|
|
59388
|
+
}
|
|
59389
|
+
return { coordPoiLine, state: stateTok, country: countryTok, city: cityTok };
|
|
59390
|
+
}
|
|
59391
|
+
var MAX_CITY_DOTS = 250;
|
|
59392
|
+
function createMapGeoQuery(opts) {
|
|
59393
|
+
const { content, width, height, data, palette, isDark } = opts;
|
|
59394
|
+
const resolved = resolveMap(parseMap(content), data);
|
|
59395
|
+
const layout = layoutMap(
|
|
59396
|
+
resolved,
|
|
59397
|
+
data,
|
|
59398
|
+
{ width, height },
|
|
59399
|
+
{ palette, isDark }
|
|
59400
|
+
);
|
|
59401
|
+
const countries = decodeFeatures(data.worldDetail);
|
|
59402
|
+
const states = decodeFeatures(data.usStates);
|
|
59403
|
+
const gazetteer = data.gazetteer;
|
|
59404
|
+
const invert = (px, py) => pixelToLonLat(layout, px, py);
|
|
59405
|
+
const project = (lonLat) => lonLatToPixel(layout, lonLat);
|
|
59406
|
+
const locate = (px, py) => {
|
|
59407
|
+
const lonLat = invert(px, py);
|
|
59408
|
+
if (!lonLat) return null;
|
|
59409
|
+
const region = regionAt(lonLat, countries, states);
|
|
59410
|
+
const city = nearestCity(lonLat, gazetteer);
|
|
59411
|
+
return {
|
|
59412
|
+
lonLat,
|
|
59413
|
+
country: region.country,
|
|
59414
|
+
state: region.state,
|
|
59415
|
+
nearestCity: city,
|
|
59416
|
+
tokens: buildTokens(lonLat, region, city)
|
|
59417
|
+
};
|
|
59418
|
+
};
|
|
59419
|
+
const cities = (extent2) => {
|
|
59420
|
+
const sorted = [...gazetteer.cities].sort((a, b) => b[3] - a[3]);
|
|
59421
|
+
const out = [];
|
|
59422
|
+
for (const c of sorted) {
|
|
59423
|
+
const [lat, lon, iso, pop, name, sub] = c;
|
|
59424
|
+
if (extent2) {
|
|
59425
|
+
const [[w, s], [e, n]] = extent2;
|
|
59426
|
+
if (lon < w || lon > e || lat < s || lat > n) continue;
|
|
59427
|
+
}
|
|
59428
|
+
const p = project([lon, lat]);
|
|
59429
|
+
if (!p) continue;
|
|
59430
|
+
if (p[0] < 0 || p[0] > width || p[1] < 0 || p[1] > height) continue;
|
|
59431
|
+
out.push({
|
|
59432
|
+
name,
|
|
59433
|
+
iso,
|
|
59434
|
+
...sub !== void 0 && { sub },
|
|
59435
|
+
lon,
|
|
59436
|
+
lat,
|
|
59437
|
+
px: p[0],
|
|
59438
|
+
py: p[1],
|
|
59439
|
+
pop
|
|
59440
|
+
});
|
|
59441
|
+
if (out.length >= MAX_CITY_DOTS) break;
|
|
59442
|
+
}
|
|
59443
|
+
return out;
|
|
59444
|
+
};
|
|
59445
|
+
return { invert, project, locate, cities, diagnostics: layout.diagnostics };
|
|
59446
|
+
}
|
|
57562
59447
|
|
|
57563
59448
|
// src/map/completion.ts
|
|
57564
59449
|
var fold2 = (s) => s.normalize("NFD").replace(/\p{Diacritic}/gu, "").toLowerCase().trim();
|
|
@@ -58283,9 +60168,12 @@ var GLOBAL_DIRECTIVES = {
|
|
|
58283
60168
|
"gruvbox",
|
|
58284
60169
|
"tokyo-night",
|
|
58285
60170
|
"one-dark",
|
|
58286
|
-
"bold",
|
|
58287
60171
|
"dracula",
|
|
58288
|
-
"monokai"
|
|
60172
|
+
"monokai",
|
|
60173
|
+
"atlas",
|
|
60174
|
+
"blueprint",
|
|
60175
|
+
"slate",
|
|
60176
|
+
"tidewater"
|
|
58289
60177
|
]
|
|
58290
60178
|
},
|
|
58291
60179
|
theme: {
|
|
@@ -58681,18 +60569,12 @@ var COMPLETION_REGISTRY = /* @__PURE__ */ new Map([
|
|
|
58681
60569
|
],
|
|
58682
60570
|
[
|
|
58683
60571
|
"map",
|
|
58684
|
-
// Geographic map directives (§24B.2/.7).
|
|
58685
|
-
//
|
|
58686
|
-
//
|
|
60572
|
+
// Geographic map directives (§24B.2/.7). Cosmetics are ON by default — the
|
|
60573
|
+
// only switches are bare `no-*` opt-outs, surfaced proactively so a
|
|
60574
|
+
// zero-config map still hints at what can be turned off. `poi`/`route` are
|
|
60575
|
+
// content keywords, not directives; metadata keys (value/label/style) live
|
|
60576
|
+
// in the reserved-key registry.
|
|
58687
60577
|
withGlobals({
|
|
58688
|
-
region: {
|
|
58689
|
-
description: "Basemap: us-states (force US state mesh + scoping) | world (inert \u2014 already the default)",
|
|
58690
|
-
values: ["us-states", "world"]
|
|
58691
|
-
},
|
|
58692
|
-
projection: {
|
|
58693
|
-
description: "Override the auto projection",
|
|
58694
|
-
values: ["equirectangular", "natural-earth", "albers-usa", "mercator"]
|
|
58695
|
-
},
|
|
58696
60578
|
"region-metric": { description: "Label for the region value ramp" },
|
|
58697
60579
|
"poi-metric": {
|
|
58698
60580
|
description: "Label for the POI value (marker size) channel"
|
|
@@ -58700,20 +60582,30 @@ var COMPLETION_REGISTRY = /* @__PURE__ */ new Map([
|
|
|
58700
60582
|
"flow-metric": {
|
|
58701
60583
|
description: "Label for the edge/leg value (thickness) channel"
|
|
58702
60584
|
},
|
|
58703
|
-
|
|
58704
|
-
|
|
58705
|
-
description: "Subdivision name labels",
|
|
58706
|
-
values: ["full", "abbrev", "off"]
|
|
60585
|
+
locale: {
|
|
60586
|
+
description: "Default country/state for bare place names, e.g. locale US-GA"
|
|
58707
60587
|
},
|
|
58708
|
-
"
|
|
58709
|
-
description: "
|
|
58710
|
-
values: ["off", "auto", "all"]
|
|
60588
|
+
"active-tag": {
|
|
60589
|
+
description: "Which tag group leads when several are present"
|
|
58711
60590
|
},
|
|
58712
|
-
|
|
58713
|
-
"default-state": { description: "ISO subdivision scope" },
|
|
60591
|
+
caption: { description: "Caption line (data-source attribution)" },
|
|
58714
60592
|
"no-legend": { description: "Suppress the legend" },
|
|
58715
|
-
|
|
58716
|
-
|
|
60593
|
+
"no-coastline": {
|
|
60594
|
+
description: "Turn off coastal water-lines (on by default)"
|
|
60595
|
+
},
|
|
60596
|
+
"no-relief": {
|
|
60597
|
+
description: "Turn off mountain-range relief shading (on by default)"
|
|
60598
|
+
},
|
|
60599
|
+
"no-context-labels": {
|
|
60600
|
+
description: "Turn off orientation labels for water + nearby countries"
|
|
60601
|
+
},
|
|
60602
|
+
"no-region-labels": {
|
|
60603
|
+
description: "Turn off subdivision name labels (on by default)"
|
|
60604
|
+
},
|
|
60605
|
+
"no-poi-labels": { description: "Turn off POI labels (on by default)" },
|
|
60606
|
+
"no-colorize": {
|
|
60607
|
+
description: "Force plain green-land reference dress (regions are auto-coloured by default)"
|
|
60608
|
+
}
|
|
58717
60609
|
})
|
|
58718
60610
|
]
|
|
58719
60611
|
]);
|
|
@@ -60183,7 +62075,8 @@ function formatLineDiff(path, original, migrated) {
|
|
|
60183
62075
|
applyCollapseProjection,
|
|
60184
62076
|
applyGroupOrdering,
|
|
60185
62077
|
applyPositionOverrides,
|
|
60186
|
-
|
|
62078
|
+
atlasPalette,
|
|
62079
|
+
blueprintPalette,
|
|
60187
62080
|
buildExtendedChartOption,
|
|
60188
62081
|
buildNoteMessageMap,
|
|
60189
62082
|
buildRenderSequence,
|
|
@@ -60217,6 +62110,7 @@ function formatLineDiff(path, original, migrated) {
|
|
|
60217
62110
|
computeTimeTicks,
|
|
60218
62111
|
contrastText,
|
|
60219
62112
|
controlsGroupCapsuleWidth,
|
|
62113
|
+
createMapGeoQuery,
|
|
60220
62114
|
decodeDiagramUrl,
|
|
60221
62115
|
decodeViewState,
|
|
60222
62116
|
displayName,
|
|
@@ -60285,6 +62179,8 @@ function formatLineDiff(path, original, migrated) {
|
|
|
60285
62179
|
looksLikeState,
|
|
60286
62180
|
makeDgmoError,
|
|
60287
62181
|
mapBackgroundColor,
|
|
62182
|
+
mapContentAspect,
|
|
62183
|
+
mapExportDimensions,
|
|
60288
62184
|
mapNeutralLandColor,
|
|
60289
62185
|
matchesContiguously,
|
|
60290
62186
|
measurePertAnalysisBlock,
|
|
@@ -60420,9 +62316,11 @@ function formatLineDiff(path, original, migrated) {
|
|
|
60420
62316
|
shapeFill,
|
|
60421
62317
|
simulateCanonical,
|
|
60422
62318
|
simulateFast,
|
|
62319
|
+
slatePalette,
|
|
60423
62320
|
solarizedPalette,
|
|
60424
62321
|
suggestChartTypes,
|
|
60425
62322
|
themes,
|
|
62323
|
+
tidewaterPalette,
|
|
60426
62324
|
tint,
|
|
60427
62325
|
tokyoNightPalette,
|
|
60428
62326
|
transformLine,
|